Reference manual for the Rascal metaprogramming language.
Here we describe all features of the Rascal language in detail, for reference purposes.

Declarations: The entities that can be declared in Rascal programs.

Patterns: Patterns are a notation for pattern matching used to detect if a value has a certain shape,.

Expressions: The expressions available in Rascal.

Statements: All Rascal statements.
You can find more (accessible) information related to Rascal here:

Why Rascal: gives the motivation for the Rascal language and describes various usage scenarios.

Getting Started describes how to download, install and start Rascal.

Getting Help shows how to use the help facilties and search the documentation. See Further Reading for a reading guide.

Library functies are described in Rascal Libraries.

We do not maintain a list of frequently asked questions (faq) but use StackOverflow instead.

We show examples for each Rascal language construct described here.

You can find many simple code examples in Recipes.

The Rascal Libraries contain examples for most functions.

Rascal has everything you need for any kind of (meta)program you want to write. See Why Rascal.

Rascal is a procedural/functional language with immutable data. Do not confuse this with objectoriented programming.

Rascal allows you to write highly imperative code, but it has declarative constructs that lead to shorter and more readable code.
1. Declarations
The entities that can be declared in Rascal programs.
The following concepts are relevant for declarations:

Module Declaration: Declare a module.

Import: Declare the import a module.

Program: A Rascal program consists of a number of Module Declarations.

StaticTyping: The static type system of Rascal.

Reified Types: Reified types are types that can be used as values.

Type Constraints: Type constraints restrict the acceptable type for parameters.

Type Parameters: Type parameters enable parameterized types.


Algebraic Data Type: Define a userdefined type (Algebraic Data Type).

Variable Declaration: Declare a variable.

Function Declaration: Declare a function.

Syntax Definition: Syntax Definitions allow the definition of parsers for programming languages, domainspecific languages and data formats.

Action: Actions are functions that are called when parse trees are constructed (right after parsing).

Ambiguity Detection: Ambiguity detection helps to find ambiguities in syntax definitions.

Ambiguity Diagnosis: Ambiguity diagnosis suggests changes to syntax definitions to make them nonambiguous.

Parse Trees: An algebraic datatype for parse trees; produced by all parsers generated from syntax definitions.

Symbol: The symbols that can occur in a syntax definition.


Alias Declaration: Declare an alias for a type.

Tag Declaration: Tag declarations are not implemented (yet).
1.1. Module Declaration
Declare a module.
module Name
Imports;
Declaration_{1};
...
Declaration_{n};
A module declaration consists of:

A module name.

Zero or more imports;

Zero or more declarations.
The module name Name will be used when the current module is imported in another module. A module name is in general a qualified name of the form:
Name_{1}::_Name_{2}:: ... ::_Name_{n}
which corresponds to a path relative to the root of the current workspace.
The constituents of a module are shown in the figure below.
An Import declares other modules that are used by the current module. Following imports, a module may contain declarations (in arbitrary order, but a Syntax Definition can occur directly following the imports) for:
Each declaration may contain a private
or public
keyword that determines
the visibility of the declared entity.
The entities that are visible inside a module are

The private or public entities declared in the module itself.

The public entities declared in any imported module.
The only entities that are visible outside the module, are the public entities declared in the module itself. If different imported modules declare the same visible name, it can be disambiguated by explicitly qualifying it with its module name:
Module :: Name
Each module resides in a separate file with extension .rsc
.
Here is the Hello
module:
module demo::basic::Hello
import IO;
void hello() {
println("Hello world, this is my first Rascal program");
}
It defines a module with the name demo::basic::Hello
and imports the IO library.
Finally, it declares the hello
function.
The actual source of this module can be found in library/demo/basic/Hello.rsc
in the Rascal sources.
1.2. Import
Declare the import a module.
import QualifiedName;
An import has as effect that all public entities declared in module QualifiedName are made available to the importing module. Circular imports are allowed. All publicly visible entities in the imported module become available in the importing module.
Import is nontransitive, i.e., the visible entities from an imported module are not reexported by the importing module.
Here, is how to import the IO library:
rascal>import IO;
ok
rascal>println("IO library was imported.");
IO library was imported.
ok
1.3. Program
A Rascal program consists of a number of Module Declarations.
A Rascal program consists of a number of Module Declarations, each stored in a separate file with extension .rsc
.
1.4. StaticTyping
The static type system of Rascal.
Rascal is based on static typing, this means that as many errors and inconsistencies as possible are spotted before the program is executed.
1.4.1. The Type Lattice
The types are ordered in a socalled type lattice shown in the following figure.
The arrows describe a subtypeof relation between types. The type void
is the smallest type and
is included in all other types and the type value
is the largest type that includes all other types.
We also see that rel
is a subtype of set
and that each ADT is a subtype of node
.
A special role is played by the datatype Tree
that is the generic type of syntax trees.
Syntax trees for specific languages are all subtypes of Tree
. As a result, syntax trees can be addressed at two levels:

in a generic fashion as
Tree
and, 
in a specific fashion as a more precisely typed syntax tree. Finally, each
alias
is structurally equivalent to one or more specific other types.
The fact that the types are ordered in a lattice makes it possible to define a Least Upper Bound (lub) on types.
Given two types T_{1} and T_{2}, lub(T_{1}, T_{2})
is defined as the nearest common super type of T_{1} and T_{2}
in the type lattice.
1.4.2. Advanced Features
The Rascal type system has various advanced features that are described separately:

Types may be be parameterized resulting in very general and reusable types, see [Type Parameters].

Declarations of [Function]s and [AlgebraicDataType]s may be parameterized and [Type Constraints] can be used to define constraints on the actual type to be used.

The formal arguments of functions are bound to values but in exceptional cases a function may need a type as argument value, Reified Types make this possible.
Here are some simple examples of correct and incorrect typing:
We can assign an integer value to an integer variable:
rascal>int i = 3;
int: 3
But assigning a string value gives an error:
rascal>int j = "abc";
prompt:///(4,9,<1,4>,<1,13>): Expected int, but got str
Advice: http://tutor.rascalmpl.org/Errors/Static/UnexpectedType/UnexpectedType.html
ok
The num
type accepts integer and real values:
rascal>num n = i;
num: 3
rascal>n = 3.14;
num: 3.14
A variable of type value
accepts all possible values:
rascal>value v = true;
value: true
rascal>v = "abc";
value: "abc"
rascal>v = [1, 2, 3];
value: [1,2,3]
1.4.3. Reified Types
Reified types are types that can be used as values.
# Name
type
Usually one declares functions that have arguments that have a type that corresponds to one of the many forms of values in Rascal. In exceptional circumstances it is desirable to define functions that have a type itself as argument.
To solve this problem in a more general manner something special has to be done.
Types are not values and without an additional mechanism they cannot be passed as arguments to functions.
To achieve this effect we introduce reified types that are denoted by the type type
.
In other words, reified types make it possible to use types as values.
The prototypical example is a parse function: how to write a type safe parse function that expresses the type of the result we expect?
Suppose we want to parse a language that has the nonterminals EXP
, STAT
and PROGRAM
.
A first, naive, solution introduces a parse function for each nonterminal:
EXP parseEXP(str s){ ... }
STAT parsePROGRAM(str s) { ... }
PROGRAM parsePROGRAM(str s) { ... }
Unfortunately this solution does not scale well to large languages with many nonterminals and it breaks down completely when we do not know the nonterminals before hand.
Now we can write (see Type Parameters for a description of the &T
notation):
&T parse(type[&T] start, str s) { ... }
and use the parse by giving it a type as argument:
parse(#EXP, "1+3");
1.4.4. Type Constraints
Type constraints restrict the acceptable type for parameters.
& Name <: Type
Constraints can be imposed on the actual types to which a type parameter may be bound. This is expressed by a subtype constraint which expresses that actual types bound to Name should be a subtype of Type.
Here is the definition of the absolute value function abs
from the Number library:
public &T <: num abs(&T <: num N)
{
return N >= 0 ? N : N;
}
The argument N
is constrained to be at most of type num
.
rascal>import util::Math;
ok
rascal>abs(3);
int: 3
rascal>abs(3.5);
real: 3.5
Here is an example from the Node library:
&T <: node setAnnotations(&T <: node x, map[str, value] annotations);
(we don’t give the body of this function since it has been implemented in Java).
setAnnotations
takes a value of any type that is at most node
and adds annotations to it.
This makes it possible to set annotations on any Algebraic Data Type.
rascal>import Node;
ok
rascal>nd = "f"(10, "abc");
node: "f"(10,"abc")
First we apply setAnnotations
to a node value:
rascal>setAnnotations(nd, ("color" : "red", "size" : "large"));
node: "f"(10,"abc")[
@size="large",
@color="red"
]
Next, we introduce a new data type Suite
:
rascal>data Suite = hearts()  diamonds()  clubs()  spades();
ok
rascal>st = diamonds();
Suite: diamonds()
And apply setAnnotations
to a value of type Suite
:
rascal>setAnnotations(st, ("player" : "Hossein", "gain" : "120"));
Suite: diamonds()[
@player="Hossein",
@gain="120"
]
1.4.5. Type Parameters
Type parameters enable parameterized types.
& Name
A type parameter may occur at every syntactic position where a type is required and turns an ordinary type into a parameterized type. Parameterized types are used to define polymorphic functions and data types, i.e., functions and data types that are applicable for more than one type. Type parameters are bound to an actual type when the function or data type is applied and further uses of the type parameter are consistently replaced by the actual type.
The following syntactic positions are binding occurrences for type parameters:

Type parameters in the type declaration of a function are bound to the types of the actual parameters in the call of that function. Type parameters that occur in the body of the function are replaced by the corresponding actual types.

The lefthand side of an alias. The type parameters are bound when the alias is used and occurrences of type parameters in the right hand side are replaced by corresponding actual types.

The alternatives of a data type. Binding and replacement is identical to that of function declarations.
All other occurrences of type parameters are using occurrences. The following rules apply:

When the same type parameter is used at different binding occurrences it should be bound to the same actual type.

For every using occurrence of a type parameter there should be a binding occurrence of a type parameter with the same name.
Let's consider a small example of the use of function parameters in a function declaration, see Function Declaration
for more details on function declarations.
The following function swap
returns a tuple in which its arguments are swapped and can be applied to arbitrary values
in a type safe manner:
rascal>tuple[&B, &A] swap(&A a, &B b) { return <b, a>; }
tuple[&B,&A] (&A, &B): function(prompt:///(0,49,<1,0>,<1,49>))
rascal>swap(1,2);
tuple[int,int]: <2,1>
rascal>swap("abc", 3);
tuple[int,str]: <3,"abc">
Observe that the type parameters that are used in the return type should be defined in the declarations of the formal parameter of the function.
An [Alias] declaration may also be parameterized. So we can generalize graphs as follows:
alias Graph[&Node] = rel[&Node, &Node];
Graph[int] GI = {<1,2>, <3,4>, <4,1>};
Graph[str] GS = {<"a", "b">, <"c","d">, <"d", "a">};
The type parameters that are used in the type in the right part of the alias declaration should be defined in the left part of the alias definition.
1.5. Algebraic Data Type
Define a userdefined type (Algebraic Data Type).
In ordinary programming languages record types or classes exist to introduce a new type name for a collection of related, named, values and to provide access to the elements of such a collection through their name.
In Rascal, algebraic data types provide this facility. They have to be declared, and then values can be declared using calls to the declared constructor functions, see Constructor.
The following data declaration defines the datatype Bool
that contains various constants (tt()
and ff()
and constructor functions conj
and disj
.
rascal>data Bool = tt()  ff()  conj(Bool L, Bool R)  disj(Bool L, Bool R);
ok
terms of type Bool
can be constructed using the defined constructors:
rascal>conj(tt(),ff());
Bool: conj(
tt(),
ff())
1.6. Variable Declaration
Declare a variable.

Type Name = Exp ;

Type Name;




The effect of a variable declaration is to introduce a new variable Name and to assign the value of expression Exp to Name. A mention of Name later on in the same scope will be replaced by this value, provided that Name\'s value has not been changed by an intermediate assignment.
When a variable is declared, it has as scope the nearest enclosing block, or the module when declared at the module level.
The following rules apply:

Double declarations in the same scope are not allowed.

The type of Exp should be compatible with Type, i.e., it should be a subtype of Type.
As a convenience, also declarations without an initialization expression are permitted inside functions (but not at the module level) and have the form
Type Name;
and only introduce the variable Name.
Rascal provides local type inference, which allows the implicit declaration of variables that are used locally in functions. The following rules apply:

An implicitly declared variable is declared at the level of the current scope, this may the whole function body or a block nested in it.

An implicitly declared variable gets as type the type of the first value that is assignment to it.

If a variable is implicitly declared in different execution path of a function, all these implicit declarations should result in the same type.

All uses of an implicitly declared variable must be compatible with its implicit type.
Two explicit variable declarations:
rascal>int max = 100;
int: 100
rascal>min = 0;
int: 0
An implicit variable declaration
rascal>day = {<"mon", 1>, <"tue", 2>, <"wed",3>,
>>>>>>> <"thu", 4>, <"fri", 5>, <"sat",6>, <"sun",7>};
rel[str,int]: {
<"thu",4>,
<"tue",2>,
<"sat",6>,
<"wed",3>,
<"fri",5>,
<"sun",7>,
<"mon",1>
}
Variable declaration and assignment leading to type error
rascal>int month = 12;
int: 12
rascal>month ="December";
prompt:///(7,10,<1,7>,<1,17>): Expected int, but got str
Advice: http://tutor.rascalmpl.org/Errors/Static/UnexpectedType/UnexpectedType.html
ok

Local type inference for variables always uses the smallest possible scope for a variable; this implies that a variable introduced in an inner scope is not available outside that scope. Here is how things can go wrong:
rascal>if( 4 > 3){ x = "abc"; } else { x = "def";}
str: "abc"
rascal>x;
prompt:///(0,1,<1,0>,<1,1>): Undeclared variable: x
Advice: http://tutor.rascalmpl.org/Errors/Static/UndeclaredVariable/UndeclaredVariable.html
ok
1.7. Function Declaration
Declare a function.

Modifiers Type Name( Type_{1} Var_{1}, …, Type_{n} Var_{n} ) Body

Modifiers Type Name( Type_{1} Var_{1}, …, Type_{n} Var_{n} Type_{0} Name_{0}… ) Body

Modifiers Type Name( Pattern_{1}, …, Pattern_{n}) Body

Modifiers Type Name( Pattern_{1}, …, Pattern_{n}, Type_{0} Name_{0}…) Body
where Body
is one of:

{ Statements }

throws Exception_{1}, Exception_{2}, … { Statements }

= Expression;
and where Modifiers
may be:

("public"  "private")? ("java"  "test"  "default")?
1.7.1. Variant 1
A function declaration introduces a new function with name name, typed formal parameters Type_{1} Var_{1}
, a return type Type
and a Statement that forms the function body.
The type of Statement should be equal to Type.
The formal parameters may be used in Statement and get their value when function Name is invoked.
1.7.2. Variant 2
A function may have a variable list of arguments, this has as syntax variant 2 given above.
The last parameter of a function may be followed by …
and this has as effect that all remaining actual parameters
that occur in a call to this function are collected as list value of the last formal parameter.
Inside the function body, the type of this parameter will therefore be list[Type_{0}]
.
1.7.3. Variant 3 and 4
All formal parameter of a function can be Patterns. There are some restrictions however:

A Pattern in formal parameter positions may not refer to variables in the scope.

Patterns in formal parameter positions may not introduce fresh variables without an explicit type.

The last parameter, if followed by
…
can only be a normal typed parameters, not just any pattern.
1.7.4. Body types

Functions with list of statements as bodies must eventually use
return
orfail
on every control flow path. 
The declarations to
throw
an exception are documentation only 
Single expressions can be bodies of functions, the return value is the value of the expression.
1.7.5. Parameterized types in function declaration
The types that occur in function declarations may also contain Type Parameters. In this way functions can be defined for arbitrary types. The type variable is bound (statically) at by the types of the parameters given at location of the call. The result type must be used at least once in any of the parameters.
1.7.6. Overloading
Function definitions may be overloaded, i.e. a function with the same name may be defined twice and a function may redefine a constructor of an Algebraic Data Type or a Syntax Definition.
There are some restrictions however:

Overloaded alternatives for the same function name but with different patterns must return the same type.

Overloaded alternatives for the same function name must have mutually exclusive patterns, unless one alternative is labeled
default
and the other is not. The patterns of formal parameters are mutually exclusive if for at least one parameter position:
They range over incomparable types, as in
int f(int a)
andint f(real a)
, or 
They range over different alternatives of an Algebraic Data Type, as in
int f(and(Bool a, Bool b))
andint f(or(Bool a, Bool b))

They range over different alternatives of a Syntax Definition

And note that deep matches using the
/
alternative are considered to be of typevalue
and therefore overlap with all other patterns.


Overlapping patterns are allowed if the one alternative has the
default
modified while the other does not. 
If a function is fallible, it uses the
fail
statement to backtrack to a different alternative, then there must be adefault
alternative defined which can handle the general case. An [AlgebraicDataType] or a [SyntaxDefinition] with the same name and return type counts as adefault
alternative. 
default
functions may not fail.
1.7.7. Modifiers
The Modifiers affect visibility and special behaviour of functions:

Visibility:
private
declares that a function is only visible in the current module.public
declares that it is visible outside the module as well. When visibility is not specified,private
is assumed. 
Special Behaviour:

java
declares that the body of the function is implemented in Java. The function should have ajavaClass
annotation that determines where the Java implementation can be found. 
test
declares that this is a test function. A test function is a boolean function (currently) without arguments. It can be called as any other function. However, it can also be called automatically by the unit test framework, by typing:test
at the command line, see [Help]. 
default
declares an alternative for an overloaded function that will only be tried after all nondefault alternatives have been tried. Note that Algebraic Data Types and Syntax Definitions implicitly definedefault
functions that may be overloaded by normal Function Declarations.

Declare a function
rascal>rel[int, int] invert(rel[int,int] R){
>>>>>>> return {<Y, X>  <int X, int Y> < R };
>>>>>>>}
rel[int,int] (rel[int,int]): function(prompt:///(0,82,<1,0>,<3,1>))
Call it
rascal>invert({<1,10>, <2,20>});
rel[int,int]: {
<10,1>,
<20,2>
}
In the following example we illustrate the use of type variables in function declarations. Declare an inversion function that is applicable to any binary relation:
rascal>rel[&T2, &T1] invert2(rel[&T1,&T2] R){
>>>>>>> return {<Y, X>  <&T1 X, &T2 Y> < R };
>>>>>>>}
rel[&T2,&T1] (rel[&T1,&T2]): function(prompt:///(0,85,<1,0>,<3,1>))
Now apply it to relations with different types:
rascal>invert2({<1,10>, <2,20>});
rel[int,int]: {
<10,1>,
<20,2>
}
rascal>invert2({<"mon", 1>, <"tue", 2>});
rel[int,str]: {
<1,"mon">,
<2,"tue">
}
As another example declare a function that can be used to swap the elements of pairs of arbitrary types (also see Tuple Subscription):
rascal>tuple[&T2, &T1] swap(tuple[&T1, &T2] TP) { return <TP[1], TP[0]>;}
tuple[&T2,&T1] (tuple[&T1,&T2]): function(prompt:///(0,66,<1,0>,<1,66>))
rascal>swap(<1, 2>);
tuple[int,int]: <2,1>
rascal>swap(<"wed", 3>);
tuple[int,str]: <3,"wed">
Here we use an overloaded definition with incomparable patterns:
rascal>int f(int i) = 1;
int (int): function(prompt:///(0,17,<1,0>,<1,17>))
rascal>int f(real r) = 2;
int (real): function(prompt:///(0,18,<1,0>,<1,18>))
rascal>f(0);
int: 1
rascal>f(0.0);
int: 2
And we may use default
, as in:
rascal>int f(0) = 1;
int (int): function(prompt:///(0,13,<1,0>,<1,13>))
rascal>default int f(int n) = n * f(n  1);
int (int): function(prompt:///(0,36,<1,0>,<1,36>))
rascal>f(0);
int: 1
rascal>f(2);
int: 2
In combination with an Algebraic Data Type, which defines default
functions implicitly for every alternative,
we can define canonicalization functions. The same holds for Syntax Definitions, see Actions.
In case of overlapping function definitions, the order in which the functions are tried is left undefined. The only exceptions are functions marked default
, those will be tried after nondefault
functions.
1.8. Syntax Definition
Syntax Definitions allow the definition of parsers for programming languages, domainspecific languages and data formats.

Start syntax Nonterminal = Alternatives;

lexical Nonterminal = Alternatives;

layout Nonterminal = Alternatives;

keyword Nonterminal = Alternatives;
where Start is either start
or nothing, and Alternatives are one of:

Tags Associativity Symbols

Tags Associativity Name : Symbols

Associativity ( Alternatives )

Alternatives_{1}  Alternatives_{2}

Alternatives_{1} > Alternatives_{2}
where Associativity is nothing, or one of assoc
, left
, right
or nonassoc
, and Tags are a possibly empty list of tags.
Rascal supports full contextfree grammars for syntax definition. It generates scannerless parsers from these definitions. These parsers produce Parse Trees that can be further processed by Rascal using Concrete Syntax fragments in Patterns and Expressions, or they can be imploded to Algebraic Data Types.
There are four kinds of nonterminals that can be defined with slightly different characteristics.

Syntax nonterminals are general contextfree nonterminals. This mean leftrecursion, rightrecursion, any of the regular expression Symbols and all kinds of Disambiguation can be used to define it. It is important to note that in between the Symbols that define a syntax nonterminal the locally defined layout nonterminal will be interleaved. For example, if you define
layout ML = [\ ]*;
andsyntax A = "a" "a"
, Rascal will modify the definition of A tosyntax A = "a" ML "a";
before generating a parser. 
Lexical nonterminals are just like syntax nonterminals, very much like syntax nonterminals. However, the definition of a lexical is not modified with interleaved layout nonterminals. And, the structure of lexicals is not traversed by the Visit statement and equality is checked between lexicals by checking the characters (not its structure) for equality.

Layout nonterminals are just like syntax nonterminals as well. However, they are used to preprocess all syntax definitions in the same module scope (see above).

Keyword nonterminals are not like syntax nonterminals. These only allow definition of enumeration of literal symbols and single character classes. Keyword nonterminals play an important role in the semantics of Disambiguation where some disambiguation constructs require finite, nonempty enumeration of strings. The prime example is the definition of reserved keywords.
Each alternative of a syntax definition is defined by a list of Symbols. Each of the Symbols can be labeled or not. The alternative of a defined syntax type may be labeled or not as well. With the label additional operations are activated on the corresponding parse trees:

The
is
operator is defined for labeled alternatives (see Operators). 
The
has
operator is defined for labeled Symbols in the righthand side (see Operators). 
Action functions can be written to override the construction of a parse tree, using the label of an alternative as the function name

[implode] uses labeled alternatives to map to an Algebraic Data Type
Alternatives can be combined in a single Syntax Definition using the 
, >
and associativity combinators.
The latter two represent Disambiguation constructs that you should read more about. The 
is a shorthand for not having to repeat syntax A =
for every alternative of A
.
Alternatives can be named or not. The names are essential only if:

you need to implode Parse Trees

you need to use the
is
expression, as inmyStatement is ifThenElse
instead of using concrete pattern matching. 
you want to write Actions that triggers on the construction of the alternative.
However, it is generally a good idea to name your rules even if you do not need them. Note that a name may be reused for different alternatives for a single nonterminal, provided that the lists of symbols for these "overloaded" alternatives use different nonterminal symbols. This implies that alternatives for lexicals generally do not use overloaded names because they are often defined only by regular expressions over terminal Symbols (literals and character classes).
The start modifier identifies the start of a grammar. The effect of a start modifier is that Rascal will generate an extra syntax definition before generating a parser that allows layout to before and after the start nonterminal. For example:
layout L = [\ ]*; start Program = Statement*;`
will produce syntax start[Program] = L Program top L;
.
Note that the start[Program]
type is now available in your program, and Parse Trees assigned to variable of that
type will allow access to the top field.
The following example makes use of practically all of the Syntax Definition features, except parse actions.
// layout is lists of whitespace characters
layout MyLayout = [\t\n\ \r\f]*;
// identifiers are characters of lowercase alphabet letters,
// not immediately preceded or followed by those (longest match)
// and not any of the reserved keywords
lexical Identifier = [az] !<< [az]+ !>> [az] \ MyKeywords;
// this defines the reserved keywords used in the definition of Identifier
keyword MyKeywords = "if"  "then"  "else"  "fi";
// here is a recursive definition of expressions
// using priority and associativity groups.
syntax Expression
= id: Identifier id
 null: "null"
 left multi: Expression l "*" Expression r
> left ( add: Expression l "+" Expression r
 sub: Expression l "" Expression r
)
 bracket "(" Expression ")"
;

Modular and compositional.

No grammar normalization or grammar factoring necessary.

Generate a parser for any contextfree grammar.

Generate parsers are really fast (for general parsers).

Powerful disambiguation constructs for common programming language disambiguation patterns.

Datadependent (contextsensitive) disambiguation via arbitrary functions.

Embedding of concrete syntax fragments in Rascal programs

Syntax Definitions follow the syntax and semantics of Algebraic Data Types quite closely.

Grammars may be ambiguous, so read about Disambiguation, Ambiguity Detection and Ambiguity Diagnosis.

Static grammar checker is not implemented yet.
1.8.1. Action
Actions are functions that are called when parse trees are constructed (right after parsing).
A socalled Action is a normal rascal Function Declaration that overloads a Syntax Definition. A Syntax Definition, very similar to Algebraic Data Type definitions, defines a constructor for a parse tree node. This constructor is the default function, and when it is overloaded by a nondefault function this overloaded function will be tried first. You can overload any labeled Syntax Definition using the name of an alternative.
For example:
syntax A = a: B C;
public A a(B b, C c) {
return f(b, c);
}
In this example Action function the a is replaced by whatever A the f
function returns.
Actions are executed every time a parse tree is constructed:

Right after parsing.

On the way back from a visit statement.

When a Concrete Syntax expression is executed.

When Parse Trees are constructed "manually".
They can be used as a Disambiguation method, using the filter
statement, as in:
syntax E = id: Id i;
set[Id] types = {};
public E id(Id i) {
if (i in types)
filter; // remove this parse tree and all its parents up to the first amb node
else
fail; // just build the parse tree "E = id: Id i", by defaulting to the constructor
}
1.8.2. Ambiguity Detection
Ambiguity detection helps to find ambiguities in syntax definitions.
AmbiDexter is a tool that analyzes Syntax Definitions, including their Disambiguations, to try and determine which ambiguities it contains. Static detection of ambiguity is not decidable, nevertheless AmbiDexter does a fine job at finding them.

AmbiDexter can find ambiguity for you before testing the parser, after which you can use [AmbiguityDiagnosis] to explain it.

AmbiDexter is now a separate commandline tool which still needs integration

AmbiDexter is not a silver bullet. It has a timelimit to stop after having searcher only so much of a language. After the time limit has expired, your [SyntaxDefinition] may still be ambiguous.
1.8.3. Ambiguity Diagnosis
Ambiguity diagnosis suggests changes to syntax definitions to make them nonambiguous.
The Ambiguity
library, a.k.a. DrAmbiguity, contains a diagnosis tool that can help you find the causes of ambiguous
parse trees and possible Disambiguations to solve them in a Syntax Definition.
DrAmbiguity is a library that processes any parse forest produced by a parser generated from Rascal’s Syntax Definitions.
Please read Disambiguation first.
import analysis::grammars::Ambiguity;
diagnose(t); // for any t of which you know it contains an ambiguity

DrAmbiguity automatically proposes Disambiguations that will work

DrAmbiguity does not scale to large parse trees, so please first make your example smaller.

DrAmbiguity proposes several [Disambiguation]s for each ambiguity, only few of which make sense from a language design point of view!

DrAmbiguity is now only a library function, while it should be integrated into the Rascal IDE
1.8.4. Disambiguation
Disambiguation is the definition of filters on the parse trees that Syntax Definitions define. There are several ways of defining Disambiguation in Rascal.
There are generally three ways of removing ambiguity from parse forests that are produced by parsers generated from Syntax Definitions.

The first way is to add disambiguation declarations to the Syntax Definition. You can choose from:

Priority Declarations, which can be used to define the relative priority in expression languages

Associativity Declarations, which can be used to define relative associativity between operators of expression languages

Follow Declarations, which can be used to implement longest match using lookahead

Precede Declarations, which can be used to implement first match using look behind

which allow you to finite sets of strings from a <<Syntax Definition to implement keyword reservation


The second way is to add Actions that will be triggered just after parsing and allow you to trim a parse forest using any information necessary.

The third way is use the Visit statement on a parse tree and implement your own filter postparsing time, or any other kind of program that processes Parse Trees.
Associativity Declaration
Define associativity of operators

syntax Exp = Assoc Label Symbol_{1} Symbol_{2} …

syntax Exp = Assoc ( Alt_{1}  Alt_{2}  … )

syntax Exp = Assoc Symbol_{1} Symbol_{2} …
Here Assoc is one of: left
, right
, assoc
or nonassoc
. See Syntax Definitions on how to define alternatives and Symbols.
Using Associativity declarations we may disambiguate binary recursive operators.
The semantics are that an associativity modifier will instruct the parser to disallow certain productions to nest at particular argument positions:

left
andassoc
will disallow productions to directly nest in their rightmost position. 
right
will disallow productions to directly nest in their leftmost position. 
nonassoc
will disallow productions to directly nest in either their leftmost or their rightmost position.
When associativity is declared for a group of productions, e.g. left ( Alt_{1}  Alt _{2}  Alt_{3})
, then each alternative will be mutually associative to each other alternative and itself. If an alternative of a group defines its own local associativity, as in left ( right Alt_{1}  Alt_{2}  Alt_{3})
, then Alt_{1} is right associative with respect to itself and left associative with respect to all others in the group.
A finer point is that associativity has no effect on any other position than the leftmost and rightmost position (see also Priority Declaration). This is to guarantee that associativity does not introduce parse errors. The following tables explain when an assocativity declaration filters given two productions father
and child
that share an associativity group.
If `left (Parent  Child)`  Parent None: E = "[" E "]" 
Parent Leftmost: E = E "*" 
Parent Rightmost: E = "*" E 
Parent Both: E = E "*" E 

Child None: 
No filter 
No filter 
No filter 
No filter 
Child Leftmost: 
No filter 
No filter 
Filter under right 
Filter under right 
Child Rightmost: 
No filter 
No filter 
No filter 
No filter 
Child Both: 
No filter 
No filter 
If `right (Parent  Child)`  Parent None: E = "[" E "]" 
Parent Leftmost: E = E "*" 
Parent Rightmost: E = "*" E 
Parent Both: E = E "*" E 

Child None: 
No filter 
No filter 
No filter 
No filter 
Child Leftmost: 
No filter 
No filter 
No filter 
No filter 
Child Rightmost: 
No filter 
Filter under left 
No filter 
Filter under left 
Child Both: 
No filter 
Filter under left 

Short notation for common constructs in programming languages.

Removes ambiguity but can not introduce parse errors.

Allows the use of less nonterminals for the same expression grammar (typically only one), which makes parse trees simpler as well as the mapping to an abstract syntax tree more direct.

Please do not assume that Rascal’s associativity declarations have the same semantics as SDF’s associativity declarations.

Use of productions that are not both left and right recursive in an associativity group, although safe, is not very meaningful. We would advise to use the Priority Declaration relation such a case. For example:
Original associativity  Better written as priority 

`E = left ( "+" E 
E "+" E );` 

`E = right ( "+" E 
E "+" E );` 

`E = left ( E "+" 
E "+" E);` 

`E = right ( E "+" 
E "+" E);` 

Follow Declaration
A conditional Symbol, constraining the characters that can immediately follow a symbol in the input source text.

Symbol >> constraint

Symbol !>> constraint
where a constraint is any character class, a literal or a keyword nonterminal Symbol.
Using !>>
, the parser will not accept the Symbol if it is immediately followed by the terminal in the input string. If the end of the symbol coincides with endoffile, the constraint will always succeed and the symbol is accepted.
Precede Declaration
A conditional Symbol, constraining the characters that can immediately precede a symbol in the input source text.

constraint << Symbol

constraint !<< Symbol
where a constraint is any character class, a literal or a keyword nonterminal Symbol.
Using !<<
, the parser will not accept the Symbol if it is immediately preceded by the terminal in the input string. If the start of the symbol coincides with start of the inout, the constraint will always succeed and the symbol is accepted.
Priority Declaration
Declare the priority of operators.

syntax Exp = alt_{1} > alt_{2} > alt_{3}
is the basic syntax for priorities. 
syntax Exp = alt_{1}  alt_{2} > alt_{3}  alt_{4}
, where the
signifies groups of equal priority 
syntax Exp = associativity ( _alt_{1}  … ) > _alt_{2}
, where an associativity group denotes a group of equal priority
Priority declarations define a partial ordering between the productions within a single nonterminal. The feature is specifically designed to fit with the semantics of expression sublanguages embedded in programming languages. There exist other mechanisms for Disambiguation, if Priority Declaration does not work for you.
The semantics of a priority relation A > B
is that B will not be nested under A in the leftmost or rightmost position.
Any other position of A will allow B fine. Note that the priority relation you define is transitively closed, so if A > B and B > C then A > C.
A finer point is that Rascal restricts the filtering of priority such that it is guaranteed that no parse errors occur at the cause of a priority. The following table defines when and where Rascal forbids a direct nesting between two productions parent > child
, depending on at which leftmost or rightmost positions the parent and the child are recursive.
If Parent > Child 
Parent None: E = "[" E "]" 
Parent Leftmost: E = E "*" 
Parent Rightmost: E = "*" E 
Parent Both: E = E "*" E 

Child None: 
No filter 
No filter 
No filter 
No filter 
Child Leftmost: 
No filter 
No filter 
Filter under right 
Filter under right 
Child Rightmost: 
No filter 
Filter under left 
No filter 
Filter under left 
Child Both: 
No filter 
Filter under left 
Filter under right 
Filter under left and right 
The following snippet uses all Priority Declaration features:
syntax Exp
= A: Id
 B: Number
> C: Exp "[" Exp "]"
 D: Exp "!"
> E: Exp "*" Exp
> F: Exp "+" Exp;
 bracket G: "(" Exp ")"
;
A short explanation:

C and D share a group of equal priority. They are incomparable in the partial ordering. That’s fine because
1![2]
is not ambiguous. 
Similarly A and B share a group; yet they are not recursive and so do not play any role in the priority ordering.

C and D both have higher priority then E and F, which means that E and F may not be directly nested under C or D.

However: E and F will be allowed under the second argument of C because it is not an outermost position. That’s fine because
1 [2 + 3]
is not ambiguous.
Here a number of strings for this language, with brackets to show how they will be parsed:

"1 + 2 * 3" will be parsed as "1 + (2 * 3)" because E > F.

"1 + 2 [ 3 ]" will be parsed as "1 + (2\[3\])" because C > F.

"1 * 3!" will be parsed as "1 + (3!)" because D > E.

"1 + [2 * 3]" will be parsed as "1 + ([2 * 3])" because priority is only defined for outermost positions.

Short notation for common expression grammars

Removes ambiguity but can not introduce parse errors

Allows the use of less nonterminals for the same expression grammar (typically only one), which makes parse trees simpler as well as the mapping to an abstract syntax tree more direct.

Please do not assume that Rascal’s priorities have the same semantics as SDF’s priorities.

When a priority does not have a filtering effect, such as in
E = E "+" > E ""
it is usually better to use normal alternative composition:E = E "+"  E "
"
. There is no difference in the semantics of parsing, but the latter expression is more intentional. 
You should not hide right or left recursion behind a nullable nonterminal, since the system will not filter the ambiguity then. Example: E = left "a"? E "*" E > E "" E will remain ambiguous. This should be written as: E = left ("a" E "*" E  E "*" E ) > E "" E; (unfolding the optional such that E becomes explicitly leftmost).
1.8.5. Parse Trees
An algebraic datatype for parse trees; produced by all parsers generated from syntax definitions.
Below is the full definition of Tree
and Production
and Symbol
. A parse tree is a nested tree structure of type Tree
.

Most internal nodes are applications (
appl
) of aProduction
to a list of childrenTree
nodes.Production
is the abstract representation of a [SyntaxDefinition] rule, which consists of a definition of an alternative for aSymbol
by a list ofSymbols
. 
The leaves of a parse tree are always characters (
char
), which have an integer index in the UTF8 table. 
Some internal nodes encode ambiguity (
amb
) by pointing to a set of alternativeTree
nodes.
The Production
and Symbol
types are an abstract notation for rules in Syntax Definitions, while the Tree
type is the actual notation
for parse trees.
Parse trees are called parse forests when they contain amb
nodes.
You can analyze and manipulate parse trees in three ways:

Directly on the
Tree
level, just like any other Algebraic Data Type 
Using Concrete Syntax

Using Actions
The type of a parse tree is the symbol that it’s production produces, i.e. appl(prod(sort("A"),[],{}),[])
has type A
. Ambiguity nodes
Each such a nonterminal type has Tree
as its immediate supertype.
// the following definition
syntax A = "a";
// would make the following [Test] succeed:
test a() = parse(#A,"a") ==
appl(prod(
sort("A"),
[lit("a")],
{}),
[appl(
prod(
lit("a"),
[\charclass([range(97,97)])],
{}),
[char(97)])]);
// you see that the defined nonterminal A ends up as the production for the outermost node. As the only child is the tree for recognizing the literal a, which is defined to be a single a from the characterclass [ a ].
// when we use labels in the definitions, they also end up in the trees:
// the following definition
lexical A = myA:"a" B bLabel;
lexical B = myB:"b";
// would make the following [Test] succeed:
test a() = parse(#A,"ab") == appl(prod(label("myA",lex("A")),[lit("a"),sort("bLabel",lex("B"))],{}),[appl(prod(lit("a"),[\charclass([range(97,97)]),[char(97)]),appl(prod(label("myB", lex("B"),[lit("b")],{}),[appl(prod(lit("b"),[\charclass([range(98,98)]),[char(98)])]) ]);
// here you see that the alternative name is a label around the first argument of `prod` while argument labels become labels in the list of children of a `prod`.
1.8.6. Symbol
The symbols that can occur in a syntax definition.
Nonterminal symbols are identifier names that start with an uppercase letter.
Symbol  Description 


Any symbol can be labeled with a field name that starts with a lowercase letter 
The following literal symbols and character classes are defined:
Symbol  Description 


Literal string 

Caseinsensitive literal string 

Character class 
The following operations on character classes can be composed arbitrarily:
Class  Description 


Complement of 

Difference of character classes 

Union of character classes 

Intersection of character classes 

Brackets for defining application order of class operators 
The following regular expressions can be constructed over Symbols:
Symbol  Description 


Optional Symbol 

Nonempty list of _Symbol_s 

Possibly empty list of _Symbol_s. 

Nonempty list of Symbol_{1} separated by Symbol_{2} 

Possibly empty list of Symbol_{1} separated by Symbol_{2}. 

Embedded sequence of symbols 

Embedded choice of alternative symbols 

The anonymous nonterminal for the language with the empty string 
Inline conditions (Disambiguations) can be added to symbols to constrain their acceptability:
Disambiguation  Description 


Symbol ends at end of line or end of file 

Symbol starts at begin of line 

Symbol starts at certain column index. 

Symbol_{1} must be (directly) followed by Symbol_{2} 

Symbol_{1} must not be (directly) followed by Symbol_{2} 

Symbol_{2} must be (directly) preceded by Symbol_{1} 

Symbol_{2} must not be (directly) preceded by Symbol_{1} 

Symbol_{1} must not be in the language defined by Symbol_{2} 
Symbols can be composed arbitrarily.
Every nonterminal symbol is a type.
The basic symbols are the nonterminal name and the labeled nonterminal name. These refer to the names defined by Syntax Definition. You can use any defined nonterminal name in any other definition (lexical in syntax, syntax in lexical, etc).
Then we have literals and character classes to define the terminals of a grammar.
When you use a literal such as "begin"
, Rascal will produce a definition for it down to the character level before generating a parser: syntax "begin" = [b][e][g][i][n];
. This effect will be visible in the Parse Trees produced by the parser. For case insensitive literals you will see a similar effect; the use of 'begin'
produces syntax 'begin' = [bB][eE][gG][iI][nN]
.
Character classes have the same escaping conventions as characters in a String literal, but spaces and newlines are meaningless and have to be escaped and the [
and ]
brackets as well as the dash 
need escaping. For example, one writes [\[ \] \ \n\]
for a class that includes the open and close square brackets and a space, a newline and a dash. Character classes support ranges as in [azAZ09]
. Please note about character classes that:

the operations on character classes are executed before parser generation time. You will not find explicit representation of these operations in [ParseTrees], but rather their net effect as resulting character classes.

Character classes are also ordered by Rascal and overlapping ranges are merged before parsers are generated. Equality between character classes is checked after this canonicalization.

Although all Symbols are type constructors, the character class operators are not allowed in types.
The other symbols either generate for you parts of the construction of a grammar, or they constrain the rules of the grammar to generate a smaller set of trees as Disambiguations.
The generative symbols are referred to as the regular symbols. These are like named nonterminals, except that they are defined implicitly and interpreted by the parser generator to produce a parser that can recognize a symbol optionally, iteratively, alternatively, sequentially, etc. You also need to know this about the regular symbols:

In Parse Trees you will find special nodes for the regular expression symbols that hide how these were recognized.

Patterns using Concrete Syntax have special semantics for the regular symbols (list matching, separator handling, ignoring layout, etc.).

Regular symbols are not allowed in keyword Syntax Definitions

Depending on their occurrence in a lexical, syntax or layout Syntax Definition the semantics of regular symbols changes. In the syntax context, layout nonterminals will be woven into the regular symbol, but not in the lexical and layout contexts. For example, a
Symbol*
in a syntax definition such assyntax X = A*;
will be processed tosyntax X = `{A Layout}*
. Similarly,syntax X = {A B}+;
will be processed tosyntax X = {A (Layout B Layout)}+;
.
The constraint symbols are specially there to deal with the fact that Rascal does not generate a scanner. There are no a priori disambiguation rules such as prefer keywords or longest match. Instead, you should use the constraint symbols to define the effect of keyword reservation and longest match.

It is important to note that these constraints work on a characterbycharacter level in the input stream. So, a follow constraint such as
A >> [az]
means that the character immediately following a recognized A must be in the range[az]
. 
Read more on the constraint symbols via Disambiguations.
A character class that defines all alphanumeric characters:
lexical AlphaNumeric = [azAZ09];
A character class that defines anything except quotes:
lexical AnythingExceptQuote = ![\"];
An identifier class with longest match (can not be followed immediately by [az]):
lexical Id = [az]+ !>> [az];
An identifier class with longest match and first match (can not be preceded or followed by [az]):
rascal>lexical Id = [az] !<< [az]+ !>> [az];
ok
An identifier class with some reserved keywords and longest match:
lexical Id = [az]+ !>> [az] \ "if" \ "else" \ "fi";
An optional else branch coded using sequence and optional symbols:
syntax Statement = "if" Expression "then" Statement ("else" Statement)? "fi";
A block of statements separated by semicolons:
syntax Statement = "{" {Statement ";"}* "}";
A declaration with an embedded list of alternative modifiers and a list of typed parameters:
syntax Declaration = ("public"  "private"  "static"  "final")* Type Id "(" {(Type Id) ","}* ")" Statement;

The symbol language is very expressive and can lead to short definitions of complex syntactic constructs.

There is no builtin longest match for iterators, which makes syntax definitions open to languages that do not have longest match.

There is no builtin keyword preference or reservation, which makes syntax definitions open to language composition and legacy languages.

By nesting too many symbols definitions can be become hard to understand.

By nesting too many symbols pattern matching and term construction becomes more complex. Extra nonterminals and rules with meaningful names can make a language specification more manageable.

The lack of automatic longest match and prefer keyword heuristics (you have to define it yourself), sometimes leads to unexpected ambiguity. See [Disambiguation].
1.9. Alias Declaration
Declare an alias for a type.
alias Name = Type;
Everything can be expressed using the elementary types and values that are provided by Rascal. However, for the purpose of documentation and readability it is sometimes better to use a descriptive name as type indication, rather than an elementary type. The use of aliases is a good way to document your intentions.
An alias declaration states that Name can be used everywhere instead of the already defined type Type. Both types are thus structurally equivalent.
Introduce two aliases ModuleId
and Frequency
for the type str.
alias ModuleId = str;
alias Frequency = int;
Another example is an alias definition for a graph containing integer nodes:
alias IntGraph = rel[int,int];
Note that the Rascal Standard Library provides a graph data type that is defined as follows:
alias Graph[&T] = rel[&T, &T];
In other words the standard graph datatype can be parameterized with any element type.
See Type Parameters for other examples parameterized alias declarations.
1.10. Annotation Declaration
Declare an annotation type for nodes. This feature is deprecated; please use [Keyword Fields] instead.
anno AnnoType OnType @ Name
An annotation may be associated with any node value, be it a pure node or some Algebraic Data Type derived from it.
Annotations are intended to attach application data to values, like adding position information or control flow information to source code or adding visualization information to a graph.
An annotation declaration defines:

AnnoType, the type of the annotation values,

OnType, the type of the values that are being annotated,

Name, the name of the annotation.
Any value of any named type can be annotated and the type of these annotations can be declared precisely.
The following constructs are provided for handling annotations:

Val @ Anno
: is an expression that retrieves the value of annotation Anno of value Val (may be undefined!). See [Selection]. 
Val_{1}[@Anno = Val_{2}]
: is an expression that sets the value of annotation Anno of the value Val_{1} to Val_{2} and returns Val_{1} with the new annotation value as result. See [Replacement]. 
Var @ Anno = Val
: is an assignment statement that sets the value of annotation Anno of the value of variable Var to Val.
Examples have been removed since this feature is deprecated.

Annotations are cumbersome since they change the structure of Values without changing the semantics of the identity of a value. This is why they are deprecated.
1.11. Tag Declaration
Tag declarations are not implemented (yet).
Tag declarations explain which type the expected value of a tag should have.

They help the type checker to find common errors and they can help the parser to parse the contents of a string tag using a contextfree grammar declaration.

Not yet implemented, so basically tags are not checked
2. Patterns
Patterns are a notation for pattern matching used to detect if a value has a certain shape, and then to bind variables to parts of the matched value.
For most of the Values, there is a corresponding pattern matching operator. Then there are some "higherorder" matching operators which make complex patterns out of simpler ones. This is the complete list:
Pattern  Syntax 

Literal 
Boolean, Integer, Real, Number, String, Location, or DateTime 
Regular Expression 

Variable declaration 

Multivariable 

Variable 

List 

Set 

Tuple 

Node 

Descendant 

Labelled 

TypedLabelled 

TypeConstrained 

Concrete 
(Symbol) ` Token_{1} Token_{2} … Token_{n} ` 
Patterns are used to dispatch functions and conditional control flow, to extract information from values and to conditionally filter values. The pattern following pattern kinds can be arbitrarily nested, following the above syntax:

Concrete Patterns: Concrete patterns.

Descendant Pattern: Deep match in an abstract pattern.

Labelled Pattern: Labelled abstract pattern.

List Pattern: List in abstract pattern.

Literal Pattern: Literal in abstract pattern.

MultiVariable Pattern: Multivariable (also known as Splicevariable) in abstract pattern.

Node pattern: Node in abstract pattern.

Regular Expression Pattern: Regular expression patterns.

Set Pattern: Set in abstract pattern.

Tuple Pattern: Tuple in abstract pattern.

Type Constrained Pattern: Type constrained abstract pattern.

Typed and Labelled Pattern: Typed, labelled, abstract pattern.

Variable Pattern: Variable in abstract pattern.

Variable Declaration Pattern: Variable declaration in abstract pattern.
All these patterns may be used in:

on the left of the Boolean Match operator (
:=
), 
on the left of the Enumerator operator (
←
), and 
as formal parameters of Function Declarations.

Try Catch statements to match thrown exceptions.
Each pattern binds variables in a conditional scope:

in further patterns to the right of the name which is bound in the same pattern

in the body of case statement (either a replacement or a statement body)

in the conditions and bodies of <If>, <For>, and <While> control flow statements

in the yielding expressions of comprehensions and in furter conditions of the comprehensions

If a pattern does not match, then it may be hard to find out why. A small test case is the best thing to create. Often a default alternative which <Throw>s an exception with the value which is not matched can be used to find out why this is happening.

If a variable is bound in the scope of a pattern, then it acts as an
==
test, so make sure to use fresh variables to avoid such accidental collisions.
2.1. Concrete Patterns
Concrete patterns.
Concrete pattern with expected symbol type: (Symbol) ` Token_{1} Token_{2} ... Token_{n} `
Typed variable inside a concrete pattern: <Type Var>
A concrete pattern is a pattern for matching a [Parse Tree]. The notation of a concrete pattern is the object language itself, the language that the parse tree describes. In other words, you can use a code example to match parsed code using a concrete pattern. These concrete code examples can contain Variable Patterns like the other Patterns.
The mechanism of concete patterns gives a good notation for matching complex structures such as a [Parse Tree], and it works in a simple manner:

the input code is parsed using a parser generated from a Syntax Definition; this generates parse trees.

the pattern example code is parsed using the same parser; this generates parse trees with Variable Patterns.

the parse tree with the Variable Patterns is matches against the parse tree of the input code, similarly to the way Node patterns work.
So, you could say that Concrete Patterns are a short notation for otherwise highly complex Node patterns on [Parse Tree]. Note that the [Typed Variable]s in a concrete pattern can only occur in the pattern at the location where the code for a full nonterminal of the Syntax Definition would be. The structure of a concrete pattern follows the structure of the grammar in the Syntax Definition and the types of the Variable Patterns are the syntax nonterminals of the Syntax Definition.
Inside concrete syntax patterns, layout is ignored while pattern matching. So parse trees which have different whitespace and comments but are otherwise the same will match anyway.
Examples (in a context where an appropriate concrete syntax has been defined):

Quoted syntax pattern with two pattern variable declarations:
rascal>import ParseTree; ok rascal>syntax Id = [az]+; ok rascal>syntax Num = [09]+; ok rascal>syntax Exp = left Exp "*" Exp > Exp "+" Exp  Id  Num; ok rascal>layout WS = [\ \n\r\t]*; ok rascal>visit (parse(#Exp, "x + x")) { >>>>>>> case (Exp) `<Id a> + <Id b>` => (Exp) `2 * <Id a>` when a == b >>>>>>>} warning, ambiguity predicted: Exp "+" Exp lacks left or right associativity Exp: (Exp) `2 * x`
WARNING: unexpected errors in the above SHELL example. Documentation author please fix! Some observations about this example:

Notice how the nonterminals
Exp
andId
from the Syntax Definition become types for the pattern. 
When this example pattern actually matches the variable
a
is bound and can be used again like any other Variable Pattern.
A full example of concrete patterns can be found in WithLayout.
2.2. Descendant Pattern
Deep match in an abstract pattern.
A descendant pattern performs a deep match of the pattern Pat. In other words, it matches when any element of the subject at any depth that matches Pat and is used to match, for instance, tree nodes at an arbitrary distance from the root.
rascal>import IO;
ok
rascal>data ColoredTree = leaf(int N)
>>>>>>>  red(ColoredTree left, ColoredTree right)
>>>>>>>  black(ColoredTree left, ColoredTree right);
ok
rascal>T = red(red(black(leaf(1), leaf(2)), black(leaf(3), leaf(4))), black(leaf(5), leaf(4)));
ColoredTree: red(
red(
black(
leaf(1),
leaf(2)),
black(
leaf(3),
leaf(4))),
black(
leaf(5),
leaf(4)))
Now we match for black
nodes with leaf(4)
as second argument:
rascal>for(/black(_,leaf(4)) := T)
>>>>>>> println("Match!");
Match!
Match!
list[void]: []
We use an anonymous variable _
at a position where we don’t care about the actual value that is matched.
In order to print the actual values of the matches, we would need an [Abstract/Labelled] pattern.
Here we match all leaves that occur as second argument of black
:
rascal>for(/black(_,leaf(int N)) := T)
>>>>>>> println("Match <N>");
Match 2
Match 4
Match 4
list[void]: []
Here we list all integers that occur in any leaf:
rascal>for(/int N := T)
>>>>>>> println("Match <N>");
Match 1
Match 2
Match 3
Match 4
Match 5
Match 4
list[void]: []
Rather than printing, we can also collect them in a list using [$Statements/Append]:
rascal>for(/int N := T)
>>>>>>> append N;
list[int]: [1,2,3,4,5,4]
2.3. Labelled Pattern
Labelled abstract pattern.
A labelled pattern matches the same values as Pat, but has as sideeffect that the matched value is assigned to Var.
rascal>import IO;
ok
rascal>data ColoredTree = leaf(int N)
>>>>>>>  red(ColoredTree left, ColoredTree right)
>>>>>>>  black(ColoredTree left, ColoredTree right);
ok
rascal>T = red(red(black(leaf(1), leaf(2)), black(leaf(3), leaf(4))), black(leaf(5), leaf(4)));
ColoredTree: red(
red(
black(
leaf(1),
leaf(2)),
black(
leaf(3),
leaf(4))),
black(
leaf(5),
leaf(4)))
rascal>for(/M:black(_,leaf(4)) := T)
>>>>>>> println("Match <M>");
Match black(leaf(3),leaf(4))
Match black(leaf(5),leaf(4))
list[void]: []
We use an anonymous variable _
at a position where we don’t care about the actual value that is matched.
2.4. List Pattern
List in abstract pattern.
A list pattern matches a list value (the subject), provided that Pat_{1}, Pat_{2}, …, Pat_{n} match the elements of that list in order. Special cases exist when one of the patterns Pat_{i} is

a Variable Pattern with a type that is identical to the element type of the subject list: the variable is matched with the value at the corresponding position in the subject list.

a MultiVariable Pattern, with an optional element type that is identical to the element type of the subject list: list matching is applied and the variable can match an arbitrary number of elements of the subject list.

a Variable Pattern, where the variable has been declared with a list type, but not initialized, outside the pattern: list matching is applied and the variable can match an arbitrary number of elements of the subject list.

a [Variable] Pattern], where the variable has been declared with a type equal to the element type of the subject, but not initialized, outside the pattern: the variable is matched with the value at the corresponding position in the subject list.
rascal>import IO;
ok

A single variable
rascal>if([10, int N, 30, 40, 50] := [10, 20, 30, 40, 50]) >>>>>>> println("Match succeeded, N = <N>"); Match succeeded, N = 20 ok

An untyped multivariable:
rascal>if([10, *L, 50] := [10, 20, 30, 40, 50]) >>>>>>> println("Match succeeded, L = <L>"); Match succeeded, L = [20,30,40] ok

A typed multivariable:
rascal>if([10, *int L, 50] := [10, 20, 30, 40, 50]) >>>>>>> println("Match succeeded, L = <L>"); Match succeeded, L = [20,30,40] ok
A list pattern may also be nonlinear, i.e., it may contain uses of variables that were bound earlier in the pattern
(here, the second occurence of L
):
rascal>if([10, *L, 40, *L, 50] := [10, 20, 30, 40, 20, 30, 50])
>>>>>>> println("Match succeeded, L = <L>");
Match succeeded, L = [20,30]
ok
Here we see an example, where all pairs of equal elements in a list are printed:
rascal>for([*L1, int N, *L2, N, *L3] := [ 5, 10, 20, 30, 40, 30, 15, 20, 10])
>>>>>>> println("N = <N>");
N = 10
N = 20
N = 30
list[void]: []
Here we print all ways in which a given list can be partitioned in two lists:
rascal>for([*L1, *L2] := [10, 20, 30, 40, 50])
>>>>>>> println("<L1> and <L2>");
[] and [10,20,30,40,50]
[10] and [20,30,40,50]
[10,20] and [30,40,50]
[10,20,30] and [40,50]
[10,20,30,40] and [50]
[10,20,30,40,50] and []
list[void]: []

Already declared list variable:
rascal>list[int] L; ok rascal>if([10, L, 50] := [10, 20, 30, 40, 50]) >>>>>>> println("Match succeeded, L = <L>"); Match succeeded, L = [20,30,40] ok

Already declared element variable:
rascal>int N; ok rascal>if([10, N, 30, 40, 50] := [10, 20, 30, 40, 50]) >>>>>>> println("Match succeeded, N = <N>"); Match succeeded, N = 20 ok
2.5. Literal Pattern
Literal in abstract pattern.
A literal of one of the basic types Boolean, Integer, Real, Number, String, Location, or DateTime can be used as abstract pattern. A literal pattern matches with a value that is identical to the literal.
A literal pattern matches with a value that is equal to it:
rascal>123 := 123
bool: true
rascal>"abc" := "abc"
bool: true
A literal pattern does not match with a value that is not equal to it:
rascal>123 := 456
bool: false
rascal>"abc" := "def"
bool: false
If the type of the literal pattern is incomparable to the subject’s type, a static type error is produced to announce that the match is guaranteed to fail:
rascal>123 := "abc";
prompt:///(7,5,<1,7>,<1,12>): Expected int, but got str
Advice: http://tutor.rascalmpl.org/Errors/Static/UnexpectedType/UnexpectedType.html
ok
However, a literal pattern can be used to filter among other values:
rascal>value x = "abc";
value: "abc"
rascal>123 := x;
bool: false
rascal>x = 123;
value: 123
rascal>123 := x;
bool: true
2.6. MultiVariable Pattern
Multivariable (also known as Splicevariable) in abstract pattern.

*Var

*Type Var
A multivariable is an abbreviation for a variable declaration pattern. It can occur in a list pattern or set pattern and can match zero or more list or set elements. Optionally the element type of the multivariable may be specified.
rascal>import IO;
ok
Using lists:
rascal>if([10, *N, 50] := [10, 20, 30, 40, 50])
>>>>>>> println("Match succeeds, N == <N>");
Match succeeds, N == [20,30,40]
ok
the above is equivalent with:
rascal>if([10, *int N, 50] := [10, 20, 30, 40, 50])
>>>>>>> println("Match succeeds, N == <N>");
Match succeeds, N == [20,30,40]
ok
Using sets:
rascal>if({10, *S, 50} := {50, 40, 30, 30, 10})
>>>>>>> println("Match succeeds, S == <S>");
Match succeeds, S == {40,30}
ok
the above is equivalent with:
rascal>if({10, *int S, 50} := {50, 40, 30, 30, 10})
>>>>>>> println("Match succeeds, S == <S>");
Match succeeds, S == {40,30}
ok
In older versions of Rascal the type of a multivariable had to be a list or set type.
2.7. Node pattern
Node in abstract pattern.
A node pattern matches a node value or a datatype value, provided that Name matches with the constructor symbol of that value and Pat_{1}, Pat_{2}, …, Pat_{n} match the children of that value in order.
Match on node values (recall that the function symbol of a node has to be quoted, see [Values/Node]):
rascal>import IO;
ok
rascal>if("f"(A,13,B) := "f"("abc", 13, false))
>>>>>>> println("A = <A>, B = <B>");
A = abc, B = false
ok
Define a data type and use it to match:
rascal>data Color = red(int N)  black(int N);
ok
rascal>if(red(K) := red(13))
>>>>>>> println("K = <K>");
K = 13
ok
2.8. Regular Expression Pattern
Regular expression patterns.
Regular expressions are used to match a string value and to decompose it in parts and also to compose new strings. Regular expression patterns bind variables of type str
when the match succeeds, otherwise they do not bind anything.
They can occur in cases of visit and switch statements,
on the lefthand side of the match operator (:=
or !:=
) and as declarator in enumerators.
We use a regular expression language that slightly extends/modifies the Java Regex language:

Regular expression are delimited by
/
and/
optionally followed by modifiers (see below). 
We allow variable introductions, syntax
<_Name_:_Regex_>
, which introduce a variable of typestr
named Name. A variable introduction corresponds to a group in a Java regexp. Each variable that is introduced should be unique, but may be referenced more than once later in the regular expression. 
Regular expressions may also contain references to variables, syntax
<_Name_>
, the string value of variableName
is used at the position of the variable reference. This can be used to define socalled nonlinear patterns. 
Java regular expressions allow optional groups, which may introduce null bindings. Since uninitialized variables are not allowed in Rascal, we limit the kinds of expressions one can write here by not allowing nesting of variable introductions.

We allow variable references in a regular expression of the form:
<_Name_>
which inserts the string value of Name in the pattern. $Name$ should have been introduced in the regular expression itself or in the context in which the regular expression occurs. 
In Perl matching options follow the regular expression, but Java uses the notation
(?Option)
at the beginning of the regular expression to set matching options. We support both styles. The following modifiers are supported:
multiline matching:
(?m)
at the start of the regular expression or the modifierm
at the end of the regular expression. The anchors^
and$
usually only match at the beginning and end of the subject string. When this option is set they also match any begin or end of line that is embedded in the subject string. Examples: 
caseinsensitive matching:
(?i)
or modifieri
. Match characters irrespective of their case. 
singleline mode:
(?s)
or modifiers
. The.
expression does usually not match line terminators. When singleline mode is set, it will match any character including line terminators. 
unix lines:
(?d)
or modifierd
. Usually newlines (\n
), carriage return (\r
) and new line carriage return (\n\r
) sequences are all considered line terminators. When this option is set, only newline is considered to be a line terminator.

For convenience, we summarize the most frequently used constructs in regular expressions in the following table.
Operator  Description 


The single character 

The punctuation character 

The backslash character 

Newline character 

Tab character 

One of the characters between the brackets (also known as character class). Character ranges and set operations on character classes may be used. 

Any one character not between the brackets. 

Character range: character between 

Any character except a line terminator. If singleline mode is set (using 

Digit: 

Nondigit:` [^09]` 

Whitespace 

Anything but whitespace. 

A word: 

A nonword:` [^\w]` 

Match 
`x 
y` 
Match 

Optional occurrence of 

Zero or more occurrences of 

One or more occurrences of 

Exactly 



At least 

The beginning of the subject string 

The end of the input string 

Word boundary: position between a word and a nonword character 

Here are some examples of regular expression patterns.
/\brascal\b/i
does a caseinsensitive match (i
) of the word rascal
between word boundaries (\b
). And
/^.*?<word:\w+><rest:.*$>/m
does a multiline match (m
), matches the first consecutive word characters (\w
) and assigns them to the variable word
. The remainder of the string is assigned to the variable rest
.
A variable reference used to make a nonlinear pattern:
/<x:[az]+><x>/
matches strings like abcabc
that consist of two identical sequences of letters separated
by three dashes. Variables that are referenced in a regular expression may also come from
the context in which the regular expression occurs. For instance,
/<x><n>/
will use the current values of x
and n
as regular expression. For values "abc"
, respectively, 3
this would be equivalent to the regular expression:
/abc3/
Observe that context variables may be of arbitrary type and that their value is first converted to
a string before it is inserted in the regular expression. This can be used in many ways.
For instance, regular expressions may contain restrictions on the number of repetitions
of an element: /a{3}/
will match exactly three letters a. Also minimum and maximum
number of occurrences can be defined.
Here is how the repetition count can be inserted by a variable reference
(where n
is assumed to have an integer value):
/a{<n>}/
Taking this example one step further, we can even write
/<x:a{<n>}>/
in other words, we introduce variable x
and its defining regular expression contains a
reference to a context variable.
Multiline matching:
rascal>/XX$/ := "lineoneXX\nlinetwo";
bool: false
rascal>/XX$/m := "lineoneXX\nlinetwo";
bool: true
rascal>/(?m)XX$/ := "lineoneXX\nlinetwo";
bool: true
Caseinsensitive matching:
rascal>/XX/ := "some xx";
bool: false
rascal>/XX/i := "some xx";
bool: true
rascal>/(?i)XX/ := "some xx";
bool: true
Singleline mode:
rascal>/a.c/ := "abc";
bool: true
rascal>/a.c/ := "a\nc";
bool: false
rascal>/a.c/s := "a\nc";
bool: true
rascal>/(?s)a.c/ := "a\nc";
bool: true
Here are examples, how to escape punctuation characters in regular expressions:
rascal>/a\/b/ := "a/b";
bool: true
rascal>/a\+b/ := "a+b";
bool: true
2.9. Set Pattern
Set in abstract pattern.
A set pattern matches a set value (the subject), provided that Pat_{1}, Pat_{2}, …, Pat_{n} match the elements of that set in any order (recall that the elements of a set are unordered and do not contain duplicates). Completely analogous to list patterns, there are special cases when one of the patterns Pat_{i} is

a Variable Declaration Pattern with a type that is identical to the element type of the subject set: the variable is matched with one value in the subject set.

a MultiVariable Pattern, with an optional element type that is identical to the element type of the subject set: set matching is applied and the variable can match an arbitrary number (in arbitrary order) of elements of the subject set.

a Variable Pattern, where the variable has been declared with a set type, but not initialized, outside the pattern: set matching is applied and the variable can match an arbitrary number (in arbitrary order) of elements of the subject set.

a Variable Pattern, where the variable has been declared with a type equal to the element type of the subject, but not initialized, outside the pattern: the variable is matched with one value in the subject set.
rascal>import IO;
ok

A single variable
rascal>if({10, 30, 40, 50, int N} := {10, 20, 30, 40, 50}) >>>>>>> println("Match succeeded, N = <N>"); Match succeeded, N = 20 ok

An untyped multivariable:
rascal>if({10, *S, 50} := {50, 40, 30, 20, 10}) >>>>>>> println("Match succeeded, S = <S>"); Match succeeded, S = {40,20,30} ok

A typed multivariable:
rascal>if({10, *int S, 50} := {50, 40, 30, 20, 10}) >>>>>>> println("Match succeeded, S = <S>"); Match succeeded, S = {40,20,30} ok
Here we see an example, where all possible splits of a set in two subsets are printed:
rascal>for({*S1, *S2} :={30, 20, 10})
>>>>>>> println("<S1> and <S2>");
{10,20,30} and {}
{10,20} and {30}
{10,30} and {20}
{10} and {20,30}
{20,30} and {10}
{20} and {10,30}
{30} and {10,20}
{} and {10,20,30}
list[void]: []

Already declared set variable:
rascal>set[int] S; ok rascal>if({10, *S, 50} := {10, 20, 30, 40, 50}) >>>>>>> println("Match succeeded, S = <S>"); Match succeeded, S = {40,20,30} ok

Already declared element variable:
rascal>int N; ok rascal>if({10, N, 30, 40, 50} := {50, 40, 30, 20, 10}) >>>>>>> println("Match succeeded, N = <N>"); Match succeeded, N = 20 ok
2.10. Tuple Pattern
Tuple in abstract pattern.
A tuple pattern matches a tuple value, provided that Pat_{1}, Pat_{2}, …, Pat_{n} match the elements of that tuple in order.
rascal>import IO;
ok
rascal>if(<A, B, C> := <13, false, "abc">)
>>>>>>> println("A = <A>, B = <B>, C = <C>");
A = 13, B = false, C = abc
ok
2.11. Type Constrained Pattern
Type constrained abstract pattern.
A type constrained pattern matches provided that the subject has type Type and Pat matches. This can be handy in case of ambiguity (say more than one constructor with the same name), or in case the pattern is completely general. See an example below:
Warning: This does not seem to work properly. There is a bug.
rascal>import IO;
ok
Some example data type which contains generic values as well as specific expressions:
rascal>data Exp = val(value v)  add(Exp l, Exp r)  sub(Exp l, Exp r);
ok
rascal>ex = add(add(val("hello"(1,2)),val("bye")), sub(val(1),val(2)));
Exp: add(
add(
val("hello"(1,2)),
val("bye")),
sub(
val(1),
val(2)))
Here we constrain the match to find only Exps:
rascal>visit (ex) {
>>>>>>> case [Exp] str name(,) : println("node name is <name>");
>>>>>>>}
node name is hello
node name is add
node name is sub
node name is add
Exp: add(
add(
val("hello"(1,2)),
val("bye")),
sub(
val(1),
val(2)))
Here we do not constrain the same pattern:
rascal>visit (ex) {
>>>>>>> case str name(,) : println("node name is <name>");
>>>>>>>}
node name is hello
node name is add
node name is sub
node name is add
Exp: add(
add(
val("hello"(1,2)),
val("bye")),
sub(
val(1),
val(2)))
2.12. Typed and Labelled Pattern
Typed, labelled, abstract pattern.
A typed, labelled, pattern matches when the subject value has type Type and Pat matches. The matched value is assigned to Var.
This construct is used for:

binding the whole pattern to a variable while also matching some stuff out of it:
MyType t : someComplexPattern(f(int a), int b))
. This is similar to Labelled Patterns but with an extra type 
to assert that the pattern has a certain type. This can be useful in disambiguating a constructor name, as in the example below.
rascal>import IO;
ok
rascal>data Lang = add(Lang l, Lang r)  number(int i);
ok
rascal>data Exp = id(str n)  add(Exp l, Exp r)  subtract(Exp l, Exp r)  otherLang(Lang a);
ok
rascal>ex = add(id("x"), add(id("y"), otherLang(add(number(1),number(2)))));
Exp: add(
id("x"),
add(
id("y"),
otherLang(add(
number(1),
number(2)))))
rascal>visit (ex) {
>>>>>>> case Lang l:add(,) : println("I found a Lang <l>");
>>>>>>> case Exp e:add(,) : println("And I found an Exp <e>");
>>>>>>>}
I found a Lang add(number(1),number(2))
And I found an Exp add(id("y"),otherLang(add(number(1),number(2))))
And I found an Exp add(id("x"),add(id("y"),otherLang(add(number(1),number(2)))))
Exp: add(
id("x"),
add(
id("y"),
otherLang(add(
number(1),
number(2)))))
2.13. Variable Pattern
Variable in abstract pattern.
Var
A variable pattern can act in two roles:

If Var has already a defined value then it matches with that value.

If Var has not been defined before (or it has been declared but not initialized) then it matches any value. That value is assigned to Var. The scope of this variable is the outermost expression in which the pattern occurs or the enclosing If, While, or Do if the pattern occurs in the test expression of those statements.
Initialize variable N
rascal>N = 10;
int: 10
and use N
in a pattern; its value is used as value to match with:
rascal>N := 10;
bool: true
rascal>N := 20;
bool: false
Use a nonexisting variable in a pattern, it is bound when the match succeeds:
rascal>import IO;
ok
rascal>if(M := 10)
>>>>>>> println("Match succeeded, M == <M>");
Match succeeded, M == 10
ok
2.14. Variable Declaration Pattern
Variable declaration in abstract pattern.
A variable declaration
Type Var
can be used as abstract pattern. A variable declaration introduces a new variable Var that matches any value of the given type Type. That value is assigned to Var when the whole match succeeds.
The scope of this variable is the outermost expression in which the pattern occurs or the enclosing If, While, or Do if the pattern occurs in the test expression of those statements.
Let’s first perform a match that succeeds:
rascal>str S := "abc";
bool: true
and now we attempt to inspect the value of S
:
rascal>S;
prompt:///(0,1,<1,0>,<1,1>): Undeclared variable: S
Advice: http://tutor.rascalmpl.org/Errors/Static/UndeclaredVariable/UndeclaredVariable.html
ok
As mentioned above: S
is only bound in the scope of the match expression!
Let’s explore how bindings work in an if statement:
rascal>import IO;
ok
rascal>if(str S := "abc")
>>>>>>> println("Match succeeds, S == \"<S>\"");
Match succeeds, S == "abc"
ok
3. Expressions
The expressions available in Rascal.
The expression is the basic unit of evaluation and may consist of the ingredients shown in the figure.

An elementary literal value, e.g. constants of the types Boolean, Integer, Real, Number, String, Location or DateTime.

A structured value for List, Set, Map, Tuple or Relation. The elements are first evaluated before the structured value is built.

A variable that evaluates to its current value.

A call to a function or constructor:

A function call. First the arguments are evaluated and the corresponding function is called. The value returned by the function is used as value of the function call. See Call.

A constructor. First the arguments are evaluated and then a data value is constructed for the corresponding type. This data value is used as value of the constructor. Constructors are functions that can be used in all contexts where functions can be used. See Constructor.


An operator expression. The operator is applied to the arguments; the evaluation order of the arguments depends on the operator. The result returned by the operator is used as value of the operator expression. See Operators.

A Visit expression.

A Boolean Any expression.

An Boolean All expression.

Some statements like If, For, While and Do can also be used in expressions, see Statement as Expression.
3.1. Values
The different types of values.

Boolean: Boolean values.

Boolean All: All argument expressions are true.

Boolean And: Boolean and operator.

Boolean Any: Any combination of argument values is true.

Boolean Equivalence: The equivalence operator on Boolean values.

Boolean IfDefinedElse: Test whether expression has a defined value, otherwise provide alternative.

Boolean Implication: The implication operator on Boolean values.

Boolean IsDefined: Test whether the value of an expression is defined.

Boolean Match: Match a pattern against an expression.

Boolean Negation: The not operator on Boolean values.

Boolean NoMatch: Negated [Boolean Match] operator.

Boolean Or: The or operator on Boolean values.


Constructor: Constructors create values for userdefined datatypes (Algebraic Datatypes).

DateTime: Date and time values.

DateTime Equal: Equality on datetime values.

DateTime Field Selection: Select a field from a datetime value.

DateTime GreaterThan: Greater than operator on datetime values.

DateTime GreaterThanOrEqual: Greater than or equal operator on datetime values.

DateTime LessThan: Less than operator on datetime values.

DateTime LessThanOrEqual: Less than or equal operator on datetime values.

DateTime NotEqual: Not equal operator on datetime values.


Integer: Integer values.

List: List values.

List Append: Append an element at the end of a list.

List Comprehension: A list comprehension generates a list value.

List Concatenation: Concatenate two lists.

List Difference: The difference between two lists.

List Equal: Equality on lists.

List Insert: add an element in front of a list.

List Intersection: Intersection of two lists.

List NotEqual: Not equal operator on lists.

List Product: Compute the product of two lists.

List Slice: Retrieve a slice of a list.

List Splice: Splice the elements of a list in an enclosing list.

List StrictSubList: The strict sublist operator on lists.

List StrictSuperList: The strict super list operator on lists.

List SubList: The sublist operator on lists.

List Subscription: Retrieve a list element via its index.

List SuperList: The super list operator on lists.

List in: Membership test on list elements.

List notin: Negated membership test on lists.


ListRelation: ListRelation values.

ListRelation CartesianProduct: Cartesian product of two list relation values.

ListRelation Composition: Composition of two list relation values.

ListRelation FieldSelection: Select a field (column) from a list relation value.

ListRelation Join: Join two list relation values.

ListRelation Reflexive Transitive Closure: The reflexive transitive closure of a binary list relation.

ListRelation Subscription: Indexing of a list relation via tuple values.

ListRelation Transitive Closure: Transitive closure on binary list relation values.


Location: (Source code) location values.

Location AddSegment: Locations can be concatenated with strings to add segments to the path component.

Location Equal: Equality operator on locations.

Location FieldSelection: Field selection on locations.

Location GreaterThan: The greater than operator on location values.

Location GreaterThanOrEqual: The greater than or equal operator on location values.

Location LessThan: The less than operator on location values.

Location LessThanOrEqual: The less than or equal operator on location values.

NotEqual: The not equal operator on location values.


Map: Map values.

Map Composition: Composition of two map values.

Map Comprehension: A map comprehension generates a map value.

Map Difference: The difference between two maps.

Map Equal: Equality operator on maps.

Map Intersection: Intersection of two maps.

Map NotEqual: Not equal operator on map values.

Map StrictSubMap: Strict submap operator on map values.

Map StrictSuperMap: Strict supermap operator on map values.

Map SubMap: Submap operator on map values.

Map Subscription: Retrieve a value by its key in map.

Map SuperMap: Supermap operator on map values.

Map Union: Union of two maps.

Map in: Membership test on the keys of a map.

Map notin: Negated membership test on the keys of a map.


Node: Node values.

Node Equal: Equal operator on node values.

Node GreaterThan: Greater than operator on node values.

Node GreaterThanOrEqual: Greater than or equal operator on node values.

Node LessThan: Less than operator on node values.

Node LessThanOrEqual: Less than or equal operator on node values.

Node NotEqual: Not equal operator on node values.

Node Slice: Retrieve a slice of a node’s argument list.

Node Subscription: Retrieve an argument of a node via its index.


Number: Numeric values.

Number Addition: Addition on numeric values.

Number Conditional: Conditional expression for numeric values.

Number Division: Division on numeric values.

Number Equal: Equality operator on numeric values.

Number GreaterThan: Greater than operator on numeric values.

Number GreaterThanOrEqual: Greater than or equal operator on numeric values.

Number LessThan: Less than operator on numeric values.

Number LessThanOrEqual: Less than or equal operator on numeric values.

Number Multiplication: Multiply two numeric values.

Number Negation: Negate a numeric value.

Number NotEqual: Not equal operator on numeric values.

Number Remainder: Remainder of two integer values.

Number Subtraction: Subtract two numeric values.


Range: Numeric range of values.

Real: Real values.

ReifiedTypes: Types can be represented by values.

Relation: Relation values.

Relation CartesianProduct: Cartesian product of two relation values.

Relation Composition: Composition of two relation values.

Relation FieldSelection: Select a field (column) from a relation value.

Relation Join: Join two relation values.

Relation ReflexiveTransitiveClosure: The reflexive transitive closure of a binary relation.

Relation Subscription: Indexing of a relation via tuple values.

Relation TransitiveClosure: Transitive closure on binary relation values.


Set: Set values.

Set Comprehension: A set comprehension generates a set value.

Set Difference: The difference between two sets.

Set Equal: Equal operator on set values.

Set Insert: Add an element to a set.

Set Intersection: Intersection of two sets.

Set NotEqual: Not equal operator on set values.

Set Product: The product of two set values.

Set Splice: Splice the elements of a set in an enclosing set.

Set StrictSubSet: Strict subset operator on set values.

Set StrictSuperSet: Strict superset operator on set values.

Set SubSet: Subset operator on set values.

Set SuperSet: Superset operator on set values.

Set Union: Union of two set values.

Set in: Membership test on set values.

Set notin: Negated membership test on set values.


String: String values.

String Concatenation: Concatenate two strings.

String Equal: Equality operator on string values.

String GreaterThan: Greater than operator on string values.

String GreaterThanOrEqual: Greater than or equal operator on string values.

String LessThan: Less than operator on string values.

String LessThanOrEqual: Less than or equal operator on string values.

String NotEqual: Not equal operator on string values.

String Slice: Retrieve a slice of a string.

String Subscription: Retrieve a substring via its index.


Tuple: Tuple values.

Tuple Concatenation: Concatenate two tuple values.

Tuple Equal: Equality operator on tuple values.

Tuple FieldSelection: Select a field from a tuple by its field name.

Tuple GreaterThan: Greater than operator on tuple values.

Tuple GreaterThanOrEqual: Greater than or equal operator on tuple values.

Tuple LessThan: Less than operator on tuple values.

Tuple LessThanOrEqual: Less than or equal operator on tuple values.

Tuple NotEqual: Not equal operator on tuple values.

Tuple Subscription: Retrieve a tuple field by its index position.


Value: Values of type
value
.
Value Conditional: Conditional expression on values.

Value Equal: Equal operator on values.

Value GreaterThan: Greater than operator on values.

Value GreaterThanOrEqual: Greater than or equal operator on values.

Value LessThan: Less than operator on values.

Value LessThanOrEqual: Less than or equal operator on values.

Value NotEqual: Not equal operator on values.


Void: Values of type
void
.
3.1.1. Boolean
Boolean values.
true
, false
bool
The Booleans are represented by the type bool
which has two values: true
and false
.
The Boolean operators (to be more precise: operators with a value of type Boolean as result) have shortcircuit semantics. This means that the operands are evaluated until the outcome of the operator is known.
Most operators are selfexplanatory except the match (:=) and no match (!:=) operators that are also the main reason to treat Boolean operator expressions separately. Although we describe patterns in full detail in Patterns, a preview is useful here. A pattern can

match (or not match) any arbitrary value (that we will call the subject value);

during the match variables may be bound to subvalues of the subject value.
The match operator
Pat := Exp
is evaluated as follows:

Exp is evaluated, the result is a subject value;

the subject value is matched against the pattern Pat;

if the match succeeds, any variables in the pattern are bound to subvalues of the subject value and the match expression yields
true
; 
if the match fails, no variables are bound and the match expression yields
false
.
This looks and is nice and dandy, so why all this fuss about Boolean operators? The catch is that—as we will see in Patternsa match need not be unique. This means that there may be more than one way of matching the subject value resulting in different variable bindings.
This behaviour is applicable in the context of all Rascal constructs where a pattern match determines the flow of control of the program, in particular:

Boolean expressions: when a pattern match fails that is part of a Boolean expression, further solutions are tried in order to try to make the Boolean expression true.

Tests in Boolean Any and Boolean All expressions.

Tests and Enumerators in comprehensions.

Pattern matches in cases of a Visit.

Pattern matches in cases of a Switch.
The following operators are provided for Boolean:

Boolean All: All argument expressions are true.

Boolean And: Boolean and operator.

Boolean Any: Any combination of argument values is true.

Boolean Equivalence: The equivalence operator on Boolean values.

Boolean IfDefinedElse: Test whether expression has a defined value, otherwise provide alternative.

Boolean Implication: The implication operator on Boolean values.

Boolean IsDefined: Test whether the value of an expression is defined.

Boolean Match: Match a pattern against an expression.

Boolean Negation: The not operator on Boolean values.

Boolean NoMatch: Negated [Boolean Match] operator.

Boolean Or: The or operator on Boolean values.
There are also library functions available for Booleans.
Consider the following match of a list
rascal>[1, *int L, 2, *int M] := [1,2,3,2,4]
bool: true
By definition list[int] L
and list[int] M
match list elements that are part of the enclosing list in which they occur. If they should match a nested list each should be enclosed in list brackets.
There are two solutions for the above match:

L
=[]
andM
=` [2, 3, 2, 4]`; and 
L
=[2,3]
andM
=` [4]`.
rascal>import IO;
ok
rascal>for ([1, *int L, 2, *int M] := [1,2,3,2,4])
>>>>>>> println("L: <L>, M: <M>");
L: [], M: [3,2,4]
L: [2,3], M: [4]
list[void]: []
Depending on the context, only the first solution of a match expression is used, respectively all solutions are used. If a match expression occurs in a larger Boolean expression, a subsequent subexpression may yield false and — depending on the actual operator — evaluation backtracks to a previously evaluated match operator to try a next solution. Let’s illustrate this by extending the above example:
[1, *int L, 2, *int M] := [1,2,3,2,4] && size(L) > 0
where we are looking for a solution in which L has a nonempty list as value. Evaluation proceeds as follows:

The left argument of the
&&
operator is evaluated: the match expression is evaluated resulting in the bindingsL = []
andM = [2, 3, 2, 4]
; 
The right argument of the
&&
operator is evaluated:size(L) > 0
yieldsfalse
; 
Backtrack to the left argument of the
&&
operator to check for more solutions: indeed there are more solutions resulting in the bindingsL = [2,3]
andM = [4]
; 
Proceed to the right operator of
&&
: this timesize(L) > 0
yieldstrue
; 
The result of evaluating the complete expression is
true
.
rascal>import IO;
ok
rascal>import List;
ok
for prints them all:
rascal>for ([1, *int L, 2, *int M] := [1,2,3,2,4] && size(L) > 0)
>>>>>>> println("L: <L>, M: <M>");
L: [2,3], M: [4]
list[void]: []
if prints the first
rascal>if ([1, *int L, 2, *int M] := [1,2,3,2,4] && size(L) > 0)
>>>>>>> println("L: <L>, M: <M>");
L: [2,3], M: [4]
ok
Boolean All
All argument expressions are true.
all ( Exp_{1}, Exp_{2}, … )
Exp_{1} 
Exp_{2} 
…  all ( Exp_{1}, Exp_{2}, … ) 



… 

Yields true
when all combinations of values of Exp_{i} are true.
Are all integers 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 even?
rascal>all(int n < [1 .. 10], n % 2 == 0);
bool: false
Are all integers 0, 2, 4, 6, 8, 10 even?
rascal>all(int n < [0, 2 .. 10], n % 2 == 0);
bool: true
When one of the Exp_{i} enumerates the elements of an empty list, all
always returns true
:
rascal>all(int n < [], n > 0);
bool: false
Pitfalls
The Rascal interpreter and compiler give different results on an empty list.
The interpreter returns fals for the abo eexample.

Boolean And
Boolean and operator.
Exp_{1} && Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} && Exp_{2} 




The and operator on Boolean values defined as follows:
Exp_{1} 
Exp_{2} 
Exp_{1} && Exp_{2} 













Boolean operators have short circuit semantics: only those operands are evaluated that are needed to compute the result. In the case of the &&
operator, the result is false
if Exp_{1}
evaluates to false
, otherwise Exp_{2}
is evaluated to determine the result.
Note that &&
backtracks over its argument expressions until it can find an evaluation that yields true
unless there is none. This may happen if the left or right expression is a nondeterministic pattern match or a value generator.
Variable assignments as a result of matching or generator expressions under a &&
are visible outside the context of the operator, but only if the context is conditional, such as an ifthenelse or a for loop. Note that if one of the argument expressions evaluates to false, then no binding is done either.
rascal>true && false;
bool: false
rascal>i < [1,2,3] && (i % 2 == 0)
bool: true
rascal>import IO;
ok
rascal>if (i < [1,2,3] && (i % 2 == 0))
>>>>>>> println("<i> % 2 == 0");
2 % 2 == 0
ok
rascal>for (i < [1,2,3,4] && (i % 2 == 0))
>>>>>>> println("<i> % 2 == 0");
2 % 2 == 0
4 % 2 == 0
list[void]: []

The backtracking
&&
allows one to express searching for a computational solution in concise manner.

Side effects to global variables or IO in the context of a backtracking
&&
can lead to more effects than you bargained for.
rascal>import IO;
ok
rascal>int i = 0;
int: 0
rascal>bool incr() { i += 1; return true; }
bool (): function(prompt:///(0,36,<1,0>,<1,36>))
rascal>for (int j < [1,2,3] && incr() && (i % 2 == 0))
>>>>>>> println("once true for <j>");
once true for 2
list[void]: []
rascal>i;
int: 3
Boolean Any
Any combination of argument values is true.
any ( Exp_{1}, Exp_{2}, … )
Exp_{1} 
Exp_{2} 
…  any ( Exp_{1}, Exp_{2}, … ) 



… 

Yields true
when at least one combination of values of Exp_{i} is true.
rascal>any(int n < [1 .. 10], n % 2 == 0);
bool: true
Boolean Equivalence
The equivalence operator on Boolean values.
Exp_{1} ⇐⇒ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐⇒ Exp_{2} 




The equivalence operator on Boolean values defined as follows:
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐⇒ Exp_{2} 













Boolean operators have short circuit semantics: only those operands are evaluated that are needed to compute the result. However, in the case of the ⇐⇒
operator both operands have to be evaluated to determine the result.
Note that the ⇐⇒
operator backtracks over its arguments until it finds an evaluation that is true
, unless there is none. Variable bindings that are the effect of matching operators in its arguments are not visible outside the scope of the ⇐⇒
.
rascal>import IO;
ok
rascal>false <==> false;
bool: true
rascal>false <==> true;
bool: false
We should add a more meaningful example of backtracking over ⇐⇒ than this old one: (i ← [1,2]) ⇐⇒ (j ← [1,2,3]); for i ← [1,2]) ⇐⇒ (j ← [1,2,3] println("true!"); (i ← [1,2] && (i % 2 == 0)) ⇐⇒ (j ← [1,2,3] && (j % 3 == 0)) for i ← [1,2] && (i % 2 == 0 ⇐⇒ (j ← [1,2,3] && (j % 3 == 0))) println("true!"); 
Boolean IfDefinedElse
Test whether expression has a defined value, otherwise provide alternative.
Exp_{1} ? Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ? Exp_{2} 




If no exception is generated during the evaluation of Exp_{1}, the result of Exp_{1} ? Exp_{2}
is the value of Exp_{1}.
Otherwise, it is the value of Exp_{2}.
Also see [Boolean isDefined] and Assignment.
This test can, for instance, be used to handle the case that a certain key value is not in a map:
rascal>T = ("a" : 1, "b" : 2);
map[str, int]: ("a":1,"b":2)
Trying to access the key "c"
will result in an error:
rascal>T["c"];
prompt:///(2,3,<1,2>,<1,5>): NoSuchKey("c")
at $shell$(prompt:///(0,7,<1,0>,<1,7>))
ok
Using the ?
operator, we can write:
rascal>T["c"] ? 0;
int: 0
This is very useful, if we want to modify the associated value, but are not sure whether it exists:
rascal>T["c"] ? 0 += 1;
map[str, int]: ("a":1,"b":2,"c":1)
Another example using a list:
rascal>L = [10, 20, 30];
list[int]: [10,20,30]
rascal>L[4] ? 0;
int: 0
It is, however, not possible to assign to index positions outside the list.
Boolean Implication
The implication operator on Boolean values.
Exp_{1} =⇒ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} =⇒ Exp_{2} 




The implication operator on Boolean values defined as follows:
Exp_{1} 
Exp_{2} 
Exp_{1} =⇒ Exp_{2} 













Boolean operators have short circuit semantics: only those operands are evaluated that are needed to compute the result. In the case of the =⇒
operator, the result is true
if Exp_{1}
evaluates to false
, otherwise Exp_{2}
is evaluated to determine the result.
rascal>false ==> true;
bool: true
Boolean IsDefined
Test whether the value of an expression is defined.
Exp ?
Exp 
Exp ? 



If no exception is generated during the evaluation of Exp,
the result is true
. Otherwise, it is false
.
rascal>T = ("a" : 1, "b" : 2);
map[str, int]: ("a":1,"b":2)
rascal>T["b"]?
bool: true
rascal>T["c"]?
bool: false
rascal>L = [10, 20, 30];
list[int]: [10,20,30]
rascal>L[1]?
bool: true
rascal>L[5]?
bool: false
Boolean Match
Match a pattern against an expression.
Pat := Exp
Pat 
Exp 
Pat := Exp 



See [Pattern Matching] for an introduction to pattern matching and Patterns for a complete description.
rascal>123 := 456;
bool: false
rascal>[10, *n, 50] := [10, 20, 30, 40, 50];
bool: true
rascal>{10, *int n, 50} := {50, 40, 30, 30, 10};
bool: true
Boolean Negation
The not operator on Boolean values.
! Exp
Exp 
! Exp 



The not operator on Boolean values defined as follows:
Exp 
! Exp 





rascal>!true;
bool: false
Boolean NoMatch
Negated [Boolean Match] operator.
Pat !:= Exp
Pat 
Exp 
Pat !:= Exp 

[Patterns] 


See [Pattern Matching] for an introduction to pattern matching and Patterns for a complete description.
rascal>123 !:= 456;
bool: true
rascal>[10, *n, 50] !:= [10, 20, 30, 40];
bool: true
rascal>{10, *n, 50} !:= {40, 30, 30, 10};
bool: true
Boolean Or
The or operator on Boolean values.
Exp_{1}  Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1}  Exp_{2} 




The or operator on Boolean values defined as follows:
Exp_{1} 
Exp_{2} 
Exp_{1}  Exp_{2} 













Boolean operators have short circuit semantics: only those operands are evaluated that are needed to compute the result. In the case of the 
operator, the result is true
if Exp_{1}
evaluates to true
, otherwise Exp_{2}
is evaluated to determine the result.
Note that 
will backtrack over its argument expressions until it can find an evaluation that is true
, unless there is none.
Variable assignments as a result of matching or generator expressions under a 
are visible outside the context of the operator, but only if the context is conditional, such as an ifthenelse or a for loop. Note that it is statically required that both sides of an 
introduce the same variable names of the same type.
rascal>import IO;
ok
rascal>false  true;
bool: true
rascal>(i < [1,2,3,4] && i % 2 == 0)  false
bool: true
rascal>for ((i < [1,2,3,4] && i % 2 == 0)  false)
>>>>>>> println("true for <i>");
true for 2
true for 4
list[void]: []
3.1.2. Constructor
Constructors create values for userdefined datatypes (Algebraic Datatypes).
Name ( Exp_{1}, Exp_{2}, … )
Exp_{1} 
Exp_{2} 
…  Name ( Exp_{1}, Exp_{2}, … ) 



… 
Depends on ADT declaration 
In ordinary programming languages record types or classes exist to introduce a new type name for a collection of related, named, values and to provide access to the elements of such a collection through their name.
In Rascal, algebraic data types provide this facility. They have to be declared, see Algebraic Data Type, and then values can be created using calls to the declared constructor functions. The constructor Name should correspond (regarding name, arity and argument types) to one of the alternatives in the ADT declaration.
First, the actual parameter expressions Exp_{i} are evaluated resulting in values V_{i}. Next, a data value is constructed in accordance with the declared data type using the values V_{i} as arguments for the constructor. This data value is used as value of the constructor. Constructors are functions that can be used in all contexts where functions can be used.
Observe that the syntax of a constructor is identical to the syntax of an function Call.
First, define a datatype WF
for word frequencies:
rascal>data WF = wf(str word, int freq);
ok
Then construct a new WF
value by calling the constructor wf
with appropriate arguments:
rascal>wf("Rascal", 10000);
WF: wf("Rascal",10000)
3.1.3. DateTime
Date and time values.

$
Date
$

$
Time
$

$
DateTime
$
datetime
Date, time, and datetime values are represented by the datetime
type.
datetime
literals start with a $
and are made up of either a date, given in year, month, day of month order;
a time, preceded by T
and given in hour, minute, second, millisecond, (optional) timezone offset order;
or a datetime, which is a date and a time, in the orders given above, and separated by a T
.
The following fields provide access to information about the value, but cannot be set:

isDate
: returnstrue
if the value is a date value,false
if the value is a datetime or time value. 
isTime
: returnstrue
if the value is a time value,false
if the value is a date or datetime value. 
isDateTime
: returnstrue
if the value is a datetime value,false
if the value is a date or time value. 
justTime
: returns the date component of a date or datetime value. 
justDate
: returns the time component of a time or datetime value. 
century
: returns the century component of a year for date or datetime values.
The following fields provide access to the individual components of date, time and datetime values, and can be accessed using DateTime Field Selection and be assigned using DateTime Field Selection:

year

month

day

hour

minute

second

millisecond

timezoneOffsetHours

timezoneOffsetMinutes
Not all fields are available on all values as indicated by the following table:
Field  date 
datetime 
time 


x 
x 


x 
x 


x 
x 


x 
x 


x 
x 


x 
x 


x 
x 


x 
x 


x 
x 
The isDate
, isTime
, and isDateTime
fields can be checked in advance to determine what
kind of value is stored in a variable of type datetime
.
The following operators are defined for DateTime:

DateTime Equal: Equality on datetime values.

DateTime Field Selection: Select a field from a datetime value.

DateTime GreaterThan: Greater than operator on datetime values.

DateTime GreaterThanOrEqual: Greater than or equal operator on datetime values.

DateTime LessThan: Less than operator on datetime values.

DateTime LessThanOrEqual: Less than or equal operator on datetime values.

DateTime NotEqual: Not equal operator on datetime values.
The following functions are defined for DateTime:

DateTime Equal: Equality on datetime values.

DateTime Field Selection: Select a field from a datetime value.

DateTime GreaterThan: Greater than operator on datetime values.

DateTime GreaterThanOrEqual: Greater than or equal operator on datetime values.

DateTime LessThan: Less than operator on datetime values.

DateTime LessThanOrEqual: Less than or equal operator on datetime values.

DateTime NotEqual: Not equal operator on datetime values.
There are also library functions available for DateTime.
Examples of datetime
values are:
rascal>$20100715$
datetime: $20100715$
rascal>$T07:15:23.123+0100$;
prompt:///(0,20,<1,0>,<1,20>): Invalid datetime input: Error reading time, expected ':', found: 49
Advice: http://tutor.rascalmpl.org/Errors/Static/DateTimeSyntax/DateTimeSyntax.html
ok
WARNING: unexpected errors in the above SHELL example. Documentation author please fix! Now introduce a datetime
value and assign it to DT
.
rascal>DT = $20100715T09:15:23.123+03:00$;
datetime: $20100715T09:15:23.123+03:00$
Here are examples of some datatime
fields:
rascal>DT.isDateTime;
bool: true
rascal>DT.justDate;
datetime: $20100715$
rascal>DT.justTime;
datetime: $T09:15:23.123+03:00$
rascal>DT.century;
int: 20
In normal parlance, the year 2010 is in the 21th century.
The century
field, however, just returns the century component of a given year, e.g., for 2010 this is 20.
DateTime Equal
Equality on datetime values.
Exp_{1} == Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} == Exp_{2} 




Yields true
if both arguments are identical datetime
values and false
otherwise.
rascal>$20100715$ == $20100715$;
bool: true
rascal>$20100715$ == $20100714$;
bool: false
DateTime Field Selection
Select a field from a datetime value.
Exp . Name
Exp 
Name 
Exp . Name 


depends on field 
Field selection applies to datetime
values.
Name should be one of the supported fields listed in DateTime and returns the value of that field.
Name stands for itself and is not evaluated.
DateTime GreaterThan
Greater than operator on datetime values.
Exp_{1} > Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} > Exp_{2} 




Yields true
if the datetime
value of Exp_{1} is later in time than the datetime
value
of Exp_{2}, and false
otherwise.
rascal>$20100715$ > $20100714$;
bool: true
rascal>$20110715$ > $20100715$;
bool: true
DateTime GreaterThanOrEqual
Greater than or equal operator on datetime values.
Exp_{1} >= Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} >= Exp_{2} 




Yields true
if the datetime
value of Exp_{1} is later in time than the datetime
value
of Exp_{2} or if both values are equal, and false
otherwise.
rascal>$20110715$ >= $20100715$;
bool: true
rascal>$20100715$ >= $20100714$;
bool: true
DateTime LessThan
Less than operator on datetime values.
Exp_{1} < Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} < Exp_{2} 




Yields true
if the datetime
value of Exp_{1} is earlier in time than the datetime
value
of Exp_{2}, and false
otherwise.
rascal>$20100714$ < $20100715$;
bool: true
rascal>$20110715$ < $20100714$;
bool: false
DateTime LessThanOrEqual
Less than or equal operator on datetime values.
Exp_{1} ⇐ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐ Exp_{2} 




Yields true
if the datetime
value of Exp_{1} is earlier in time than the datetime
value
of Exp_{2} or if the values of Exp_{1} and Exp_{2} are equal, and false
otherwise.
rascal>$20100715$ <= $20100715$;
bool: true
rascal>$20110715$ <= $20100714$;
bool: false
DateTime NotEqual
Not equal operator on datetime values.
Exp_{1} != Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} != Exp_{2} 




Yields true
if both arguments are different datetime
values and false
otherwise.
rascal>$20100715$ != $20100714$;
bool: true
rascal>$20100715$ != $20100715$;
bool: false
3.1.4. Integer
Integer values.
sequence of digits of arbitrary length.
int
The integer values are represented by the type int
and are written as usual. They can be arbitrarily large.
See Number for all operations and functions on integers, reals and numbers.

12

0

123456789
3.1.5. List
List values.
[ Exp_{1}, Exp_{2}, … ]
Exp_{1} 
Exp_{2} 
…  [ Exp_{1}, Exp_{2}, … ] 



… 

A list is an ordered sequence of values and has the following properties:

All elements have the same static type.

The order of the elements matters.

A list may contain an element more than once.
The type of a list has the form list[T]
,
where T
is an arbitrary type.
When a value or variable of type list occurs inside a list, that list value is inserted as list element.
To achieve splicing of these elements, i.e., the insertion of the elements of the list value rather than the whole list,
it has to be prefixed by the splice operator *
.
The following operators are provided on list:

List Append: Append an element at the end of a list.

List Comprehension: A list comprehension generates a list value.

List Concatenation: Concatenate two lists.

List Difference: The difference between two lists.

List Equal: Equality on lists.

List Insert: add an element in front of a list.

List Intersection: Intersection of two lists.

List NotEqual: Not equal operator on lists.

List Product: Compute the product of two lists.

List Slice: Retrieve a slice of a list.

List Splice: Splice the elements of a list in an enclosing list.

List StrictSubList: The strict sublist operator on lists.

List StrictSuperList: The strict super list operator on lists.

List SubList: The sublist operator on lists.

List Subscription: Retrieve a list element via its index.

List SuperList: The super list operator on lists.

List in: Membership test on list elements.

List notin: Negated membership test on lists.
There are also library functions available for List.
rascal>[1, 2, 3];
list[int]: [1,2,3]
rascal>[<1,10>, <2,20>, <3,30>];
lrel[int,int]: [
<1,10>,
<2,20>,
<3,30>
]
rascal>[1, "b", 3];
list[value]: [1,"b",3]
rascal>[<"a",10>, <"b",20>, <"c",30>];
lrel[str,int]: [
<"a",10>,
<"b",20>,
<"c",30>
]
rascal>[["a", "b"], ["c", "d", "e"]];
list[list[str]]: [
["a","b"],
["c","d","e"]
]
List splicing works as follows: by prefixing L
by the splice operator, its elements are included as elements in the enclosing list:
rascal>L = [1, 2, 3];
list[int]: [1,2,3]
rascal>[10, L, 20];
list[value]: [
10,
[1,2,3],
20
]
rascal>[10, *L, 20];
list[int]: [10,1,2,3,20]
List Append
Append an element at the end of a list
Exp_{1} 
Exp_{2} 
Exp_{1} + Exp_{2} 




The operator +
appends an element at the end of a list. The +
is one of those Operators which are overloaded. It can also mean List Insert or List Concatenation for example.
rascal>[] + 1;
list[int]: [1]
rascal>[1] + 2;
list[int]: [1,2]

If both operands of
+
are a list, then it acts as List Concatenation
This is concatenation:
rascal>[1] + [2]
list[int]: [1,2]
To append a list to a list, use extra brackets:
rascal>[1] + [[2]]
list[value]: [
1,
[2]
]
List Comprehension
A list comprehension generates a list value.
[ Exp_{1}, Exp_{2}, …  Gen_{1}, Gen_{2}, … ]
Exp_{1} 
Exp_{2} 
…  [ Exp_{1}, Exp_{2}, …  Gen_{1}, Gen_{2}, … ] 



… 

A list comprehension consists of a number of contributing expressions Exp_{1}, Exp_{2}, … and a number of generators Gen_{1}, Gen_{2}, Gen_{3}, … that are evaluated as described in Comprehensions.
Computing a list of squares of the numbers from 0 to 10 that are divisible by 3:
rascal>[n * n  int n < [0 .. 10], n % 3 == 0];
list[int]: [0,9,36,81]
But we can also include the relevant n
in the resulting list:
rascal>[n, n * n  int n < [0 .. 10], n % 3 == 0];
list[int]: [0,0,3,9,6,36,9,81]
List Concatenation
Concatenate two lists.
Exp_{1} + Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} + Exp_{2} 




The +
operator concatenates the elements of the two lists in order of appearance.
Note that the same operator is overloaded for List Insert and List Append.
rascal>[1, 2, 3] + [4, 5, 6];
list[int]: [1,2,3,4,5,6]
rascal>[] + [1]
list[int]: [1]
rascal>[1] + []
list[int]: [1]
rascal>[1] + [2] + [3]
list[int]: [1,2,3]
And overloaded usage for insert and append looks like:
rascal>1 + []
list[int]: [1]
rascal>[] + 1
list[int]: [1]
List Difference
The difference between two lists.
Exp_{1}  Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1}  Exp_{2} 







If both Exp_{1} and Exp_{2} have a list as value, the result is the difference of these two list values. If Exp_{2} does not have a list as value, it is first converted to a list before the difference is computed. The difference is computed by taking the successive elements of the second list and removing the first occurrence of that element in the first list.
rascal>[1, 2, 3, 4]  [1, 2, 3];
list[int]: [4]
rascal>[1, 2, 3, 4]  [3];
list[int]: [1,2,4]
rascal>[1, 2, 3, 4]  3;
list[int]: [1,2,4]
rascal>[1, 2, 3, 4]  [5, 6, 7];
list[int]: [1,2,3,4]
rascal>[1, 2, 3, 1, 2, 3]  [1];
list[int]: [2,3,1,2,3]
rascal>[1, 2, 3, 1, 2, 3]  [1, 2];
list[int]: [3,1,2,3]
List Equal
Equality on lists.
Exp_{1} == Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} == Exp_{2} 




Yields true
if both arguments are equal lists and false
otherwise.
rascal>[1, 2, 3] == [1, 2, 3];
bool: true
rascal>[1, 2, 3] == [3, 2, 1];
bool: false
List Insert
add an element in front of a list
Exp_{1} 
Exp_{2} 
Exp_{1} + Exp_{2} 




The +
operator can insert an element in front of a list. Note that +
is one of the Operators that is overloaded, it is also List Concatenation and List Append for example.
rascal>1 + []
list[int]: [1]
rascal>1 + [2]
list[int]: [1,2]
rascal>1 + [2,3]
list[int]: [1,2,3]

If the first operand before the
+
is a list,+
acts as List Concatenation and not as List Insert
This is concatenation:
rascal>[1] + [2]
list[int]: [1,2]
To insert a list as an element, use extra brackets:
rascal>[[1]] + [2]
list[value]: [
[1],
2
]
List Intersection
Intersection of two lists.
Exp_{1} & Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} & Exp_{2} 




Returns the intersection of the two list values of Exp_{1} and Exp_{2}, i.e., the list value of Exp_{1} with all elements removed that do not occur in the list value of Exp_{2}.
rascal>[1, 2, 3, 4, 5] & [4, 5, 6];
list[int]: [4,5]
List NotEqual
Not equal operator on lists.
Exp_{1} != Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} != Exp_{2} 




Yields true
if both arguments are unequal lists and false
otherwise.
rascal>[1, 2, 3] != [3, 2, 1];
bool: true
rascal>[1, 2, 3] != [1, 2, 3];
bool: false
List Product
Compute the product of two lists.
Exp_{1} * Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} * Exp_{2} 




Yields a list of tuples resulting from the product of the values of Exp_{1} and Exp_{2}. It contains a tuple for each combination of values from both arguments.
rascal>[1, 2, 3] * [4, 5, 6];
lrel[int,int]: [
<1,4>,
<1,5>,
<1,6>,
<2,4>,
<2,5>,
<2,6>,
<3,4>,
<3,5>,
<3,6>
]
Here is a concise way to create a deck of cards:
rascal>["clubs", "hearts", "diamonds", "spades"] * [1 .. 13];
lrel[str,int]: [
<"clubs",1>,
<"clubs",2>,
<"clubs",3>,
<"clubs",4>,
<"clubs",5>,
<"clubs",6>,
<"clubs",7>,
<"clubs",8>,
<"clubs",9>,
<"clubs",10>,
<"clubs",11>,
<"clubs",12>,
<"hearts",1>,
<"hearts",2>,
<"hearts",3>,
<"hearts",4>,
<"hearts",5>,
<"hearts",6>,
<"hearts",7>,
<"hearts",8>,
<"hearts",9>,
<"hearts",10>,
<"hearts",11>,
<"hearts",12>,
<"diamonds",1>,
<"diamonds",2>,
<"diamonds",3>,
<"diamonds",4>,
<"diamonds",5>,
<"diamonds",6>,
<"diamonds",7>,
<"diamonds",8>,
<"diamonds",9>,
<"diamonds",10>,
<"diamonds",11>,
<"diamonds",12>,
<"spades",1>,
<"spades",2>,
<"spades",3>,
<"spades",4>,
<"spades",5>,
<"spades",6>,
<"spades",7>,
<"spades",8>,
<"spades",9>,
<"spades",10>,
<"spades",11>,
<"spades",12>
]
List Slice
Retrieve a slice of a list.

Exp_{1} [ Exp_{2} .. Exp_{4}]

Exp_{1} [ Exp_{2} , Exp_{3} .. Exp_{4}]
where Exp_{2} and Exp_{4} are optional.
Exp_{1} 
Exp_{2} 
Exp_{3} 
Exp_{4} 





List slicing uses the integer values of Exp_{2} and Exp_{4} to determine the begin
(inclusive) and end
(exclusive)
of a slice from the list value L of Exp_{1}. Negative indices count from the end of the list backwards.
Using the second form, an extra index Exp_{3} is given that determines the
index of the second element in the slice and establishes the step
between
successive elements in the slice. The default step
is 1.
If end
is smaller than begin
, the slice is constructed backwards.
Let Len
be the length of L and let N_{2}, N_{3} and N_{4} be the respective values of the expressions
Exp_{2}, Exp_{2} and Exp_{2} when they are present.
The slice parameters begin
, end
, and step
are determined as follows:

Exp_{2}:

If Exp_{2} is absent, then
begin = 0
. 
Otherwise, if N_{2} >= 0 then
begin = N_{2}
elsebegin = N_{2} + Len
.


Exp_{4}:

If Exp_{4} is absent, then
end = Len
. 
Otherwise, if N_{4} >= 0, then
end = N_{4}
elseend = N_{4} + Len
.


Exp_{3}:

If Exp_{3} is absent, then if
begin < end
thenstep = 1
elsestep = 1
. 
Otherwise, if
begin < end
, thenstep = N_{3}  begin
elsestep = begin  N_{3}
.

Now, the constraints 0 ⇐ begin < Len
and 0 < end < Len
should hold,
otherwise the exception IndexOutOfBounds
is thrown.
The slice consists of the elements L[begin]
, L[begin+step]
, L[end  step]
.
When begin >= end
, the elements are listed in reverse order.
Consider the list L = [0, 10, 20, 30, 40, 50, 60, 70, 80];
as running example.
Here is a view on L that will help to correlate positive and negative indices:
i 
0  1  2  3  4  5  6  7  8 


0 
10 
20 
30 
40 
50 
60 
70 
80 

9 
8 
7 
6 
5 
4 
3 
2 
1 
Some common use cases (with begin
⇐ end
):
Slice  Means: 


elements with indices 

elements with indices 

elements with indices from the beginning through 

the whole list 

last element of the list 

the last two elements of the list 

all elements except the last two. 
Let’s put this into practice now.
rascal>L = [0, 10, 20, 30, 40, 50, 60, 70, 80];
list[int]: [0,10,20,30,40,50,60,70,80]
Slices with begin < end
rascal>L[1..3];
list[int]: [10,20]
rascal>L[1..]; // empty end => end of list
list[int]: [10,20,30,40,50,60,70,80]
rascal>L[..3]; // empty begin => first element of list
list[int]: [0,10,20]
rascal>L[..]; // both empty => whole list
list[int]: [0,10,20,30,40,50,60,70,80]
Slices with begin >= end
rascal>L[3..1]; // slice contains elements with indices 3 and 2 (in that order)
list[int]: [30,20]
rascal>L[3..3]; // empty slice when begin == end
list[int]: []
Slices with negative begin or end:
rascal>L[2..2]; // equivalent to L[2..7]
list[int]: [20,30,40,50,60]
rascal>L[2..7];
list[int]: [20,30,40,50,60]
rascal>L[4..2]; // equivalent to L[5..7]
list[int]: [50,60]
rascal>L[5..7];
list[int]: [50,60]
Slices with an explicit second index:
rascal>L[1,3..6];
list[int]: [10,30,50]
rascal>L[5,3..];
list[int]: [50,30,10]
Explore error cases:
rascal>L[..10];
list[int]: [0,10,20,30,40,50,60,70,80]
rascal>L[1..20];
list[int]: [10,20,30,40,50,60,70,80]
List Splice
Splice the elements of a list in an enclosing list.
Exp 
Exp_{1} 
Exp_{n} 
[Exp_{1}, …, Exp, …, Exp_{n}] 





The operator *
splices the elements of a list in an enclosing list.
Consider the following list in which the list [10, 20, 30]
occurs as list element. It has as type list[value]
:
rascal>[1, 2, [10, 20, 30], 3, 4];
list[value]: [
1,
2,
[10,20,30],
3,
4
]
The effect of splicing the same list element in the enclosing list gives a flat list of type list[int]
:
rascal>[1, 2, *[10, 20, 30], 3, 4];
list[int]: [1,2,10,20,30,3,4]
The same example can be written as:
rascal>L = [10, 20, 30];
list[int]: [10,20,30]
rascal>[1, 2, *L, 3, 4];
list[int]: [1,2,10,20,30,3,4]
in which nested lists are handled.
List StrictSubList
The strict sublist operator on lists.
Exp_{1} < Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} < Exp_{2} 




Yields true
if the value of Exp_{1} is a strict sublist of the value of Exp_{2}, and false
otherwise.
rascal>[1, 2, 3] < [1, 2, 3, 4];
bool: true
rascal>[1, 2, 3, 4] < [1, 2, 3, 4];
bool: false
rascal>[1, 3, 5] < [1, 2, 3, 4, 5]
bool: true
List StrictSuperList
The strict super list operator on lists.
Exp_{1} > Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} > Exp_{2} 




Yields true
if the value of Exp_{2} is a strict sublist of the value of Exp_{1}, and false
otherwise.
rascal>[1, 2, 3, 4] > [1, 2, 3];
bool: true
rascal>[1, 2, 3, 4] > [1, 2, 3, 4];
bool: false
rascal>[1, 2, 3, 4] > [1, 2, 3];
bool: true
rascal>[1, 2, 3, 4, 5] > [1, 3, 5]
bool: true
List SubList
The sublist operator on lists.
Exp_{1} ⇐ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐ Exp_{2} 




Yields true
if the value of Exp_{1} is equal to or a sublist of the value of Exp_{2}, and false
otherwise.
rascal>[1, 2, 3] <= [1, 2, 3, 4];
bool: true
rascal>[1, 2, 3] <= [1, 2, 3];
bool: true
rascal>[1, 3, 5] <= [1, 2, 3, 4, 5];
bool: true
List Subscription
Retrieve a list element via its index.
Exp_{1} [ Exp_{2} ]
Exp_{1} 
Exp_{2} 
Exp_{1} [ Exp_{2} ] 




List subscription uses the integer value of Exp_{2} as index in the list value of Exp_{1}.
The value of Exp_{2} should be greater or equal 0 and less than the number of elements in the list.
If this is not the case, the exception IndexOutOfBounds
is thrown.
Introduce a list, assign it to L and retrieve the element with index 1:
rascal>L = [10, 20, 30];
list[int]: [10,20,30]
rascal>L[1];
int: 20
Explore an error case:
rascal>L[5];
prompt:///(2,1,<1,2>,<1,3>): IndexOutOfBounds(5)
at $shell$(prompt:///(0,5,<1,0>,<1,5>))
ok
List SuperList
The super list operator on lists.
Exp_{1} >= Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} >= Exp_{2} 




Yields true
if the value of Exp_{2} is equal to or a sublist of the value of Exp_{1}, and false
otherwise.
rascal>[1, 2, 3, 4] >= [1, 2, 3];
bool: true
rascal>[1, 2, 3, 4] >= [1, 2, 3, 4];
bool: true
rascal>[1, 2, 3, 4] >= [1, 2, 3];
bool: true
rascal>[1, 2, 3, 4, 5] >= [1, 3, 5]
bool: true
List in
Membership test on list elements.
Exp_{1} in Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} in Exp_{2} 




Yields true
if the value of Exp_{1} occurs as element in the value of Exp_{2} and false
otherwise.
The type of Exp_{1} should be compatible with the element type of Exp_{2}.
rascal>2 in [1, 2, 3];
bool: true
rascal>4 in [1, 2, 3];
bool: false
List notin
Negated membership test on lists.
Exp_{1} notin Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} notin Exp_{2} 




Yields true
if the value of Exp_{1} does not occur as element in the value of Exp_{2} and false
otherwise.
The type of Exp_{1} should be compatible with the element type of Exp_{2}.
rascal>4 notin [1, 2, 3];
bool: true
rascal>2 notin [1, 2, 3];
bool: false
3.1.6. ListRelation
ListRelation values.
[ < Exp_{11}, Exp_{12}, … > , < Exp_{21}, Exp_{22}, … > , … ]
Exp_{11} 
Exp_{12} 
…  { < Exp_{11}, Exp_{12}, … > , … } 



… 

A list relation is a list of elements with the following property:

All elements have the same static tuple type.
ListRelations are thus nothing more than lists of tuples, but since they are used so often we provide a shorthand notation for them.
ListRelations are represented by the type lrel[T_{1} L_{1}, T_{2} L_{2}, … ]
, where T_{1}, T_{2}, … are arbitrary types and
L_{1}, L_{2}, … are optional labels. It is a shorthand for list[tuple[T_{1} L_{1}, T_{2} L_{2}, … ]]
.
An nary list relation with m tuples is denoted by
[< E_{11}, E_{12}, …, E_{1n}>,< E_{21}, E_{22}, …, E_{2n}>, …, < E_{m1}, E_{m2}, …, E_{mn}>]
,
where the E_{ij} are expressions that yield the desired element type T_{i}.
Since list relations are a form of list all operations (see List) and functions (see [PreludeList]) are also applicable to relations.
The following additional operators are provided for list relations:

ListRelation CartesianProduct: Cartesian product of two list relation values.

ListRelation Composition: Composition of two list relation values.

ListRelation FieldSelection: Select a field (column) from a list relation value.

ListRelation Join: Join two list relation values.

ListRelation Reflexive Transitive Closure: The reflexive transitive closure of a binary list relation.

ListRelation Subscription: Indexing of a list relation via tuple values.

ListRelation Transitive Closure: Transitive closure on binary list relation values.
There are also library functions available for ListRelation.
rascal>[<1,10>, <2,20>, <3,30>]
lrel[int,int]: [
<1,10>,
<2,20>,
<3,30>
]
instead of lrel[int,int] we can also give list[tuple[int,int]]
as type of the above expression
remember that these types are interchangeable.
rascal>[<"a",10>, <"b",20>, <"c",30>]
lrel[str,int]: [
<"a",10>,
<"b",20>,
<"c",30>
]
rascal>[<"a", 1, "b">, <"c", 2, "d">]
lrel[str,int,str]: [
<"a",1,"b">,
<"c",2,"d">
]
ListRelation CartesianProduct
Cartesian product of two list relation values.
Exp_{1} * Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} * Exp_{2} 




Returns a binary relation that is the Cartesian product of two lists.
rascal>[1, 2, 3] * [9];
lrel[int,int]: [
<1,9>,
<2,9>,
<3,9>
]
rascal>[1, 2, 3] * [10, 11];
lrel[int,int]: [
<1,10>,
<1,11>,
<2,10>,
<2,11>,
<3,10>,
<3,11>
]
ListRelation Composition
Composition of two list relation values.
Exp_{1} o Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} o Exp_{2} 




Returns the composition of two binary list relations.
rascal>[<1,10>, <2,20>, <3,15>] o [<10,100>, <20,200>];
lrel[int,int]: [
<1,100>,
<2,200>
]
We use the letter o
as operator and this may conflict other defined names.
ListRelation FieldSelection
Select a field (column) from a list relation value.
Exp . Name



Exp should evaluate to a list relation that has an ith field label L_{i} that is identical to Name. Return a list with all values of that field. Name stands for itself and is not evaluated.
rascal>lrel[str street, int nm] R = [<"abc", 1>, <"abc", 2>, <"def", 4>, <"def", 5>];
lrel[str street,int nm]: [
<"abc",1>,
<"abc",2>,
<"def",4>,
<"def",5>
]
rascal>R.street;
list[str]: ["abc","abc","def","def"]
ListRelation Join
Join two list relation values.
Exp_{1} join Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} join Exp_{2} 




ListRelation resulting from the natural join of the list relation values of the two arguments. This list relation contains tuples that are the result from concatenating the elements from both arguments.
rascal>[<1,2>, <10,20>] join [<2,3>];
lrel[int,int,int,int]: [
<1,2,2,3>,
<10,20,2,3>
]
rascal>[<1,2>] join [3, 4];
lrel[int,int,int]: [
<1,2,3>,
<1,2,4>
]
rascal>[<1,2>, <10,20>] join [<2,3>, <20,30>];
lrel[int,int,int,int]: [
<1,2,2,3>,
<1,2,20,30>,
<10,20,2,3>,
<10,20,20,30>
]
ListRelation Reflexive Transitive Closure
The reflexive transitive closure of a binary list relation.
Exp *
Exp 
Exp * 



Reflexive transitive closure is defined by repeated composition of a list relation. If we define for a given list relation R:

R^{0} = identity relation =
[<a, a>, <b, b>  <a, b> ← R]

R^{1} = R

R^{2} = R o R

R^{3} = R o R^{2}

…
then the reflexive transitive closure R* can be defined in two ways: (also see ListRelation Transitive Closure):

R* = R^{0} + R^{1} + R^{2} + R^{3} + …

R* = R^{0} + R+
rascal>[<1,2>, <2,3>, <3,4>]*;
lrel[int,int]: [
<1,2>,
<2,3>,
<3,4>,
<1,3>,
<2,4>,
<1,4>,
<4,4>,
<3,3>,
<2,2>,
<1,1>
]
ListRelation Subscription
Indexing of a list relation via tuple values.

Exp_{0} [ Exp_{1}, Exp_{2}, … Exp_{n}]

Exp_{0} [ Exp_{1}]
Variant 1
Exp_{0} 
Exp_{1} 
Exp_{2} 
…  Exp_{0} [ Exp_{1}, Exp_{2}, … ] 




… 

Variant 2





ListRelation resulting from subscription of a ListRelation Exp_{0}.
Variant 1
Subscription with the index values of Exp_{1}, Exp_{2}, ….
The result is a ListRelation with all tuples that have these index values as first elements
with the index values removed from the tuple.
If the resulting tuple has only a single element, a list is returned instead of a relation.
A wildcard _
as index value matches all possible values at that index position.
Variant 2
Subscription with a set of the index values of Exp_{1}. The result is a ListRelation with all tuples that have these index values as first element with the index values removed from the tuple.
rascal>R = [<1,10>, <2,20>, <1,11>, <3,30>, <2,21>];
lrel[int,int]: [
<1,10>,
<2,20>,
<1,11>,
<3,30>,
<2,21>
]
rascal>R[1];
tuple[int,int]: <2,20>
rascal>R[{1}];
list[int]: [10,11]
rascal>R[{1, 2}];
list[int]: [10,20,11,21]
rascal>RR = [<1,10,100>,<1,11,101>,<2,20,200>,<2,22,202>,
>>>>>>> <3,30,300>];
lrel[int,int,int]: [
<1,10,100>,
<1,11,101>,
<2,20,200>,
<2,22,202>,
<3,30,300>
]
rascal>RR[1];
tuple[int,int,int]: <1,11,101>
rascal>RR[1,_];
list[int]: [100,101]
Introduce a relation with economic data and assign it to GDP
:
rascal>lrel[str country, int year, int amount] GDP =
>>>>>>>[<"US", 2008, 14264600>, <"EU", 2008, 18394115>,
>>>>>>> <"Japan", 2008, 4923761>, <"US", 2007, 13811200>,
>>>>>>> <"EU", 2007, 13811200>, <"Japan", 2007, 4376705>];
lrel[str country,int year,int amount]: [
<"US",2008,14264600>,
<"EU",2008,18394115>,
<"Japan",2008,4923761>,
<"US",2007,13811200>,
<"EU",2007,13811200>,
<"Japan",2007,4376705>
]
and then retrieve the information for the index "Japan"
:
rascal>GDP["Japan"];
lrel[int,int]: [
<2008,4923761>,
<2007,4376705>
]
or rather for the indices "Japan"
and 2008
:
rascal>GDP["Japan", 2008];
list[int]: [4923761]
ListRelation Transitive Closure
Transitive closure on binary list relation values.
Exp +
Exp 
Exp + 



Returns the transitive closure of a binary listrelation. Transitive closure is defined by repeated composition of a relation. If we define for a given relation R:

R^{1} = R

R^{2} = R o R

R^{3} = R o R^{2}

…
then the transitive closure R+ can be defined as

R+ = R^{1} + R^{2} + R^{3} + …
rascal>[<1,2>, <2,3>, <3,4>]+;
lrel[int,int]: [
<1,2>,
<2,3>,
<3,4>,
<1,3>,
<2,4>,
<1,4>
]
3.1.7. Location
(Source code) location values.
 Uri  ( O, L, < BL, BC > , < EL,EC > )
where:

Uri is an arbitrary Uniform Resource Identifier (URI).

O and L are integer expressions giving the offset of this location to the begin of file, respectively, its length.

BL and BC are integers expressions giving the begin line and begin column.

EL and EC are integers expressions giving the end line and end column.
The part following the second pipe symbol (
) is optional.
loc
Location values are represented by the type loc
and serve the following purposes:

Providing a uniform mechanism for accessing local or remote files. This is used in all IOrelated library functions.

If the optional part is present they serve as text coordinates in a specific local or remote source file. This is very handy to associate a source code location which extracted facts.
URIs are explained in Uniform Resource Identifier. From their original definition in RFC3986 we cite the following useful overview of an URI:
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
    
scheme authority path query fragment
 _______________________
/ \ / \
urn:example:animal:ferret:nose
The elements of a location value can be accessed and modified using the standard mechanism of field selection and field assignment. The corresponding field names are:

top
: the URI of the location without precise positioning information (offset, length, begin, end). 
uri
: the URI of the location as a string. Also subfields of the URI can be accessed:
scheme
: the scheme (or protocol) to be used; 
authority
: the domain where the data are located, as astr
; 
host
: the host where the URI is hosted (part of authority), as astr
; 
port
: port on host (part of authority), as aint
; 
path
: path name of file on host, as astr
; 
extension
: file name extension, as astr
; 
query
: query data, as astr
; 
fragment
: the fragment name following the path name and query data, as astr
; 
user
: user info (only present in schemes like mailto), as astr
; 
parent
: removes the last segment from the path component, if any, as aloc
; 
file
: the last segment of the path, as astr
; 
ls
: the contents of a directory, if the loc is a directory, as alist[loc]
.


offset
: start of text area. 
length
: length of text area. 
begin.line
,begin.column
: begin line and column of text area. 
end.line
,end.column
end line and column of text area.
Supported protocols are:
Scheme name and pattern  Description 


access a remote file via the web. 

access a local file on the file system. 

access the current working directory (the directory from which Rascal was started). 

access the home directory of the user. 

access the Rascal standard library. 

access the temporay file directory. 

access any entry in a zip file (or a jar) 

access the source code of a Rascal module name 

access a project in the current instance of Eclipse. 

access OSGI bundles. Only active in Eclipse context 
Locations with specific position information should always be generated automatically but for the curious here is an example:
rascal>file:///home/paulk/pico.trm(0,1,<2,3>,<4,5>)
loc: file:///home/paulk/pico.trm(0,1,<2,3>,<4,5>)
Note that this is equivalent to using the home
scheme:
rascal>home://pico.trm(0,1,<2,3>,<4,5>)
loc: home://pico.trm(0,1,<2,3>,<4,5>)
You could read a webpage:
rascal>import IO;
ok
rascal>println(readFile(http://www.example.org))
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf8" />
<meta httpequiv="Contenttype" content="text/html; charset=utf8" />
<meta name="viewport" content="width=devicewidth, initialscale=1" />
<style type="text/css">
body {
backgroundcolor: #f0f0f2;
margin: 0;
padding: 0;
fontfamily: applesystem, systemui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sansserif;
}
div {
width: 600px;
margin: 5em auto;
padding: 2em;
backgroundcolor: #fdfdff;
borderradius: 0.5em;
boxshadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
}
a:link, a:visited {
color: #38488f;
textdecoration: none;
}
@media (maxwidth: 700px) {
div {
margin: 0 auto;
width: auto;
}
}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information…</a></p>
</div>
</body>
</html>
ok
Addition on locations creates longer paths:
rascal>x = tmp://myTempDirectory;
loc: tmp://myTempDirectory
rascal>x += "myTempFile.txt";
loc: tmp://myTempDirectory/myTempFile.txt
Location AddSegment
Locations can be concatenated with strings to add segments to the path component
Loc + Str
Loc 
Str 
Loc + Str 




Adds a segment to the path component of a location.
This concatenation introduces a path separator (/
) automatically.
rascal>tmp:///myDir + "myFile";
loc: tmp:///myDir/myFile
To get the original back, you can use the parent
field:
rascal>(tmp:///myDir + "myFile").parent
loc: tmp:///myDir
Location Equal
Equality operator on locations.
Exp_{1} == Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} == Exp_{2} 




Yields true
if both arguments are identical and false
otherwise.
Location FieldSelection
Field selection on locations.
Exp . Name
Exp 
Name 
Exp . Name 


Depends on field 
Field selection applies to locations. Name should be one of the supported fields listed in Location and returns the value of that field. Name stands for itself and is not evaluated.
Location GreaterThan
The greater than operator on location values.
Exp_{1} > Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} > Exp_{2} 




Yields true
if the location value of Exp_{1} strictly textually encloses
the location value of Exp_{2}, and false
otherwise.
Location GreaterThanOrEqual
The greater than or equal operator on location values.
Exp_{1} >= Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} >= Exp_{2} 




Yields true
if the location value of Exp_{1} textually encloses
the location value of Exp_{2}, and false
otherwise.
Location LessThan
The less than operator on location values.
Exp_{1} < Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} < Exp_{2} 




Yields true
if the location value of Exp_{1} is strictly textually contained
in the location value of Exp_{2}, and false
otherwise.
Location LessThanOrEqual
The less than or equal operator on location values.
Exp_{1} ⇐ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐ Exp_{2} 




Yields true
if the location value of Exp_{1} is textually contained
in the location value of Exp_{2}, and false
otherwise.
NotEqual
The not equal operator on location values.
Exp_{1} != Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} != Exp_{2} 




Yields true
if both arguments are not identical and false
otherwise.
3.1.8. Map
Map values.
( KeyExp_{1} : ValExp_{1}, KeyExp_{2} : ValExp_{2}, … )
KeyExp_{1} 
ValExp_{1} 
KeyExp_{2} 
ValExp_{2} 
…  ( KeyExp_{1} : ValExp_{1}, KeyExp_{2} : ValExp_{2}, … ) 





… 

A map is a set of key/value pairs and has the following properties:

Key and value may have different static types.

A key can only occur once.
Maps resemble functions rather than relations in the sense that only a single value can be associated with each key.
The following functions are provided for maps:

Map Composition: Composition of two map values.

Map Comprehension: A map comprehension generates a map value.

Map Difference: The difference between two maps.

Map Equal: Equality operator on maps.

Map Intersection: Intersection of two maps.

Map NotEqual: Not equal operator on map values.

Map StrictSubMap: Strict submap operator on map values.

Map StrictSuperMap: Strict supermap operator on map values.

Map SubMap: Submap operator on map values.

Map Subscription: Retrieve a value by its key in map.

Map SuperMap: Supermap operator on map values.

Map Union: Union of two maps.

Map in: Membership test on the keys of a map.

Map notin: Negated membership test on the keys of a map.
rascal>("pear" : 1, "apple" : 3, "banana" : 0);
map[str, int]: ("banana":0,"pear":1,"apple":3)
Map Composition
Composition of two map values.
Exp_{1} o Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} o Exp_{2} 




Returns the composition of two maps.
rascal>import Map;
ok
rascal>("one" : 1, "two" : 2) o (1 : 10, 2 : 20);
map[str, int]: ("one":10,"two":20)
We use the letter o
as operator and this may conflict other defined names.
Map Comprehension
A map comprehension generates a map value.
( Exp_{1} : Exp_{2}  Gen_{1}, Gen_{2}, … )
Exp_{1} 
Exp_{2} 
( Exp_{1} : Exp_{2}  Gen_{1}, Gen_{2}, … ) 




A map comprehension consists of a number of two contributing expressions Exp_{1} (for key values), and Exp_{2} (the values associated with those key values) and a number of generators Gen_{1}, Gen_{2}, Gen_{3}, … that are evaluated as described in Comprehensions.
Introduce a map of fruits
:
rascal>fruits = ("pear" : 1, "apple" : 3, "banana" : 0, "berry" : 25, "orange": 35);
map[str, int]: ("banana":0,"pear":1,"orange":35,"berry":25,"apple":3)
rascal>import String;
ok
Use a map comprehension to filter fruits with a name of at most 5 characters:
rascal>(fruit : fruits[fruit]  fruit < fruits, size(fruit) <= 5);
map[str, int]: ("pear":1,"berry":25,"apple":3)
Use a map comprehension to filter fruits with an associated value larger than 10:
rascal>(fruit : fruits[fruit]  fruit < fruits, fruits[fruit] > 10);
map[str, int]: ("orange":35,"berry":25)
Map Difference
The difference between two maps.
Exp_{1}  Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1}  Exp_{2} 




The result is the difference of the two map values of Exp_{1} and Exp_{2}, i.e. a map with all pairs in Exp_{1} that do have a key that does not occur in Exp_{2}.
rascal>("apple": 1, "pear": 2)  ("banana": 3, "apple": 4);
map[str, int]: ("pear":2)
Map Equal
Equality operator on maps.
Exp_{1} == Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} == Exp_{2} 




Yields true
if both arguments contain the same key/value pairs, and false
otherwise.
rascal>("apple": 1, "pear": 2) == ("pear": 2, "apple": 1);
bool: true
rascal>("apple": 1, "pear": 2) == ("apple": 1, "banana": 3)
bool: false
Map Intersection
Intersection of two maps.
Exp_{1} & Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} & Exp_{2} 




Returns the intersection of the two map values of Exp_{1} and Exp_{2}, i.e., a map that contains the key/value pairs that occur in both maps.
rascal>("apple": 1, "pear": 2) & ("banana": 3, "apple": 1);
map[str, int]: ("apple":1)
rascal>("apple": 1, "pear": 2) & ("banana": 3, "apple": 4);
map[str, int]: ()
Map NotEqual
Not equal operator on map values.
Exp_{1} != Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} != Exp_{2} 




Yields true
if both arguments contain different key/value pairs, and false
otherwise.
rascal>("apple": 1, "pear": 2) != ("apple": 1, "banana": 3);
bool: true
rascal>("apple": 1, "pear": 2) != ("pear": 2, "apple": 1);
bool: false
Map StrictSubMap
Strict submap operator on map values.
Exp_{1} < Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} < Exp_{2} 




Yields true
if all key/value pairs in the map value of Exp_{1} occur in the map value Exp_{2}
and the values of Exp_{1} and EXp_{2} are not equal, and false
otherwise.
rascal>("apple": 1, "pear": 2) < ("pear": 2, "apple": 1, "banana" : 3);
bool: true
rascal>("apple": 1, "pear": 2) < ("apple": 1, "banana" : 3);
bool: false
Map StrictSuperMap
Strict supermap operator on map values.
Exp_{1} > Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} > Exp_{2} 




Yields true
if all key/value pairs in the map value of Exp_{2} occur in the map value Exp_{1}
and the values of Exp_{1} and EXp_{2} are not equal, and false
otherwise.
rascal>("pear": 2, "apple": 1, "banana" : 3) > ("apple": 1, "pear": 2);
bool: true
rascal>("apple": 1, "banana" : 3) > ("apple": 1, "pear": 2);
bool: false
Map SubMap
Submap operator on map values.
Exp_{1} ⇐ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐ Exp_{2} 




Yields true
if all key/value pairs in the map value of Exp_{1} occur in the map value Exp_{2}
or the values of Exp_{1} and Exp_{2} are equal, and false
otherwise.
rascal>("apple": 1, "pear": 2) <= ("pear": 2, "apple": 1);
bool: true
rascal>("apple": 1, "pear": 2) <= ("pear": 2, "apple": 1, "banana" : 3);
bool: true
rascal>("apple": 1, "pear": 2) <= ("apple": 1, "banana" : 3);
bool: false
Map Subscription
Retrieve a value by its key in map.
Exp_{1} [ Exp_{2} ]
Exp_{1} 
Exp_{2} 
Exp_{1} [ Exp_{2} ] 




Map subscription uses the value of Exp_{2} as key in the map value of Exp_{1} and returns the associated value.
If this key does not occur in the map, the exception NoSuchKey
is thrown.
Introduce a map, assign it to colors
, and retrieve the element with index "trumps"
:
rascal>colors = ("hearts":"red", "clover":"black",
>>>>>>> "trumps":"black", "clubs":"red");
map[str, str]: ("hearts":"red","trumps":"black","clover":"black","clubs":"red")
rascal>colors["trumps"];
str: "black"
Explore some erroneous subscription expressions:
rascal>colors[0];
prompt:///(7,1,<1,7>,<1,8>): Expected str, but got int
Advice: http://tutor.rascalmpl.org/Errors/Static/UnexpectedType/UnexpectedType.html
ok
rascal>colors["square"];
prompt:///(7,8,<1,7>,<1,15>): NoSuchKey("square")
at $shell$(prompt:///(0,17,<1,0>,<1,17>))
ok
Map SuperMap
Supermap operator on map values.
Exp_{1} >= Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} >= Exp_{2} 




Yields true
if all key/value pairs in the map value of Exp_{2} occur in the map value Exp_{1}
or the values of Exp_{1} and Exp_{2} are equal, and false
otherwise.
rascal>("pear": 2, "apple": 1) >= ("apple": 1, "pear": 2);
bool: true
rascal>("pear": 2, "apple": 1, "banana" : 3) >= ("apple": 1, "pear": 2);
bool: true
rascal>("apple": 1, "banana" : 3) >= ("apple": 1, "pear": 2);
bool: false
Map Union
Union of two maps.
Exp_{1} + Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} + Exp_{2} 




The result is the union of the two map values of Exp_{1} and Exp_{2}. If they have a pair with the same key in common, that key will be associated in the union with the value associated with that key in Exp_{2}.
rascal>("apple": 1, "pear": 2) + ("banana": 3, "kiwi": 4);
map[str, int]: ("banana":3,"pear":2,"kiwi":4,"apple":1)
rascal>("apple": 1, "pear": 2) + ("banana": 3, "apple": 4);
map[str, int]: ("banana":3,"pear":2,"apple":4)
Map union is very suited for representing environment composition in interpreters.
Map in
Membership test on the keys of a map.
Exp_{1} in Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} in Exp_{2} 




Yields true
if the value of Exp_{1} occurs as key in the map value of Exp_{2} and false
otherwise.
The type of Exp_{1} should be compatible with the key type TK of Exp_{2}.
rascal>"pear" in ("apple": 1, "pear": 2);
bool: true
rascal>"pineapple" in ("apple": 1, "pear": 2);
bool: false
Map notin
Negated membership test on the keys of a map.
Exp_{1} notin Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} notin Exp_{2} 




Yields true
if the value of Exp_{1} does not occur as key in the map value of Exp_{2} and false
otherwise.
The type of Exp_{1} should be compatible with the key type TK of Exp_{2}.
rascal>"pineapple" notin ("apple": 1, "pear": 2);
bool: true
rascal>"pear" notin ("apple": 1, "pear": 2);
bool: false
3.1.9. Node
Node values.
Exp_{0} ( Exp_{1}, Exp_{2}, …, FieldName_{1} = Expr~1, FieldName_{2} = _Expr~2, … )
Exp_{0} 
Exp_{1} 
Exp_{2} 
…  Exp_{0} ( Exp_{1}, Exp_{2}, … ) 




… 

Values of type node
represent untyped trees and are constructed as follows:

the string value of Exp_{0} is the node name;

zero or more expressions of type
value
are the node's children. 
optionally, unordered named fields can be added as well.
The following are provided for nodes:

Node Equal: Equal operator on node values.

Node GreaterThan: Greater than operator on node values.

Node GreaterThanOrEqual: Greater than or equal operator on node values.

Node LessThan: Less than operator on node values.

Node LessThanOrEqual: Less than or equal operator on node values.

Node NotEqual: Not equal operator on node values.

Node Slice: Retrieve a slice of a node’s argument list.

Node Subscription: Retrieve an argument of a node via its index.
A node with name "my_node" and three arguments:
rascal>"my_node"(1, true, "abc");
node: "my_node"(1,true,"abc")
A nested node structure:
rascal>"my_node1"(1, "my_node2"(3.5, ["a", "b", "c"]), true);
node: "my_node1"(
1,
"my_node2"(
3.5,
["a","b","c"]),
true)
A node with named fields:
rascal>"my_node2"(1,2,size=2,age=24);
node: "my_node2"(1,2,
size=2,
age=24)

nodes are untyped and can be used to quickly import untyped data into Rascal

pattern matching on nodes is quite expressive

the lack of types at runtime makes pattern matching on node possibly inaccurate (you might match more than you think)
Node Equal
Equal operator on node values.
Exp_{1} == Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} == Exp_{2} 




Yields true
if the node names of the values of Exp_{1} and Exp_{2} are equal and
the children of each node are pairwise equal, otherwise false
.
rascal>"f"(1, "abc", true) == "f"(1, "abc", true);
bool: true
rascal>"f"(1, "abc", true) == "f"(1, "def", true);
bool: false
Node GreaterThan
Greater than operator on node values.
Exp_{1} > Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} > Exp_{2} 




Comparison on nodes is defined by a lexicographic ordering. Node N = F(N_{1}, …, N_{n})
is greater than node
N = G(M_{1}, …, M_{m})
when:
* N is not equal to M, and
* F is lexicographically greater than G, or F is equal to G and n > m
.
rascal>"g"(3) > "f"(10, "abc");
bool: true
rascal>"f"(10, "abc") > "f"(10);
bool: true
Node GreaterThanOrEqual
Greater than or equal operator on node values.
Exp_{1} >= Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} >= Exp_{2} 




Comparison on nodes is defined by a lexicographic ordering. Node N = F(N_{1}, …, N_{n})
is greater than or equal node
N = G(M_{1}, …, M_{m})
when:
* N is equal to M, or
* F is lexicographically greater than G, or F is equal to G and n > m
.
rascal>"g"(3) >= "f"(10, "abc");
bool: true
rascal>"f"(10, "abc") >= "f"(10);
bool: true
rascal>"f"(10, "abc") >= "f"(10, "abc");
bool: true
Node LessThan
Less than operator on node values.
Exp_{1} < Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} < Exp_{2} 




Comparison on nodes is defined by a lexicographic ordering. Node N = F(N_{1}, …, N_{n})
is less than node
N = G(M_{1}, …, M_{m})
when:
* N is not equal to M, and
* F is lexicographically less than G, or F is equal to G and n < m
.
rascal>"f"(10, "abc") < "g"(3);
bool: true
rascal>"f"(10) < "f"(10, "abc");
bool: true
Node LessThanOrEqual
Less than or equal operator on node values.
Exp_{1} ⇐ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐ Exp_{2} 




Comparison on nodes is defined by a lexicographic ordering. Node N = F(N_{1}, …, N_{n})
is less than or equal node
N = G(M_{1}, …, M_{m})
when:
* N is equal to M, or
* F is lexicographically less than G, or F is equal to G and n < m
.
rascal>"f"(10, "abc") <= "f"(10, "abc");
bool: true
rascal>"f"(10) <= "f"(10, "abc");
bool: true
Node NotEqual
Not equal operator on node values.
Exp_{1} != Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} != Exp_{2} 




Yields true
if the node names of the values of Exp_{1} and Exp_{2} are unequal or
any of the children of each node is pairwise unequal, otherwise true
.
rascal>"f"(1, "abc", true) != "g"(1, "abc", true);
bool: true
rascal>"f"(1, "abc", true) != "f"(1, "abc", true);
bool: false
Node Slice
Retrieve a slice of a node’s argument list.

Exp_{1} [ Exp_{2} .. Exp_{4}]

Exp_{1} [ Exp_{2} , Exp3 .. Exp_{4}]
where Exp_{2} and Exp_{4} are optional.
Exp_{1} 
Exp_{2} 
Exp_{3} 
Exp_{4} 
Exp_{1} [ Exp_{2} .. Exp_{4} ] or Exp_{1} [ Exp_{2} , Exp_{3} .. Exp_{4}] 






A Node slice is similar to a list List Slice and uses the integer values of Exp_{2} and Exp_{4} to determine the begin
(inclusive) and end
(exclusive)
of a slice from the children of the node value ND of Exp_{1}. Negative indices count from the end of the list of children backwards.
Using the second form, an extra index Exp_{3} is given that determines the
index of the second element in the slice and establishes the step
between
successive elements in the slice. The default step
is 1.
If end
is smaller than begin
, the slice is constructed backwards.
Let Len
be the number of children of ND and let N_{2}, N_{3} and N_{4} be the respective values of the expressions
Exp_{2}, Exp_{2} and Exp_{2} when they are present.
The slice parameters begin
, end
, and step
are determined as follows:

Exp_{2}:

If Exp_{2} is absent, then
begin = 0
. 
Otherwise, if N_{2} >= 0 then
begin = N_{2}
elsebegin = N_{2} + Len
.


Exp_{4}:

If Exp_{4} is absent, then
end = Len
. 
Otherwise, if N_{4} >= 0, then
end = N_{4}
elseend = N_{4} + Len
.


Exp_{3}:

If Exp_{3} is absent, then if
begin < end
thenstep = 1
elsestep = 1
. 
Otherwise, if
begin < end
, thenstep = N_{3}  begin
elsestep = begin  N_{3}
.

Now, the constraints 0 ⇐ begin < Len
and 0 < end < Len
should hold,
otherwise the exception IndexOutOfBounds
is thrown.
The slice consists of the children ND[begin]
, ND[begin+step]
, ND[end  step]
.
When begin >= end
, the elements are listed in reverse order.
Consider the list ND = "f"(0, "abc", 20, false, 40, [3,4,5], 60, {"a", "b"}, 80);
as running example.
Here is a view on the children of ND that will help to correlate positive and negative indices:
i 
0  1  2  3  4  5  6  7  8 












9 
8 
7 
6 
5 
4 
3 
2 
1 
Some common use cases (with begin
⇐ end
):
Slice  Means: 


children with indices 

children with indices 

children with indices from the beginning through 

the whole list of children 

last child of the list of children 

the last two children of the list of children 

all children except the last two. 
Let’s put this into practice now.
rascal>ND = "f"(0, "abc", 20, false, 40, [3,4,5], 60, {"a", "b"}, 80);
node: "f"(
0,
"abc",
20,
false,
40,
[3,4,5],
60,
{"a","b"},
80)
Slices with begin < end
rascal>ND[1..3];
list[value]: ["abc",20]
rascal>ND[1..]; // empty end => end of list of children
list[value]: [
"abc",
20,
false,
40,
[3,4,5],
60,
{"a","b"},
80
]
rascal>ND[..3]; // empty begin => first child of list
list[value]: [0,"abc",20]
rascal>ND[..]; // both empty => whole list of children
list[value]: [
0,
"abc",
20,
false,
40,
[3,4,5],
60,
{"a","b"},
80
]
Slices with begin >= end
rascal>ND[3..1]; // slice contains children with indices 3 and 2 (in that order)
list[value]: [false,20]
rascal>ND[3..3]; // empty slice when begin == end
list[value]: []
Slices with negative begin or end:
rascal>ND[2..2]; // equivalent to ND[2..7]
list[value]: [
20,
false,
40,
[3,4,5],
60
]
rascal>ND[2..7];
list[value]: [
20,
false,
40,
[3,4,5],
60
]
rascal>ND[4..2]; // equivalent to ND[5..7]
list[value]: [
[3,4,5],
60
]
rascal>ND[5..7];
list[value]: [
[3,4,5],
60
]
Slices with an explicit second index:
rascal>ND[1,3..6];
list[value]: [
"abc",
false,
[3,4,5]
]
rascal>ND[5,3..];
list[value]: [
[3,4,5],
false,
"abc"
]
Explore error cases:
rascal>ND[..10];
list[value]: [
0,
"abc",
20,
false,
40,
[3,4,5],
60,
{"a","b"},
80
]
rascal>ND[1..20];
list[value]: [
"abc",
20,
false,
40,
[3,4,5],
60,
{"a","b"},
80
]
Node Subscription
Retrieve an argument of a node via its index.
Exp_{1} [ Exp_{2} ]
Exp_{1} 
Exp_{2} 
Exp_{1} [ Exp_{2} ] 




Node subscription uses the integer value of Exp_{2} as index in the argument list of the node value of Exp_{1}.
The value of Exp_{2} should be greater or equal 0 and less than the number of arguments of the node.
If this is not the case, the exception IndexOutOfBounds
is thrown.
Introduce a node, assign it to F and retrieve the various arguments:
rascal>F = "f"(1, "abc", false);
node: "f"(1,"abc",false)
rascal>F[0]
value: 1
rascal>F[1]
value: "abc"
rascal>F[2]
value: false
Explore an error case:
rascal>F[3];
prompt:///(2,1,<1,2>,<1,3>): IndexOutOfBounds(3)
at $shell$(prompt:///(0,5,<1,0>,<1,5>))
ok
3.1.10. Number
Numeric values.
int
, real
, num
Numbers include integers (values of type int
) and reals (values of type real
).
If both operands have the same type (int
or real
) then the operator is the corresponding operator on integers or reals. Otherwise, integer arguments are first converted to real and the real operator is applied.
The following operations are provided on numbers:

Number Addition: Addition on numeric values.

Number Conditional: Conditional expression for numeric values.

Number Division: Division on numeric values.

Number Equal: Equality operator on numeric values.

Number GreaterThan: Greater than operator on numeric values.

Number GreaterThanOrEqual: Greater than or equal operator on numeric values.

Number LessThan: Less than operator on numeric values.

Number LessThanOrEqual: Less than or equal operator on numeric values.

Number Multiplication: Multiply two numeric values.

Number Negation: Negate a numeric value.

Number NotEqual: Not equal operator on numeric values.

Number Remainder: Remainder of two integer values.

Number Subtraction: Subtract two numeric values.
Number Addition
Addition on numeric values.
Exp_{1} + Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} + Exp_{2} 










Yields the numerical sum of the values of Exp_{1} and Exp_{2}.
rascal>12 + 13
int: 25
rascal>12 + 13.5
real: 25.5
Number Conditional
Conditional expression for numeric values.
Exp_{1} ? Exp_{2} : Exp_{3}
Exp_{1} 
Exp_{2} 
Exp_{3} 
Exp_{1} ? Exp_{2} : Exp_{3} 













If the value of Exp is true
then the value of Exp_{1} else the value of Exp_{2}.
rascal>(3 > 2) ? 10 : 20
int: 10
rascal>(3 > 20) ? 10 : 20
int: 20
Number Division
Division on numeric values.
Exp_{1} / Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} / Exp_{2} 










Yields the result of dividing the value of Exp_{1} by the value of Exp_{2}.
rascal>12 / 3
int: 4
rascal>10 / 3
int: 3
rascal>12 / 3.0
real: 4.
rascal>10 / 3.0
real: 3.333333333
rascal>12 / 0
prompt:///(5,1,<1,5>,<1,6>): ArithmeticException("/ by zero")
ok
Number Equal
Equality operator on numeric values.
Exp_{1} == Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} == Exp_{2} 










Yields true
if the value of both arguments is numerically equal, and false
otherwise.
rascal>12 == 12
bool: true
rascal>12 == 12.0
bool: true
rascal>12 == 13
bool: false
rascal>12 == 13.0
bool: false
rascal>3.14 == 3.14
bool: true
rascal>3.14 == 3
bool: false
Number GreaterThan
Greater than operator on numeric values.
Exp_{1} > Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} > Exp_{2} 










Yields true
if the value of Exp_{1} is numerically greater than the value of Exp_{2}, and false
otherwise.
rascal>13 > 12
bool: true
rascal>12 > 13
bool: false
rascal>13.5 > 12
bool: true
rascal>12.5 > 13
bool: false
Number GreaterThanOrEqual
Greater than or equal operator on numeric values.
Exp_{1} >= Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} >= Exp_{2} 










Yields true
if the value of Exp_{1} is numerically greater than or equal to the value of Exp_{2}, and false
otherwise.
rascal>13 >= 12
bool: true
rascal>12 >= 13
bool: false
rascal>13.5 >= 12
bool: true
rascal>12.5 >= 13
bool: false
Number LessThan
Less than operator on numeric values.
Exp_{1} < Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} < Exp_{2} 










Yields true
if the value of Exp_{1} is numerically less than the value of Exp_{2}, and false
otherwise.
rascal>13 < 12
bool: false
rascal>12 < 13
bool: true
rascal>13.5 < 12
bool: false
rascal>12.5 < 13
bool: true
Number LessThanOrEqual
Less than or equal operator on numeric values.
Exp_{1} ⇐ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐ Exp_{2} 










Yields true
if the value of Exp_{1} is numerically less than or equal to the value of Exp_{2}, and false
otherwise.
rascal>13 <= 12
bool: false
rascal>12 <= 13
bool: true
rascal>13.5 <= 12
bool: false
rascal>12.5 <= 13
bool: true
Number Multiplication
Multiply two numeric values.
Exp_{1} * Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} * Exp_{2} 










Yields the result of multiplying the values of Exp_{1} and Exp_{2}.
rascal>12 * 13
int: 156
rascal>12 * 13.5
real: 162.0
rascal>12*13
int: 156
Number Negation
Negate a numeric value.
 Exp
Exp 
 Exp 





Yields the negated values of Exp.
rascal>12
int: 12
rascal>13.5
real: 13.5
rascal> 12
int: 12
Number NotEqual
Not equal operator on numeric values.
Exp_{1} != Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} != Exp_{2} 










Yields true
if the value of both arguments is numerically unequal, and false
otherwise.
rascal>12 != 13
bool: true
rascal>12 != 12
bool: false
rascal>12 != 13.0
bool: true
rascal>12.0 != 13
bool: true
rascal>3.14 != 3
bool: true
rascal>3.14 != 3.14
bool: false
Number Remainder
Remainder of two integer values.
Exp_{1} % Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} % Exp_{2} 




Yields the remainder when dividing the of Exp_{1} by the value of Exp_{2}.
rascal>12 % 5
int: 2
rascal>12 % 6
int: 0
Remainder is only defined on integers:
rascal>13.5 % 6
prompt:///(7,1,<1,7>,<1,8>): remainder not supported on real and int
Advice: http://tutor.rascalmpl.org/Errors/Static/UnsupportedOperation/UnsupportedOperation.html
ok
Number Subtraction
Subtract two numeric values.
Exp_{1}  Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1}  Exp_{2} 










Yields the numerical result of subtracting the value of Exp_{2} from the value of Exp_{1}.
rascal>13  12
int: 1
rascal>13.5  12
real: 1.5
rascal>12  13
int: 1
rascal>12  13.5
real: 1.5
3.1.11. Range
Numeric range of values.

[ Exp_{1} .. Exp_{3} ]

[ Exp_{1}, Exp_{2} .. Exp_{3} ]
Ranges are a shorthand for describing lists of integers from Exp_{1} up to (exclusive) Exp_{3} with increments of 1. When Exp_{2} is present it is taken as the second element of the list and Exp_{2}  Exp_{1} is used as increment for the subsequent list elements.
A range with integer expressions is identical to a list List Slice. However, a range may also contain numeric expressions that are not integers.
rascal>[1 .. 10];
list[int]: [1,2,3,4,5,6,7,8,9]
rascal>[1, 3 .. 10];
list[int]: [1,3,5,7,9]
rascal>[0.5, 3.2 .. 10];
list[real]: [0.5,3.2,5.9,8.6]
rascal>[1, 2 .. 10];
list[int]: [1,2,5,8]
Ranges are mostly used to loop over ranges of integers.
In some cases ranges are empty where one could have expected at least one element:
rascal>[1, 3 .. 10];
list[int]: []
3.1.12. Real
Real values.
real
The real values are represented by the type real
and are written as usual in most programming languages.
They can have arbitrary size and precision.
See Number for all operations on integers, reals and numbers.

1.5

3.14e123
3.1.13. ReifiedTypes
Types can be represented by values
The type reify expression operator has two functions in one go:

it transforms type literals into values that represent them (an isomorphic relation)

it reifies the declarations necessary to build values of the types as well
As a result a reified type can be used to reconstruct a type and the abstract (Algebraic Data Type) or concrete (Syntax Definition) grammar that produced it.
Type literals have a nice interaction with Type Parameters, since they can be used to bind a type parameter without having to provide a value of the type. An example is the [parse] function in [ParseTree] (see below for an example usage).
The values that are used to represent types are declared in the [LibrariesPreludeType] module and [LibrariesPreludeParseTree] modules, namely Symbol
is the datatype to represent types symbolically and Production
is the datatype for representing grammatical constructs.
A type literal wraps a Symbol
and a map of `Production`s.
First import the module Type
:
rascal>import Type;
ok
Builtin types can be constructed without definitions, so the reified type representation is simple:
rascal>#int
type[int]: type(
int(),
())
rascal>#list[int]
type[list[int]]: type(
list(int()),
())
rascal>#rel[int from, int to]
type[rel[int from,int to]]: type(
set(tuple([
label(
"from",
int()),
label(
"to",
int())
])),
())
to get the symbol from the reified type:
rascal>#int.symbol
Symbol: int()
or we can use some definitions and reify the defined type to see a different behavior:
rascal>data Nat = zero()  succ(Nat prev)  add(Nat l, Nat r)  mul(Nat l, Nat r);
ok
rascal>#Nat
type[Nat]: type(
adt(
"Nat",
[]),
(adt(
"Nat",
[]):choice(
adt(
"Nat",
[]),
{
cons(
label(
"add",
adt(
"Nat",
[])),
[
label(
"l",
adt(
"Nat",
[])),
label(
"r",
adt(
"Nat",
[]))
],
[],
{}),
cons(
label(
"mul",
adt(
"Nat",
[])),
[
label(
"l",
adt(
"Nat",
[])),
label(
"r",
adt(
"Nat",
[]))
],
[],
{}),
cons(
label(
"zero",
adt(
"Nat",
[])),
[],
[],
{}),
cons(
label(
"succ",
adt(
"Nat",
[])),
[label(
"prev",
adt(
"Nat",
[]))],
[],
{})
})))
and we can get an abstract definition of the constructors of the [AlgebraicDataType]:
rascal>import Type;
ok
rascal>#Nat.definitions[adt("Nat",[])]
Production: choice(
adt(
"Nat",
[]),
{
cons(
label(
"add",
adt(
"Nat",
[])),
[
label(
"l",
adt(
"Nat",
[])),
label(
"r",
adt(
"Nat",
[]))
],
[],
{}),
cons(
label(
"mul",
adt(
"Nat",
[])),
[
label(
"l",
adt(
"Nat",
[])),
label(
"r",
adt(
"Nat",
[]))
],
[],
{}),
cons(
label(
"zero",
adt(
"Nat",
[])),
[],
[],
{}),
cons(
label(
"succ",
adt(
"Nat",
[])),
[label(
"prev",
adt(
"Nat",
[]))],
[],
{})
})
we could go the other way around and construct a type literal dynamically:
rascal>type(\int(),())
type[value]: type(
int(),
())
rascal>type(\int(),()) == #int
bool: true
we use type literals often in IO to express an expected type:
rascal>import ValueIO;
ok
rascal>int testInt = readTextValueString(#int, "1");
int: 1
rascal>tuple[int,int] testTuple = readTextValueString(#tuple[int,int], "\<1,2\>");
tuple[int,int]: <1,2>

Note that the type reify operator always produces constant values, because type literals are always constants.
3.1.14. Relation
Relation values.
{ < Exp_{11}, Exp_{12}, … > , < Exp_{21}, Exp_{22}, … > , … }
Exp_{11} 
Exp_{12} 
…  { < Exp_{11}, Exp_{12}, … > , … } 



… 

A relation is a set of elements with the following property:

All elements have the same static tuple type.
Relations are thus nothing more than sets of tuples, but since they are used so often we provide a shorthand notation for them.
Relations are represented by the type rel[T_{1} L_{1}, T_{2} L_{2}, … ]
, where T_{1}, T_{2}, … are arbitrary types and
L_{1}, L_{2}, … are optional labels. It is a shorthand for set[tuple[T_{1} L_{1}, T_{2} L_{2}, … ]]
.
An nary relations with m tuples is denoted by
{< E_{11}, E_{12}, …, E_{1n} >,< E_{21}, E_{22}, …, E_{2n} >, …, < E_{m1}, E_{m2}, …, E_{mn} >}
,
where the E_{ij} are expressions that yield the desired element type T_{i}.
Since relations are a form of set all operations (see Set) and functions (see [PreludeSet]) are also applicable to relations.
The following additional operators are provided for relations:

Relation CartesianProduct: Cartesian product of two relation values.

Relation Composition: Composition of two relation values.

Relation FieldSelection: Select a field (column) from a relation value.

Relation Join: Join two relation values.

Relation ReflexiveTransitiveClosure: The reflexive transitive closure of a binary relation.

Relation Subscription: Indexing of a relation via tuple values.

Relation TransitiveClosure: Transitive closure on binary relation values.
There are also library functions available for Relations.
rascal>{<1,10>, <2,20>, <3,30>}
rel[int,int]: {
<1,10>,
<3,30>,
<2,20>
}
instead of rel[int,int]
we can also give set[tuple[int,int]]
as type of the above expression
remember that these types are interchangeable.
rascal>{<"a",10>, <"b",20>, <"c",30>}
rel[str,int]: {
<"a",10>,
<"b",20>,
<"c",30>
}
rascal>{<"a", 1, "b">, <"c", 2, "d">}
rel[str,int,str]: {
<"c",2,"d">,
<"a",1,"b">
}
Relation CartesianProduct
Cartesian product of two relation values.
Exp_{1} * Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} * Exp_{2} 




Returns a binary relation that is the Cartesian product of two sets.
rascal>{1, 2, 3} * {9};
rel[int,int]: {
<1,9>,
<3,9>,
<2,9>
}
rascal>{1, 2, 3} * {10, 11};
rel[int,int]: {
<1,10>,
<1,11>,
<3,10>,
<3,11>,
<2,10>,
<2,11>
}
Relation Composition
Composition of two relation values.
Exp_{1} o Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} o Exp_{2} 




Returns the composition of two binary relations.
rascal>import Relation;
ok
rascal>{<1,10>, <2,20>, <3,15>} o {<10,100>, <20,200>};
rel[int,int]: {
<1,100>,
<2,200>
}
We use the letter o
as operator and this may conflict other defined names.
Relation FieldSelection
Select a field (column) from a relation value.
Exp . Name
Exp 
Exp . Name 



Exp should evaluate to a relation that has an ith field label L_{i} that is identical to Name. Return a set with all values of that field. Name stands for itself and is not evaluated.
rascal>rel[str street, int nm] R = {<"abc", 1>, <"abc", 2>, <"def", 4>, <"def", 5>};
rel[str street,int nm]: {
<"abc",1>,
<"abc",2>,
<"def",5>,
<"def",4>
}
rascal>R.street;
set[str]: {"abc","def"}
Relation Join
Join two relation values.
Exp_{1} join Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} join Exp_{2} 




Relation resulting from the natural join of the relation values of the two arguments. This relation contains tuples that are the result from concatenating the elements from both arguments.
rascal>{<1,2>, <10,20>} join {<2,3>};
rel[int,int,int,int]: {
<1,2,2,3>,
<10,20,2,3>
}
rascal>{<1,2>} join {3, 4};
rel[int,int,int]: {
<1,2,3>,
<1,2,4>
}
rascal>{<1,2>, <10,20>} join {<2,3>, <20,30>};
rel[int,int,int,int]: {
<1,2,2,3>,
<10,20,2,3>,
<10,20,20,30>,
<1,2,20,30>
}
Relation ReflexiveTransitiveClosure
The reflexive transitive closure of a binary relation.
Exp *
Exp 
Exp * 



Reflexive transitive closure is defined by repeated composition of a relation. If we define for a given relation R:

R^{0} = identity relation =
{<a, a>, <b, b>  <a, b> ← R}

R^{1} = R

R^{2} = R o R

R^{3} = R o R^{2}

…
then the reflexive transitive closure R* can be defined in two ways: (also see Relation TransitiveClosure): * R* = R^{0} + R^{1} + R^{2} + R^{3} + … * R* = R^{0} + R+
rascal>{<1,2>, <2,3>, <3,4>}*;
rel[int,int]: {
<4,4>,
<1,1>,
<1,3>,
<1,2>,
<1,4>,
<3,3>,
<3,4>,
<2,3>,
<2,2>,
<2,4>
}
Relation Subscription
Indexing of a relation via tuple values.
Exp_0 [ Exp_{1}, Exp_{2}, … Exp_{n}]
Exp_0 [ Exp_{1}]
Variant 1
Exp_0 
Exp_{1} 
Exp_{2} 
…  Exp_0 [ Exp_{1}, Exp_{2}, … ] 




… 

Variant 2
Exp_{0} 
Exp_{1} 
Exp_{0} [ Exp_{1} ] 




Relation resulting from subscription of a relation Exp_{0}.
Variant 1
Subscription with the index values of Exp_{1}, Exp_{2}, ….
The result is a relation with all tuples that have these index values as first elements
with the index values removed from the tuple.
If the resulting tuple has only a single element, a set is returned instead of a relation.
A wildcard _
as index value matches all possible values at that index position.
Variant 2
Subscription with a set of the index values of Exp_{1}. The result is a relation with all tuples that have these index values as first element with the index values removed from the tuple.
rascal>R = {<1,10>, <2,20>, <1,11>, <3,30>, <2,21>};
rel[int,int]: {
<3,30>,
<1,10>,
<1,11>,
<2,20>,
<2,21>
}
rascal>R[1];
set[int]: {10,11}
rascal>R[{1}];
set[int]: {10,11}
rascal>R[{1, 2}];
set[int]: {10,20,11,21}
rascal>RR = {<1,10,100>,<1,11,101>,<2,20,200>,<2,22,202>,
>>>>>>> <3,30,300>};
rel[int,int,int]: {
<1,10,100>,
<3,30,300>,
<1,11,101>,
<2,20,200>,
<2,22,202>
}
rascal>RR[1];
rel[int,int]: {
<10,100>,
<11,101>
}
rascal>RR[1,_];
set[int]: {100,101}
Introduce a relation with economic data and assign it to GDP
:
rascal>rel[str country, int year, int amount] GDP =
>>>>>>>{<"US", 2008, 14264600>, <"EU", 2008, 18394115>,
>>>>>>> <"Japan", 2008, 4923761>, <"US", 2007, 13811200>,
>>>>>>> <"EU", 2007, 13811200>, <"Japan", 2007, 4376705>};
rel[str country,int year,int amount]: {
<"EU",2007,13811200>,
<"US",2007,13811200>,
<"Japan",2007,4376705>,
<"US",2008,14264600>,
<"Japan",2008,4923761>,
<"EU",2008,18394115>
}
and then retrieve the information for the index "Japan"
:
rascal>GDP["Japan"];
rel[int,int]: {
<2007,4376705>,
<2008,4923761>
}
or rather for the indices "Japan"
and 2008
:
rascal>GDP["Japan", 2008];
set[int]: {4923761}
Relation TransitiveClosure
Transitive closure on binary relation values.
Exp +
Exp 
Exp + 



Returns the transitive closure of a binary relation. Transitive closure is defined by repeated composition of a relation. If we define for a given relation R:

R^{1} = R

R^{2} = R o R

R^{3} = R o R^{2}

…
then the transitive closure R+ can be defined as

R+ = R^{1} + R^{2} + R^{3} + …
rascal>{<1,2>, <2,3>, <3,4>}+;
rel[int,int]: {
<3,4>,
<1,3>,
<1,2>,
<1,4>,
<2,3>,
<2,4>
}
We can also simply (but not necessarily efficiently) define transitive closure ourselves:
rascal>rel[int,int] tclosure(rel[int,int] R) {
>>>>>>> tc = R;
>>>>>>> while(true){
>>>>>>> tc1 = tc;
>>>>>>> tc += tc o R;
>>>>>>> if(tc1 == tc)
>>>>>>> return tc;
>>>>>>> }
>>>>>>>}
rel[int,int] (rel[int,int]): function(prompt:///(0,149,<1,0>,<9,1>))
tclosure({<1,2>, <2,3>, <3,4>});
rascal>
>>>>>>>
cancelled
rascal>.Benefits
^ Parse error hereok
rascal>
cancelled
rascal>.Pitfalls
^ Parse error hereok
rascal>
cancelled
WARNING: unexpected errors in the above SHELL example. Documentation author please fix! :leveloffset: +1
3.2. Set
Set values.
{ Exp_{1}, Exp_{2}, … }
Exp_{1} 
Exp_{2} 
…  { Exp_{1}, Exp_{2}, … } 

T_{1} 
T_{2} 
… 
set[ lub(T_{1}, T_{2}, … ) ] 
A set is an unordered sequence of values and has the following properties:

All elements have the same static type.

The order of the elements does not matter.

A set contains an element only once. In other words, duplicate elements are eliminated and no matter how many times an element is added to a set, it will occur in it only once.
The type of a set has the form set[T]
,
where T
is an arbitrary type.
When a value or variable of type set occurs inside a set, that set value is inserted as set element.
To achieve splicing of these elements, i.e., the insertion of the elements of the set value rather than the whole set,
it has to be prefixed by the splice operator *
.
The following operators are provided on sets:

Set Comprehension: A set comprehension generates a set value.

Set Difference: The difference between two sets.

Set Equal: Equal operator on set values.

Set Insert: Add an element to a set.

Set Intersection: Intersection of two sets.

Set NotEqual: Not equal operator on set values.

Set Product: The product of two set values.

Set Splice: Splice the elements of a set in an enclosing set.

Set StrictSubSet: Strict subset operator on set values.

Set StrictSuperSet: Strict superset operator on set values.

Set SubSet: Subset operator on set values.

Set SuperSet: Superset operator on set values.

Set Union: Union of two set values.

Set in: Membership test on set values.

Set notin: Negated membership test on set values.
There are also library functions available for Sets. .Examples ## Set types
rascal>{1, 2, 3};
set[int]: {1,3,2}
rascal>{<1,10>, <2,20>, <3,30>};
rel[int,int]: {
<1,10>,
<3,30>,
<2,20>
}
rascal>{1, "b", 3};
set[value]: {"b",1,3}
rascal>{<"a", 10>, <"b", 20>, <"c", 30>}
rel[str,int]: {
<"a",10>,
<"b",20>,
<"c",30>
}
rascal>{{"a", "b"}, {"c", "d", "e"}}
set[set[str]]: {
{"a","b"},
{"c","d","e"}
}
Note that

{1, 2, 3}
and{3, 2, 1}
are identical sets (since order is not relevant). 
{1, 2, 3}
and{1, 2, 3, 1}
are also identical sets (since duplication is not relevant).
3.2.1. Set splicing
Introduce a set variable S
rascal>S = {1, 2, 3};
set[int]: {1,3,2}
and observe how the value of S
is added as single element in another set:
rascal>{10, S, 20};
set[value]: {10,20,{1,3,2}}
or how its elements are added as elements to the other set:
rascal>{10, *S, 20};
set[int]: {10,1,3,20,2}
3.2.2. Set Comprehension
A set comprehension generates a set value.
{ Exp_{1}, Exp_{2}, …  Gen_{1}, Gen_{2}, … }
Exp_{1} 
Exp_{2} 
…  { Exp_{1}, Exp_{2}, …  Gen_{1}, Gen_{2}, … } 



… 

A set comprehension consists of a number of contributing expressions Exp_{1}, Exp_{2}, … and a number of generators Gen_{1}, Gen_{2}, Gen_{3}, … that are evaluated as described in Comprehensions.
rascal>{ N * N  int N < [0 .. 10]};
set[int]: {16,64,1,9,81,4,0,49,36,25}
rascal>{ N * N  int N < [0 .. 10], N % 3 == 0};
set[int]: {9,81,0,36}
3.2.3. Set Difference
The difference between two sets.
Exp_{1}  Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1}  Exp_{2} 







If both Exp_{1} and Exp_{2} have a set as value, the result is the difference of these two set values. If Exp_{2} does not have a set as value, it is first converted to a set before the difference is computed. The difference is computed by removing all elements of the second set from the first set.
rascal>{1, 2, 3, 4}  {1, 2, 3};
set[int]: {4}
rascal>{1, 2, 3, 4}  {3};
set[int]: {1,2,4}
rascal>{1, 2, 3, 4}  3;
set[int]: {1,2,4}
rascal>{1, 2, 3, 4}  {5, 6, 7};
set[int]: {1,3,2,4}
3.2.4. Set Equal
Equal operator on set values.
Exp_{1} == Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} == Exp_{2} 




Yields true
if both arguments are equal sets and false
otherwise.
rascal>{1, 2, 3} == {3, 2, 1};
bool: true
rascal>{1, 2, 3} == {1, 2};
bool: false
3.2.5. Set Insert
Add an element to a set.
Exp_{1} + Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} + Exp_{2} 







The +
operator will add elements to sets.
rascal>{1, 2, 3} + 4;
set[int]: {1,3,2,4}
rascal>1 + { 2, 3, 4};
set[int]: {1,3,2,4}
rascal>{1} + 1;
set[int]: {1}
rascal>1 + {1};
set[int]: {1}

if both operands of
+
are a set then it acts as Set Union.
3.2.6. Set Intersection
Intersection of two sets.
Exp_{1} & Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} & Exp_{2} 




Returns the intersection of the two set values of Exp_{1} and Exp_{2}. The intersection consists of the common elements of both sets.
rascal>{1, 2, 3, 4, 5} & {4, 5, 6};
set[int]: {5,4}
3.2.7. Set NotEqual
Not equal operator on set values.
Exp_{1} != Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} != Exp_{2} 




Yields true
if both arguments are unequal sets and false
otherwise.
rascal>{1, 2, 3} != {3, 2, 1};
bool: false
rascal>{1, 2, 3} != {1, 2};
bool: true
3.2.8. Set Product
The product of two set values.
Exp_{1} * Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} * Exp_{2} 




Yields a relation resulting from the product of the values of Exp_{1} and Exp_{2}. It contains a tuple for each combination of values from both arguments.
rascal>{1, 2, 3} * {4, 5, 6};
rel[int,int]: {
<1,5>,
<1,4>,
<1,6>,
<3,5>,
<3,4>,
<3,6>,
<2,5>,
<2,4>,
<2,6>
}
A card deck can be created as follows:
rascal>{"clubs", "hearts", "diamonds", "spades"} * {1,2,3,4,5,6,7,8,9,10,11,12,13};
rel[str,int]: {
<"hearts",10>,
<"hearts",7>,
<"hearts",1>,
<"hearts",3>,
<"hearts",13>,
<"hearts",9>,
<"hearts",2>,
<"hearts",4>,
<"hearts",11>,
<"hearts",6>,
<"hearts",12>,
<"hearts",5>,
<"hearts",8>,
<"spades",10>,
<"spades",7>,
<"spades",1>,
<"spades",3>,
<"spades",13>,
<"spades",9>,
<"spades",2>,
<"spades",4>,
<"spades",11>,
<"spades",6>,
<"spades",12>,
<"spades",5>,
<"spades",8>,
<"clubs",10>,
<"clubs",7>,
<"clubs",1>,
<"clubs",3>,
<"clubs",13>,
<"clubs",9>,
<"clubs",2>,
<"clubs",4>,
<"clubs",11>,
<"clubs",6>,
<"clubs",12>,
<"clubs",5>,
<"clubs",8>,
<"diamonds",10>,
<"diamonds",7>,
<"diamonds",1>,
<"diamonds",3>,
<"diamonds",13>,
<"diamonds",9>,
<"diamonds",2>,
<"diamonds",4>,
<"diamonds",11>,
<"diamonds",6>,
<"diamonds",12>,
<"diamonds",5>,
<"diamonds",8>
}
3.2.9. Set Splice
Splice the elements of a set in an enclosing set.
Exp 
Exp_{1} 
Exp_{n} 
{Exp_{1}, …, Exp, …, Exp_{n}} 





The operator *
splices the elements of a set in an enclosing set.
Consider the following set in which the set {10, 20, 30]
occurs as set element. It has as type set[value]
:
rascal>{1, 2, {10, 20, 30}, 3, 4};
set[value]: {3,2,4,1,{10,20,30}}
The effect of splicing the same set element in the enclosing set gives a flat list of type set[int]
:
rascal>{1, 2, *{10, 20, 30}, 3, 4};
set[int]: {10,1,3,20,2,4,30}
The same example can be written as:
rascal>S = {10, 20, 30};
set[int]: {10,20,30}
rascal>{1, 2, *S, 3, 4};
set[int]: {10,1,3,20,2,4,30}
3.2.10. Set StrictSubSet
Strict subset operator on set values.
Exp_{1} < Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} < Exp_{2} 




Yields true
if the value of Exp_{1} is a strict subset of the value of Exp_{2}, and false
otherwise.
rascal>{1, 2, 3} < {1, 2, 3, 4};
bool: true
rascal>{1, 2, 3} < {1, 3, 4};
bool: false
rascal>{1, 2, 3} < {1, 2, 3};
bool: false
3.2.11. Set StrictSuperSet
Strict superset operator on set values.
Exp_{1} > Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} > Exp_{2} 




Yields true
if the value of Exp_{1} is a strict superset of the value of Exp_{2}, and false
otherwise.
rascal>{1, 2, 3, 4} > {3, 2, 1};
bool: true
rascal>{1, 2, 3, 4} > {4, 3, 2, 1};
bool: false
3.2.12. Set SubSet
Subset operator on set values.
Exp_{1} ⇐ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐ Exp_{2} 




Yields true
if the value of SetExp_{1} is a subset of the value of SetExp_{2}, and false
otherwise.
rascal>{1, 2, 3} <= {1, 2, 3, 4};
bool: true
rascal>{1, 2, 3} <= {1, 2, 3};
bool: true
3.2.13. Set SuperSet
Superset operator on set values.
Exp_{1} >= Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} >= Exp_{2} 




Yields true
if the value of Exp_{1} is a superset of the value of Exp_{2} and false
otherwise.
rascal>{1, 2, 3, 4} >= {3, 2, 1};
bool: true
rascal>{1, 2, 3, 4} >= {4, 3, 2, 1};
bool: true
3.2.14. Set Union
Union of two set values.
Exp_{1} 
Exp_{2} 
Exp_{1} + Exp_{2} 




The +
operator computes set union if both operands are sets. If one of the operands is not a set, it acts as Set Insert instead.
rascal>{1, 2, 3} + {4, 5, 6};
set[int]: {5,1,3,2,4,6}
rascal>{1,2,3} + {2,3,4};
set[int]: {1,3,2,4}
rascal>{1, 2, 3} + {3};
set[int]: {1,3,2}
rascal>{2} + { 2, 3, 4};
set[int]: {3,2,4}
3.2.15. Set in
Membership test on set values.
Exp_{1} in Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} in Exp_{2} 




Yields true
if the value of Exp_{1} occurs as element in the value of Exp_{2} and false
otherwise. The type of Exp_{1} should be compatible with the element type of Exp_{2}.
rascal>2 in {1, 2, 3};
bool: true
rascal>4 in {1, 2, 3};
bool: false
3.2.16. Set notin
Negated membership test on set values.
Exp_{1} notin Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} notin Exp_{2} 




Yields true
if the value of Exp_{1} does not occur as element in the value of Exp_{2} and false
otherwise. The type of Exp_{1} should be compatible with the element type of Exp_{2}.
rascal>4 notin {1, 2, 3};
bool: true
rascal>4 notin {1, 2, 3, 4};
bool: false
3.3. String
String values.
"StringChar_{1}StringChar_{2}…"
where `StringChar_{i} may be one of the following:

Ordinary character: Any character except
<
,>
,"
,'
or\
. 
Escaped character: Backslash
\
followed by any of<
,>
,"
,'
or\
represents the escaped character itself. Other escape sequences that are supported are:
\n
: newline 
\t
: tab 
\r
: carriage return 
\b
: backspace 
\f
: vertical feed 
\u hexDigit_{1} hexDigit_{2} hexDigit_{3} hexDigit_{4}
: hexadecimal escapes with four digit indexes into UNICODE. 
\U hexDigit_{1} hexDigit_{2} hexDigit_{3} hexDigit_{4} hexDigit_{5} hexDigit_{6}
: hexadecimal escapes with six digit indexes into UNICODE. 
\ a_hexDigit_{1}_ hexDigit_{2}
: hexadecimal escapes with 2 digit indexes into ASCII (0x0 … 0x7F).


String Interpolation:
Form  Description 


Interpolate the value of the expression as a string 

Conditional inclusion of Text, where StringChars may use variables introduced in Exp 

Conditional inclusion of either StringChars_{1} or StringChars_{2} 

Iterative splicing of StringChars into the result, where StringChars may use variables introduced in Exp. 

Iterative splicing of StringChars into the result, where StringChars may use variables introduced in Exp. 

Iterative splicing of StringChars into the result, where StringChars may use variables introduced in Exp. 

Multiline:
Form  Description 

`StringChars_{1}\n StringChars_{2} ` 
Strings can be multiline without an escape or continuation marker 

A margin character 
str
The string values are represented by the type str
and consist of character
sequences surrounded by double quotes, e.g., "a"
or "a\nlong\nstring"
.
Multiline: Strings may span more than one line. The margin character '
indicates which part of a line will be ignored. This is useful for indenting a multiline string with the source code that generates it.
Interpolation: String literals support socalled string interpolation:
inside string constants text between angle brackets (<
and >
) is first executed and then replaced by
its string value.
Various statements (if, for, while, do) also return a value and can be used in this way.
In the interpolation variant of these statements the block or blocks that are part of the statement become arbitrary text
(that may itself contain interpolations).
Autoindent: Expressions that get interpolated in a string will be autoindented. This means that each line that results from the evaluation of the expression is prefixed with the indentation level of the position of the expression in the current string.
The following operators are defined for Strings:

String Concatenation: Concatenate two strings.

String Equal: Equality operator on string values.

String GreaterThan: Greater than operator on string values.

String GreaterThanOrEqual: Greater than or equal operator on string values.

String LessThan: Less than operator on string values.

String LessThanOrEqual: Less than or equal operator on string values.

String NotEqual: Not equal operator on string values.

String Slice: Retrieve a slice of a string.

String Subscription: Retrieve a substring via its index.
There are also library functions available for Strings.
rascal>N = 13;
int: 13
rascal>"The value of N is <N>";
str: "The value of N is 13"
rascal>"The value of N*N is <N*N>";
str: "The value of N*N is 169"
rascal>"The value is <(N < 10) ? 10 : N*N>";
str: "The value is 169"
As you can see the string value of variables and expressions is interpolated in the result as expected. <br> Some examples of more advances string interpolation
rascal>"N is <if(N < 10){> small <} else {> large <}>";
str: "N is large "
rascal>"N is <if(N < 10){> small <} else {> large (<N>)<}>";
str: "N is large (13)"
rascal>"before <for(x<[1..5]){>a <x> b <}>after";
str: "before a 1 b a 2 b a 3 b a 4 b after"
multiline string
rascal>import IO;
ok
rascal>println("hello
>>>>>>>this
>>>>>>> is
>>>>>>> new")
hello
this
is
new
ok
multiline string with margin:
rascal>if (true)
>>>>>>> println("this is
>>>>>>> 'what
>>>>>>> ' margins
>>>>>>> 'are good for
>>>>>>> ");
this is
what
margins
are good for
ok
auto indent:
rascal>str genMethod(str n) = "int <n>() {
>>>>>>> ' return 0;
>>>>>>> '}";
str (str): function(prompt:///(0,99,<1,0>,<3,27>))
rascal>str genClass() = "class myClass {
>>>>>>> ' <genMethod("myMethod")>
>>>>>>> '}";
str (): function(prompt:///(0,99,<1,0>,<3,21>))
rascal>println(genClass());
class myClass {
int myMethod() {
return 0;
}
}
ok
String interpolation enables very flexible templatebased text generation as used in generators for source code, markup and the like.
3.3.1. String Concatenation
Concatenate two strings.
Exp_{1} + Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} + Exp_{2} 




Concatenates the string values of Exp_{1} and Exp_{2}.
Note that to concatenate other types of values into a string, you can use String interpolation.
rascal>"abc" + "def";
str: "abcdef"
3.3.2. String Equal
Equality operator on string values.
Exp_{1} == Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} == Exp_{2} 




Yields true
if both arguments are identical and false
otherwise.
rascal>"abc" == "abc";
bool: true
rascal>"abc" == "defghi";
bool: false
3.3.3. String GreaterThan
Greater than operator on string values.
Exp_{1} > Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} > Exp_{2} 




Yields true
if the string value of Exp_{1} is strictly lexicographically greater
than the string value of Exp_{2}, and false
otherwise.
rascal>"abcdef" > "abc";
bool: true
rascal>"defghi" > "abcdef";
bool: true
rascal>"a" > "abc";
bool: false
3.3.4. String GreaterThanOrEqual
Greater than or equal operator on string values.
Exp_{1} >= Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} >= Exp_{2} 




Yields true
if the string value of Exp_{1} is lexicographically greater
than the string value of Exp_{2} or if both strings are equal, and false
otherwise.
rascal>"abc" >= "abc";
bool: true
rascal>"abcdef" >= "abc";
bool: true
rascal>"defghi" >= "abcdef";
bool: true
rascal>"a" >= "abc";
bool: false
3.3.5. String LessThan
Less than operator on string values.
Exp_{1} < Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} < Exp_{2} 




Yields true
if the string value of Exp_{1} is strictly lexicographically less
than the string value of Exp_{2}, and false
otherwise.
rascal>"abc" < "abcdef";
bool: true
rascal>"abc" < "defghi";
bool: true
rascal>"abc" < "a";
bool: false
3.3.6. String LessThanOrEqual
Less than or equal operator on string values.
Exp_{1} ⇐ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐ Exp_{2} 




Yields true
if the string value of Exp_{1} is lexicographically less
than the string value of Exp_{2} or if both string are equal, and false
otherwise.
rascal>"abc" <= "abc";
bool: true
rascal>"abc" <= "abcdef";
bool: true
rascal>"abc" <= "defghi";
bool: true
rascal>"abc" <= "a";
bool: false
3.3.7. String NotEqual
Not equal operator on string values.
Exp_{1} != Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} != Exp_{2} 




Yields true
if both arguments are not identical and false
otherwise.
rascal>"abc" != "defghi";
bool: true
rascal>"abc" != "abc";
bool: false
3.3.8. String Slice
Retrieve a slice of a string.
3.3.9. Exp_{1} [ Exp_{2} .. Exp_{4}]
3.3.10. Exp_{1} [ Exp_{2} , Exp3 .. Exp_{4}]
where Exp_{2} and Exp_{4} are optional.
Exp_{1} 
Exp_{2} 
Exp_{3} 
Exp_{4} 
Exp_{1} [ Exp_{2} .. Exp_{4} ] or Exp_{1} [ Exp_{2} , Exp_{3} .. Exp_{4}] 






A String slice is similar to a list List Slice and uses the integer values of Exp_{2} and Exp_{4} to determine the begin
(inclusive) and end
(exclusive)
of a slice from the string value S of Exp_{1}. Negative indices count from the end of the string backwards.
Using the second form, an extra index Exp_{3} is given that determines the
index of the second element in the slice and establishes the step
between
successive elements in the slice. The default step
is 1.
If end
is smaller than begin
, the slice is constructed backwards.
Let Len
be the length of S and let N_{2}, N_{3} and N_{4} be the respective values of the expressions
Exp_{2}, Exp_{2} and Exp_{2} when they are present.
The slice parameters begin
, end
, and step
are determined as follows:

Exp_{2}:

If Exp_{2} is absent, then
begin = 0
. 
Otherwise, if N_{2} >= 0 then
begin = N_{2}
elsebegin = N_{2} + Len
.


Exp_{4}:

If Exp_{4} is absent, then
end = Len
. 
Otherwise, if N_{4} >= 0, then
end = N_{4}
elseend = N_{4} + Len
.


Exp_{3}:

If Exp_{3} is absent, then if
begin < end
thenstep = 1
elsestep = 1
. 
Otherwise, if
begin < end
, thenstep = N_{3}  begin
elsestep = begin  N_{3}
.

Now, the constraints 0 ⇐ begin < Len
and 0 < end < Len
should hold,
otherwise the exception IndexOutOfBounds
is thrown.
The slice consists of the elements S[begin]
, S[begin+step]
, S[end  step]
.
When begin >= end
, the elements are listed in reverse order.
Consider the string S = "abcdefghi";
(with size 9) as running example.
Here is a view on L that will help to correlate positive and negative indices:
i 
0  1  2  3  4  5  6  7  8 












9 
8 
7 
6 
5 
4 
3 
2 
1 
Some common use cases (with begin
⇐ end
):
Slice  Means: 


characters with indices 

characters with indices 

characters with indices from the beginning through 

the whole list 

last element of the string 

the last two characters of the string 

all characters except the last two. 
Let’s put this into practice now.
rascal>S = "abcdefghi";
str: "abcdefghi"
Slices with begin < end
rascal>S[1..3];
str: "bc"
rascal>S[1..]; // empty end => end of string
str: "bcdefghi"
rascal>S[..3]; // empty begin => first character of string
str: "abc"
rascal>S[..]; // both empty => whole string
str: "abcdefghi"
Slices with begin >= end
rascal>S[3..1]; // slice contains characters with indices 3 and 2 (in that order)
str: "dc"
rascal>S[3..3]; // empty slice when begin == end
str: ""
Slices with negative begin or end:
rascal>S[2..2]; // equivalent to S[2..7]
str: "cdefg"
rascal>S[2..7];
str: "cdefg"
rascal>S[4..2]; // equivalent to S[5..7]
str: "fg"
rascal>S[5..7];
str: "fg"
Slices with an explicit second index:
rascal>S[1,3..6];
str: "bdf"
rascal>S[5,3..];
str: "fdb"
Explore error cases:
rascal>S[..10];
str: "abcdefghi"
rascal>S[1..20];
str: "bcdefghi"
3.3.11. String Subscription
Retrieve a substring via its index.
Exp_{1} [ Exp_{2} ]
Exp_{1} 
Exp_{2} 
Exp_{1} [ Exp_{2} ] 




String subscription uses the integer value of Exp_{2} as index in the string value of Exp_{1}.
The value of Exp_{2} should be greater or equal 0 and less than the number of characters in the string.
If this is not the case, the exception IndexOutOfBounds
is thrown.
Introduce a string, assign it to S and retrieve the element with index 1:
rascal>S = "abc";
str: "abc"
rascal>S[1];
str: "b"
Explore an error case:
rascal>S[5];
prompt:///(2,1,<1,2>,<1,3>): IndexOutOfBounds(5)
at $shell$(prompt:///(0,5,<1,0>,<1,5>))
ok
3.4. Tuple
Tuple values.
< Exp_{1}, Exp_{2}, … >
Exp_{1} 
Exp_{2} 
…  < Exp_{1}, Exp_{2}, … > 


T_{2} 
… 

A tuple is a sequence of elements with the following properties:

Each element in a tuple (may) have a different type.

Each element of a tuple may have a label that can be used to select that element of the tuple.

Each tuple is fixedwidth, i.e., has the same number of elements.
Tuples are represented by the type tuple[T_{1} L_{1}, T_{2} L_{2}, …]
,
where T_{1}, T_{2}, … are arbitrary types and L_{1}, L_{2}, … are optional labels.
The following operators are provided for tuples:

Tuple Concatenation: Concatenate two tuple values.

Tuple Equal: Equality operator on tuple values.

Tuple FieldSelection: Select a field from a tuple by its field name.

Tuple GreaterThan: Greater than operator on tuple values.

Tuple GreaterThanOrEqual: Greater than or equal operator on tuple values.

Tuple LessThan: Less than operator on tuple values.

Tuple LessThanOrEqual: Less than or equal operator on tuple values.

Tuple NotEqual: Not equal operator on tuple values.

Tuple Subscription: Retrieve a tuple field by its index position.
rascal>tuple[str first, str last, int age] P = <"Jo","Jones",35>;
tuple[str first,str last,int age]: <"Jo","Jones",35>
rascal>P.first;
str: "Jo"
rascal>P.first = "Bo";
tuple[str first,str last,int age]: <"Bo","Jones",35>
3.4.1. Tuple Concatenation
Concatenate two tuple values.
Exp_{1} + Exp_{2}
Exp_{1} 
Exp_2 
Exp_{1} > Exp_2 




Returns a tuple consisting of the concatenation of the tuple elements of Exp_{1} and Exp_{2}.
rascal><"abc", 1, 2.5> + <true, "def">;
tuple[str,int,real,bool,str]: <"abc",1,2.5,true,"def">
3.4.2. Tuple Equal
Equality operator on tuple values.
Exp_{1} == Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} == Exp_{2} 




Yields true
if both tuples are identical and false
otherwise.
rascal><1, "abc", true> == <1, "abc", true>;
bool: true
3.4.3. Tuple FieldSelection
Select a field from a tuple by its field name.
Exp . Name
Exp 
Name 
Exp . Name 




Field selection applies to tuples with named elements. Exp should evaluate to a tuple with field Name and returns the value of that field. Name stands for itself and is not evaluated.
rascal>tuple[int key, str val] T = <1, "abc">;
tuple[int key,str val]: <1,"abc">
rascal>T.val;
str: "abc"
3.4.4. Tuple GreaterThan
Greater than operator on tuple values.
Exp_{1} > Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} > Exp_{2} 




Yields true
if

both tuples are not equal, and

the leftmost element in the tuple value of Exp_{1} that differs from the corresponding element in the tuple value of Exp_{2} is greater than that element in Exp_{2}.
Otherwise the result if false
.
rascal><1, "def", true> > <1, "abc", true>;
bool: true
3.4.5. Tuple GreaterThanOrEqual
Greater than or equal operator on tuple values.
Exp_{1} >= Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} >= Exp_{2} 




Yields true
if

both tuples are equal, or

the leftmost element in the tuple value of Exp_{1} that differs from the corresponding element in the tuple value of Exp_{2} is greater than that element in Exp_{2}.
Otherwise the result if false
.
rascal><1, "abc", true> > <1, "abc", true>;
bool: false
rascal><1, "def", true> > <1, "abc", true>;
bool: true
3.4.6. Tuple LessThan
Less than operator on tuple values.
Exp_{1} < Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} < Exp_{2} 




Yields true
if

both tuples are not equal, and

the leftmost element in the tuple value of Exp_{1} that differs from the corresponding element in the tuple value of Exp_{2} is less than that element in Exp_{2}.
Otherwise the result if false
.
rascal><1, "abc", true> < <1, "def", true>;
bool: true
3.4.7. Tuple LessThanOrEqual
Less than or equal operator on tuple values.
Exp_{1} ⇐ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐ Exp_{2} 




Yields true
if

both tuples are equal, or

the leftmost element in the tuple value of Exp_{1} that differs from the corresponding element in the tuple value of Exp_{2} is less than that element in Exp_{2}.
Otherwise the result if false
.
rascal><1, "abc", true> <= <1, "abc", true>;
bool: true
rascal><1, "abc", true> <= <1, "def", true>;
bool: true
3.4.8. Tuple NotEqual
Not equal operator on tuple values.
Exp_{1} != Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} != Exp_{2} 




Yields true
if both tuples are not identical and false
otherwise.
rascal><1, "abc", true> != <1, "abc">;
bool: true
rascal><1, "abc", true> != <1, "abc", true>;
bool: false
3.4.9. Tuple Subscription
Retrieve a tuple field by its index position.
Exp_{1} [ Exp_{2} ]
Subscription retrieves the tuple element with index Exp_{2} from the tuple value of Exp_{1}.
Introduce a tuple, assign it to T and retrieve the element with index 0:
rascal>T = <"mon", 1>;
tuple[str,int]: <"mon",1>
rascal>T[0];
str: "mon"
3.5. Value
Values of type value
.
value
Value stands for all possible Rascal values and is represented by the type value
.
This type is a container for all other types and does not have any values itself.
The following operators are provided for values:

Value Conditional: Conditional expression on values.

Value Equal: Equal operator on values.

Value GreaterThan: Greater than operator on values.

Value GreaterThanOrEqual: Greater than or equal operator on values.

Value LessThan: Less than operator on values.

Value LessThanOrEqual: Less than or equal operator on values.

Value NotEqual: Not equal operator on values.
3.5.1. Value Conditional
Conditional expression on values.
Exp_{1} ? Exp_{2} : Exp_{3}
Exp_{1} 
Exp_{2} 
Exp_{3} 
Exp_{1} ? Exp_{2} : Exp_{3} 





Yields the value of Exp_{2} if the value of Exp_{1} is true
and the value of Exp_{3} otherwise.
The result type is the least upper bound (also known as lub
, see Static Typing) of the types of Exp_{2} and Exp_{3}.
rascal>( 3 > 2 ) ? 30 : 40;
int: 30
rascal>( 3 < 2 ) ? "abc" : {3, 4};
set[int]: {3,4}
3.5.2. Value Equal
Equal operator on values.
Exp_{1} == Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} == Exp_{2} 




Yields true
if both arguments are identical and false
otherwise.
Introduce two variables X
, Y
and Z
and force them to be of type value
:
rascal>value X = "abc";
value: "abc"
rascal>value Y = "abc";
value: "abc"
rascal>value Z = 3.14;
value: 3.14
Now compare X
and Y
for equality:
rascal>X == Y;
bool: true
and X
and Z
:
rascal>X == Z;
bool: false
3.5.3. Value GreaterThan
Greater than operator on values.
Exp_{1} > Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} > Exp_{2} 




By brute force, a total less than operator between two values V_{1} and V_{2} of arbitrary types T_{1} and T_{2} is defined:

If the types T_{1} and T_{2} can be compared then V_{1} less than V_{2} is used.

Otherwise values are ordered according their type name, for instance,
int
is smaller thanlist
, andmap
is smaller thanrel
.
Greater than yields true
if the value of Exp_{2} is strictly less
than (according to the ordering defined above) the value of Exp_{1}, and false
otherwise.
Introduce two variables X
, Y
and Z
and force them to be of type value
:
rascal>value X = "def";
value: "def"
rascal>value Y = "abc";
value: "abc"
rascal>value Z = 3.14;
value: 3.14
Now compare X
and Y
:
rascal>X > Y;
bool: true
and X
and Z
:
rascal>X > Z;
bool: false
3.5.4. Value GreaterThanOrEqual
Greater than or equal operator on values.
Exp_{1} >= Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} >= Exp_{2} 




By brute force, a total less than operator between two values V_{1} and V_{2} of arbitrary types T_{1} and T_{2} is defined:

If the types T_{1} and T_{2} can be compared then V_{1} less than V_{2} is used.

Otherwise values are ordered according their type name, for instance,
int
is smaller thanlist
, andmap
is smaller thanrel
.
Greater than or equal yields true
if the value of Exp_{2} is strictly less
than (according to the ordering defined above) the value of Exp_{1} or if both values are equal, and false
otherwise.
Introduce two variables X
, Y
and Z
and force them to be of type value
:
rascal>value X = "def";
value: "def"
rascal>value Y = "abc";
value: "abc"
rascal>value Z = 3.14;
value: 3.14
Now compare X
and Y
:
rascal>X >= Y;
bool: true
and X
and Z
:
rascal>X >= Z;
bool: false
3.5.5. Value LessThan
Less than operator on values.
Exp_{1} < Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} < Exp_{2} 




By brute force, a total less than operator between two values V_{1} and V_{2} of arbitrary types T_{1} and T_{2} is defined:

If the types T_{1} and T_{2} can be compared then V_{1} less than V_{2} is used.

Otherwise values are ordered according their type name, for instance,
int
is smaller thanlist
, andmap
is smaller thanrel
.
Less than yields true
if the value of Exp_{1} is strictly less
than (according to the ordering defined above) the value of Exp_{2}, and false
otherwise.
Introduce two variables X
, Y
and Z
and force them to be of type value
:
rascal>value X = "abc";
prompt:///(6,9,<1,6>,<1,15>): Redeclared variable: X
Advice: http://tutor.rascalmpl.org/Errors/Static/RedeclaredVariable/RedeclaredVariable.html
ok
rascal>value Y = "def";
prompt:///(6,9,<1,6>,<1,15>): Redeclared variable: Y
Advice: http://tutor.rascalmpl.org/Errors/Static/RedeclaredVariable/RedeclaredVariable.html
ok
rascal>value Z = 3.14;
prompt:///(6,8,<1,6>,<1,14>): Redeclared variable: Z
Advice: http://tutor.rascalmpl.org/Errors/Static/RedeclaredVariable/RedeclaredVariable.html
ok
WARNING: unexpected errors in the above SHELL example. Documentation author please fix! Now compare X
and Y
:
rascal>X < Y;
bool: false
and X
and Z
:
rascal>X < Z;
bool: false
3.5.6. Value LessThanOrEqual
Less than or equal operator on values.
Exp_{1} ⇐ Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} ⇐ Exp_{2} 




By brute force, a total less than operator between two values V_{1} and V_{2} of arbitrary types T_{1} and T_{2} is defined:

If the types T_{1} and T_{2} can be compared then V_{1} less than V_{2} is used.

Otherwise values are ordered according their type name, for instance,
int
is smaller thanlist
, andmap
is smaller thanrel
.
Less than or equal yields true
if the value of Exp_{1} is strictly less
than (according to the ordering defined above) the value of Exp_{2} or if both values are equal, and false
otherwise.
Introduce two variables X
, Y
and Z
and force them to be of type value
:
rascal>value X = "abc";
value: "abc"
rascal>value Y = "def";
value: "def"
rascal>value Z = 3.14;
value: 3.14
Now compare X
and Y
:
rascal>X <= Y;
bool: true
and X
and Z
:
rascal>X <= Z;
bool: false
3.5.7. Value NotEqual
Not equal operator on values.
Exp_{1} != Exp_{2}
Exp_{1} 
Exp_{2} 
Exp_{1} != Exp_{2} 




Yields true
if both arguments are not identical and false
otherwise.
Introduce two variables X
, Y
and Z
and force them to be of type value
:
rascal>value X = "abc";
value: "abc"
rascal>value Y = "abc";
value: "abc"
rascal>value Z = 3.14;
value: 3.14
Now compare X
and Y
for inequality:
rascal>X != Y;
bool: false
and X
and Z
:
rascal>X != Z;
bool: true
3.6. Void
Values of type void
.
void
Void stands for nothing and is represented by the type void
.
It is a type without any values.
4. Operators
The Rascal operators.
An operator expression consists of an operator and one or more operands. The evaluation order of the operands depends on the operator. The operator is applied to the operands and the resulting value (or values in some cases) is the result of the operator expression.
All operators are summarized in the following table. They are listed from highest precedence to lowest precedence. In other words, operators listed earlier in the table bind stronger.
Operator  See  Short Description 


Location, DateTime, Tuple, [RelationFieldSelection.Relation], 
Select named field from structured value 

Change value of named field of structured value 


Select fields from relation or structured value 


Returns true if and only if the constructor name of the value produced by Exp is equal to Name 


Returns true if and only if the constructor (node or parse tree) of the value produced by Exp has any field labeled Name 


Retrieve values for given index/key from list, map, tuple or relation. 


Retrieve a slice from a list, string, or node. 


Test whether an expression has a defined value 


Negate a Boolean value 


Negation of numbers 


Transitive closure on relation or list relation 


Reflexive transitive closure on relation or list relation 


Value of annotation Name of Exp's value 


Assign value of Exp_{2} to annotation Name of Exp_{1}'s value 


Exp_{1} and Exp_{2} should evaluate to a relation or map; return their composition. Note: the letter "o" is thus a keyword 


Divide two numbers 


Remainder on numbers 


Multiply numbers; product of list, set, or relation 


Intersection of list, set (including relation), or map 


Number, String, List Concatenation, List Insert,List Append, Tuple Concatenation, Set, Map, Location 
Add numbers; concatenate string, list or tuple; union on set (including relation), or map; concatenate location and string 

Subtract numbers; difference of list, set (including relation), or map 


Join on relation 


Membership test for element in list, map, set (including relation) 


Negated membership test for element in list, map, set (including relation) 


Less than or equal on all values 


Less than on all values 


Greater than or equal on all values 


Greater than on all values. 


Pattern matches value of expression 


Pattern does not match value of expression 


Equality on all values 


Inequality on all values 


Value of expression when it is defined, otherwise alternative value 


Conditional expression for all types 


Implication on Boolean values 


Equivalence on Boolean values 


And on Boolean values 


Or on Boolean values 
4.1. Field Assignment
Assignment to a field of a tuple or datatype.
Exp_{1} [ Name = Exp_{2} ]
Exp_{1} should evaluate to a tuple or datatype with a field Name; assign the value of Exp_{2} to that field
Field assignment applies to all values that have named components like tuples and relations with named elements, data types, and locations. Field assignment returns a new value in which the named component has been replaced by a new value. Name stands for itself and is not evaluated.
rascal>tuple[int key, str val] T = <1, "abc">;
tuple[int key,str val]: <1,"abc">
rascal>T[val = "def"];
tuple[int key,str val]: <1,"def">
rascal> T;
tuple[int key,str val]: <1,"abc">
Observe that field assignment creates a new value with an updated field. The old value remains unchanged as can be seen from the unchanged value of T in the above example.
4.2. Field Projection
Projection of tuple.
Exp < Field_{1}, Field_{2} … >
Exp should evaluate to a tuple or relation, and Field_{i} should be a field name or an integer constant that refers to elements in the order in which they occur in the original value (counting from 0).
Suppose we have a relation with traffic information that records the name of the day, the day number, and the length of the traffic jams at that day.
rascal>rel[str day, int daynum, int length] Traffic =
>>>>>>>{<"mon", 1, 100>, <"tue", 2, 150>, <"wed", 3, 125>,
>>>>>>> <"thur", 4, 110>, <"fri", 5, 90>};
rel[str day,int daynum,int length]: {
<"thur",4,110>,
<"mon",1,100>,
<"fri",5,90>,
<"wed",3,125>,
<"tue",2,150>
}
rascal>Traffic<length,daynum>;
rel[int length,int daynum]: {
<110,4>,
<125,3>,
<90,5>,
<150,2>,
<100,1>
}
rascal>Traffic<2,day>;
rel[int length,str day]: {
<110,"thur">,
<125,"wed">,
<90,"fri">,
<150,"tue">,
<100,"mon">
}
Field projection thus selects parts from a larger value that has a fixed number of parts. The selection is based on position and not on value and can be used to completely reorder or remove the parts of a larger value.
5. Call
Function call.
Name ( Exp_{1}, Exp_{2}, … )
Exp_{1} 
Exp_{2} 
…  Name ( Exp_{1}, Exp_{2}, … ) 



… 
Determined by Name, T_{i} and function declarations 
First, the actual parameter expressions Exp_{i} are evaluated resulting in values V_{i}. Based on Name and the argument types T_{i}, the identity of the function to be called is determined.
The values V_{i} are bound to the formal parameter names of the declared functions and the function body is executed. The value returned by the function is used as value of the function call.
A constructor call has identical syntax to that of a function call, see Constructor,
See Function Declaration for more details about function declarations.
Describe keyword parameters. 
First declare a function square
with argument n that returns n^2:
rascal>int square(int n) { return n * n; }
int (int): function(prompt:///(0,35,<1,0>,<1,35>))
Next call square
. This results in the following steps:

Based on the name
square
and the int argument 12 we identify the function to be called (= the functionsquare
we just defined). 
Compute the value of the actual parameter (= 12).

Bind the formal parameter
n
to the actual value 12. 
Execute the body of
square
. 
The return value of square is the vale of the call:
rascal>square(12);
int: 144
6. Comprehensions
Comprehensions provide a concise notation to conditionally generate new values.
Comprehensions are defined for the following types:

list
, see List Comprehension, 
set
, see Set Comprehension, 
map
, see Map Comprehension.
The syntax varies slightly for each type, but comprehensions have the following common elements:

A generator can come in two flavours:

an enumerator that generates all the values in some subject value.

a filter that performs an arbitrary test on previously generated values.


One or more contributing expressions that are added to the list, set or map that is being constructed.
The contributing expressions are evaluated for all possible values of the enumerators that are not excluded by a test. When a filter fails, execution continues with the preceding enumerator (if any).
Each enumerator may introduce new variables that can be used in subsequent generators as well as in the contributing expressions. A generator can use the variables introduced by preceding generators.
A list comprehension:
rascal>[ 3 * X  int X < [1 .. 10] ];
list[int]: [3,6,9,12,15,18,21,24,27]
A list comprehension with a filter:
rascal>[ 3 * X  int X < [1 .. 10], X > 5];
list[int]: [18,21,24,27]
A list comprehension with multiple contributing expressions:
rascal>[X, X * X  int X < [1, 2, 3, 4, 5], X >= 3];
list[int]: [3,9,4,16,5,25]
A set comprehension with a filter:
rascal>{X  int X < {1, 2, 3, 4, 5}, X >= 3};
set[int]: {5,3,4}
A set comprehension that constructs a relation:
rascal>{<X, Y>  int X < {1, 2, 3}, int Y < {2, 3, 4}, X >= Y};
rel[int,int]: {
<2,2>,
<3,3>,
<3,2>
}
rascal>{<Y, X>  <int X, int Y> < {<1,10>, <2,20>}};
rel[int,int]: {
<10,1>,
<20,2>
}
Introduce a map of fruits
and use a map comprehension to filter fruits with an associated value larger than 10:
rascal>fruits = ("pear" : 1, "apple" : 3, "banana" : 0, "berry" : 25, "orange": 35);
map[str, int]: ("banana":0,"pear":1,"orange":35,"berry":25,"apple":3)
rascal>(fruit : fruits[fruit]  fruit < fruits, fruits[fruit] > 10);
map[str, int]: ("orange":35,"berry":25)
See List Comprehension, Set Comprehension, or Map Comprehension for more examples.
6.1. Enumerator
Enumerate all values in a given subject value.
Pattern ← Exp
An enumerator generates all the values in a given subject value.
For elementary types (bool
, int
, real
, num
, loc
, datetime
, str
) this is just a singleton.
For composite types (list
, set
, map
, tuple
, rel
, node
) the values of their elements,
respectively, their direct children are enumerated. An enumerator is evaluated as follows:

Expression Exp is evaluated and may have an arbitrary value V.

The elements of V are enumerated one by one.

Each element value is matched against the pattern Pattern. There are two cases:

The match succeeds, any variables in Pattern are bound, and the next generator in the comprehension is evaluated. The variables that are introduced by an enumerator are only available to generators that appear later (i.e., to the right) in the comprehension. When this enumerator is the last generator in the comprehension, the contributing expressions of the comprehension are evaluated.

The match fails, no variables are bound. If V has more elements, a next element is tried. Otherwise, a previous generator (i.e., to the left) is tried. If this enumerator is the first generator in the comprehension, the evaluation of the comprehension is complete.

Type information is used to check the validity of an enumerator and guard you against mistakes. An impossible enumerator like
int N < {"apples", "oranges"}
will be flagged as an error since the pattern can never match.
Here are some examples of enumerators:

int N ← {1, 2, 3, 4, 5}
. 
str K ← KEYWORDS
, whereKEYWORDS
should evaluate to a value ofset[str]
. 
<str K, int N> ← {<"a",10>, <"b",20>, <"c",30>}
. 
<str K, int N> ← FREQUENCIES
, whereFREQUENCIES
should evaluate to a value of typerel[str,int]
. 
<str K, 10> ← FREQUENCIES
, will only generate pairs with10
as second element. 
int N ← 17
, will only generate the value17
.
Here are examples of enumerators in action:
rascal>[ N * N  int N < [1, 2, 3, 4, 5] ];
list[int]: [1,4,9,16,25]
rascal>{<N, K>  <str K, int N> < {<"a",10>, <"b",20>, <"c",30>}};
rel[int,str]: {
<10,"a">,
<20,"b">,
<30,"c">
}
6.2. Filter
Filter values in a List Comprehension], Set Comprehension or Map Comprehension.
Exp
Exp 


A filter is a booleanvalued expression.
If the evaluation of the filter gives true
this indicates that the current combination of generated values up
to this filter is still desired and execution continues with subsequent generators.
If the evaluation gives false
this indicates that the current combination of values is undesired,
and that another combination should be tried by going back to the previous generator.
Adding a filter to a comprehension, may restrict the values that are included in the result of the comprehension:
rascal>[ X * X  int X < [1, 2, 3, 4, 5, 6] ];
list[int]: [1,4,9,16,25,36]
rascal>[ X * X  int X < [1, 2, 3, 4, 5, 6], X % 3 == 0 ];
list[int]: [9,36]
Filters can also be applied to values produced by several generators:
rascal>[<X, Y>  int X < [0 .. 10], int Y < [0 .. 10], X + Y == 10]
lrel[int,int]: [
<1,9>,
<2,8>,
<3,7>,
<4,6>,
<5,5>,
<6,4>,
<7,3>,
<8,2>,
<9,1>
]
7. Concrete Syntax
Concrete syntax is a notation for patterns that match parse trees and expressions that generate them.

(Nonterminal) `sentence`

`
sentence
`
where each sentence is a string over the language generated from Nonterminal
. This language is extended in the following way. Each nonterminal reachable X
from Nonterminal has an added alternative to allow nested Rascal Patterns inside of concrete syntax fragments:

syntax X = "<" Pattern p ">";
A concrete syntax fragment allows the programmer to write patterns and expressions in the language that is currently analyzed, transformed or generated. The Concrete Syntax feature is derived from Syntax Definitions. For any nonterminal defined in a Syntax Definition, you may use Concrete Syntax to match or generate its parse trees.

Easy notation for complex structures

Since Rascal currently has no typechecker, the disambiguation of concrete syntax fragments is done heuristically which may lead to surprises.

The disambiguation of embedded concrete syntax fragments may change in the near future.
8. Reducer
Reduce generated values to a single value.
( InitExp  RedExp  Gen_{1}, Gen_{2}, … )
A reducer resembles the fold function found in most functional languages.
A reducer is equivalent to the following code:
it = InitExp; (1)
for(Gen_{1}, Gen_{2}, ... ) (2)
it = RedExp; (3)
it; (4)
and is executed as follows:
1  A fresh variable it is initialized with InitExp.
We call the variable it since we use it to initialize the reducer, to make changes to it ,
and to return it as result. 
2  A for loop iterates over all values produced by the generators Gen_{1} , Gen_{2} , … . 
3  In the body of the loop, variable it is updated to reflect a new reduced value.
Note that it itself and variables introduced in Gen_{1}, Gen_{2}, … may occur in RedExp. 
4  The value of it is the result of the reducer. 
rascal>L = [1, 3, 5, 7];
list[int]: [1,3,5,7]
rascal>(0  it + e  int e < L);
int: 16
rascal>(1  it * e  int e < L);
int: 105
9. Statement as Expression
Statements that have a value and can be used as expressions.
Several forms of statements produce a value and can be used as expression. This is further explained in the sections for the relevant statements, see If, While, Do and For.
It is likely that the design of Rascal will evolve into completely merging expressions and statements.
10. Visit
Visit the elements in a tree or value.
Strategy visit ( Exp ) {
case PatternWithAction_{1};
case PatternWithAction_{2};
...
default: ...
}
Visiting, recursively traversing, the nodes in a deeply nested datastructure is a very common task in the EASY domain. In many cases (but certainly not all) this datastructure is a syntax tree of some source code file and the nodes correspond to expressions or statements.
The visit expression/statement allows to focus on the points of interest in the datastructure while automating the search over the other parts for the programmer.
Computing metrics or refactoring are examples of tasks that require a tree visit. There are three frequently occurring scenarios:

Accumulator: traverse the tree and collect information (fold).

Transformer: traverse the tree and transform it into another tree (map).

Accumulating Transformer: traverse the tree, collect information and also transform the tree.
The visit expression in Rascal can accommodate all these (and more) use cases.
Given a subject term (the current value of Exp) and a list of cases (consisting of a sequence of [Pattern with Action]s, it traverses the term. Depending on the precise actions it may perform replacement (mimicking a transformer), update local variables (mimicking an accumulator) or a combination of these two (accumulating transformer). If any of the actions contains an Insert statement, the value of the visit expression is a new value that is obtained by successive insertions in the subject term by executing one or more cases. Otherwise, the original value of the subject term is returned.
The visit expression is optionally preceded by one of the following strategy indications that determine the traversal order of the subject:

topdown
: visit the subject from root to leaves. 
topdownbreak
: visit the subject from root to leaves, but stop at the current path when a case matches. 
bottomup
: visit the subject from leaves to root (this is the default). 
bottomupbreak
: visit the subject from leaves to root, but stop at the current path when a case matches. 
innermost
: repeat a bottomup traversal as long as a case matches. 
outermost
: repeat a topdown traversal as long as a case matches.
The execution of the cases has the following effect:

A PatternWithAction of the form
Pattern ⇒ Exp
replaces the current subtree of the subject by the value of Exp. Note that a copy of the subject is created at the start of the visit statement and all replacements are made in this copy. As a consequence, modifications made during the visit cannot influence matches later on. The modified copy of the subject is ultimately returned by the visit expression. 
A PatternWithAction of the form
Pattern : Statement
executesStatement
and this should lead to one of the following:
Execution of an Insert statement of the form
insert Exp_{2}
. The value of Exp_{2} replaces the subtree of the subject that is currently being visited. Once again, this modification takes place in a copy of the original subject (see above). Note that:
An insert statement may only occur in a PatternWithAction in a visit expression or a rule.

Pattern ⇒ Exp
is equivalent toPattern : insert Exp;
.


Execution of a Fail statement: the next case is tried.

Execution of a Return statement that returns a value from the enclosing function.

The precise behaviour of the visit expression depends on the type of the subject:

For type node or ADT, all nodes of the tree are visited (in the order determined by the strategy). Concrete patterns and abstract patterns directly match tree nodes. Regular expression patterns match only values of type string.

For other structured types (list, set, map, tuple, rel), the elements of the structured type are visited and matched against the cases. When inserts are made, a new structured value is created. In these cases a strategy does not have any effect.
Visit a value and increment a counter for pattern leaf(int N)
matches:
visit(t) {
case leaf(int N): c = c + N;
};
Replace all values that match the pattern red(l, r)
:
visit(t) {
case red(l, r) => green(l, r)
};
Do a bottomup visit of an expression and apply the function simp
to each subexpression:
bottomup visit(e){
case Exp e1 => simp(e1)
}
More examples can, for instance, be found in Recipes, see ColoredTrees, WordReplacement, CountConstructors, and Derivative.
10.1. Pattern With Action
A pattern with an associated action that is executed on a successful match.

Pattern ⇒ Exp

Pattern: Statement
Patterns can be used in various contexts, but a common context is a PatternWithAction, which in its turn, may be used in various statements such Switch and Visit.
There are two variants as listed above:

When the subject matches Pattern, the expression Exp is evaluated and the subject is replaced with the result.

When the subject matches Pat, the Statement is executed. More statements can be executed by including them in a Block.
In Switch statements, only the form Pattern : Statement
is allowed.
When the subject matches Pattern, the Statement is executed and the execution of the switch statement is complete.
However, when a fail statement is executed in Statement further alternatives of
Pattern are tried. If no alternatives remain, PatternWithAction as a whole fails and subsequent cases of
the switch statement are tried.
In Visit expressions, the form Pattern ⇒ Exp
describes subtree replacement:
the current subtree of the subject of the visit expression is replaced by the value of Exp.
The form Pattern : Statement
is as described for switch statements, with the addition that execution of an
Insert statement will replace the current subtree. After both success or failure of the PatternWithAction,
the traversal of the subject continues.
Two examples of variant 1 (replacement):
case red(CTree l, CTree r) => red(r,l)
case red(l, r) => green(l, r)
Three examples of variant 2 (Statement):
case /Leila/: println("The topic is Starwars");
case red(_, _): println("A red root node");
case red(_,_): c = c + 1;
The action may also be a Block:
case red(_,_): { c = c + 1; println("c = <c>"); }
Statements
All Rascal statements.
The following statements are available:

Append: Append an element to the list value produced by various loop statements.

Assert: An executable assertion.

Assignment: Assign a value to a variable or more complex data structure.

Constructor: Assign to constructor.

Field: Assign to a field of a tuple, relation or datatype.

IsDefined: Assign but replace if value is not defined.

Multiple: Assign to multiple assignables.

Slice: Assign to a slice of a list or string.

Subscription: Assign a single element of a structured value.

Variable: Assign to a variable.

Block: Group statements into a block.

Break: End the execution of a while, do or for loop.

Continue: Continue with the next iteration of while, do or for loop.

Do: Repeat statements while condition holds.

Fail: Let the current alternative of a pattern match fail.

For: For loop.

If: Conditional statement.

Return: Return a value as result of a [Function].

Solve: Solve a set of equalities by fixedpoint iteration.

Test: Test statement (deprecated).

Try Catch: Try to execute a statement and catch resulting exceptions.

While: While loop.
11. Append
Append an element to the list value produced by various loop statements.
append Exp
An append statement may only occur in the body of a While, Do or For statement. It appends the value of Exp to the resulting list value of the loop construct in which it occurs.
rascal>for(int i < [1..5]) append i*i;
list[int]: [1,4,9,16]
rascal>L = for(int i < [1..5]) append i*i;
list[int]: [1,4,9,16]
12. Assert
An executable assertion.

assert Exp_{1}

assert Exp_{1} : Exp_{2}
Exp_{1} 
Exp_{2} 



An assert statement may occur everywhere where a declaration is allowed. It has two forms:
An assert statement consists of a Boolean expression Exp_{1} and an optional string expression Exp_{2} that serves as a identifying message for this assertion.
When Exp_{1} evaluates to false
, an AssertionFailed
exception is thrown.
rascal>assert 1==2 : "is never true";
prompt:///(14,15,<1,14>,<1,29>): AssertionFailed("is never true")
at $shell$(main://$shell$)
ok
rascal>int div(int x, int y) {
>>>>>>> assert y != 0 : "y must be nonzero";
>>>>>>> return x / y;
>>>>>>>}
int (int, int): function(prompt:///(0,81,<1,0>,<4,1>))
rascal>div(4,0);
prompt:///(42,20,<2,18>,<2,38>): AssertionFailed("y must be nonzero")
at div(prompt:///(0,81,<1,0>,<4,1>))
at $shell$(prompt:///(0,9,<1,0>,<1,9>))
ok
13. Assignment
Assign a value to a variable or more complex data structure.
Assignable AssignmentOp Exp
where AssignmentOp may be one of =
, +=
, =
, *=
, /=
, or ?=
.
An Assignable is one of the following:

Var

Assignable [ Exp ]

Assignable [ Exp .. Exp ]

Assignable [ Exp, Exp .. Exp ]

Assignable . Name

< Assignable, Assignable, …, Assignable >

Assignable ? Exp

Assignable @ Name

Name ( Assignable, Assignable, … )
The purpose of an assignment is to assign a new value to a simple variable or to an element of a more complex data structure.
The standard assignment operator is =
.
The other assignment operators can be expressed as abbreviations for the standard assignment operator.
Assignment Operator  Equivalent to 













An assignable is either a single variable, (the base variable), optionally followed by subscriptions, slices or field selections. The assignment statement always results in assigning a completely new value to the base variable. We distinguish the following forms of assignment:

Constructor: Assign to constructor.

Field: Assign to a field of a tuple, relation or datatype.

IsDefined: Assign but replace if value is not defined.

Multiple: Assign to multiple assignables.

Slice: Assign to a slice of a list or string.

Subscription: Assign a single element of a structured value.

Variable: Assign to a variable.
13.1. Annotation
Assign to an annotation. This feature is deprecated.
The value V of Assignable is determined and should be of a type that has an annotation Name. A new value V' is created that is a copy of V but with the value of annotation Name replaced by the value of Exp. V' is assigned to Assignable. See Annotation Declaration.
Examples have been removed since this feature is deprecated.
13.2. Constructor
Assign to constructor.
First the value Exp is determined and should be a data value of the form Name(V_{1}, V_{2}, …, V_{n}).
Next the assignments `Assignable_{i} = V_{i}
are performed for 1 ⇐ i ⇐ n.
rascal>data FREQ = wf(str word, int freq);
ok
rascal>W = wf("rascal", 1000);
FREQ: wf("rascal",1000)
rascal>wf(S, I) = W;
FREQ: wf("rascal",1000)
rascal>S;
str: "rascal"
rascal>I;
int: 1000
13.3. Field
Assign to a field of a tuple, relation or datatype.
The value V
of Assignable is determined and should be of a type that has a field Name.
The value of that field is replaced in V by the value of Exp resulting in a new value V' that is assigned to Assignable.
rascal>data FREQ = wf(str word, int freq);
ok
rascal>W = wf("rascal", 1000);
FREQ: wf("rascal",1000)
rascal>W.freq = 100000;
FREQ: wf("rascal",100000)
13.4. IsDefined
Assign but replace if value is not defined.
First the value of Exp_{1} is determined and if that is defined it is assigned to Assignable. Otherwise, the value of Exp_{2} is assigned to Assignable. Values which can be undefined are values in Maps where the key is not set or values of Annotations which have not been set yet.
No other values can be used in an undefined state, so the ? operator does not make sense on undefined or uninitialized variables for example.
rascal>M = ("Andy": 1, "Brian" : 2);
map[str, int]: ("Andy":1,"Brian":2)
Using an isDefined
assignable can we increment a nonexisting entry:
rascal>M["SomebodyElse"] ? 0 += 1;
map[str, int]: ("Andy":1,"Brian":2,"SomebodyElse":1)
rascal>M["SomebodyElse"];
int: 1
And if we increment an existing entry the ? has no effect:
rascal>M["Andy"] ? 0 += 1;
map[str, int]: ("Andy":2,"Brian":2,"SomebodyElse":1)
rascal>M["Andy"]
int: 2
13.5. Multiple
Assign to multiple assignables.
First the value Exp is determined and should be a tuple of the form < V_{1}, V_{2}, …, V_{n} >
.
Next the assignments Assignable_{i} = V_{i}
are performed for 1 <= i <= n.
rascal><A, B, C> = <"abc", 2.5, [1,2,3]>;
tuple[str,real,list[int]]: <"abc",2.5,[1,2,3]>
rascal>A;
str: "abc"
rascal>B;
real: 2.5
rascal>C;
list[int]: [1,2,3]
13.6. Slice
Assign to a slice of a list or string.

Assignable [ Exp_{1} .. Exp_3 ] = Exp_{4}

Assignable [ Exp_{1}, Exp_{2} .. Exp_{3} ] = Exp_{4}
Exp_{1}
and Exp_{3}
are optional
.Types
A slice assignment is defined for List, String and Node and aims to replace a slice from the old value of the assignable by a new value. See List Slice, String Slice or Node Slice for a more detailed explanation of slicing.
Let V be the current value of Assignable.

Assignable [ Exp_{1} .. Exp_{3} ] = Exp_{4}
: The slice[ Exp_{1} .. Exp_{3} ]
determines two indicesbegin
(inclusive) andend
(exclusive) in V. A new value V' is computed that is a copy of V but with all the elements in V withbegin ⇐ index < end
replaced by the elements of the value of Exp_{4}. Note that the size of V and V' may differ. V' is assigned to the Assignable. 
Assignable [ Exp_{1}, Exp_{2} .. Exp_{3} ] = Exp_{4}
: The slice[ Exp_{1}, Exp_{2} .. Exp_{3} ]
determines two indicesbegin
(inclusive) andend
(exclusive) and astep
between indices in _V. A new value V' is computed that is a copy of V but with all the elements in V with indicesbegin
,begin+step
. …endstep
⇐index < end
replaced by the successive elements of the value of Exp_{4}. Note that the size of V and V' may differ. V' is assigned to the Assignable. If the number of indices in the slice and the number of elements in the value of Exp_{4} is not equal the following is done:
If the number of elements in the slice is larger: the elements of Exp_{4} are used in a circular manner.

If the number of elements in the slice is smaller: the remaining elements of Exp_{4} is inserted after the last index in the slice.

Replace the elements with index 3, 4, 5 in L
:
rascal>L = [0,1,2,3,4,5,6,7,8,9];
list[int]: [0,1,2,3,4,5,6,7,8,9]
rascal>L[3..6] = [100,200,300,400,500];
list[int]: [0,1,2,100,200,300,400,500,6,7,8,9]
Replace the elements with index 1, 3, 5, 7 in L
(note how the elements from [100,200]
are used in a circular way):
rascal>L = [0,1,2,3,4,5,6,7,8,9];
list[int]: [0,1,2,3,4,5,6,7,8,9]
rascal>L[1,3..8] = [100,200];
list[int]: [0,100,2,200,4,100,6,200,8,9]
Replace the elements with index 1, 3, 5, 7 in L
(note how the unused elements from [100,200,300,400,500]
are insert at index 7):
rascal>L = [0,1,2,3,4,5,6,7,8,9];
list[int]: [0,1,2,3,4,5,6,7,8,9]
rascal>L[1,3..8] = [100,200,300,400,500];
list[int]: [0,100,2,200,4,300,6,400,500,8,9]
Similar examples for slicing assignment on strings:
rascal>S = "abcdefghij";
str: "abcdefghij"
rascal>S[3..6] = "UVWXYZ";
str: "abcUVWXYZghij"
rascal>S = "abcdefghij";
str: "abcdefghij"
rascal>S[1,3..8] = "XY";
str: "aXcYeXgYij"
rascal>S = "abcdefghij";
str: "abcdefghij"
rascal>S[1,3..8] = "UVWXYZ";
str: "aUcVeWgXYZij"
Replace the elements with index 3, 4, 5 in node N
:
rascal>N = "f"(0,true,2,"abc",4,5.5,6,{7,77},8,{9,99,999});
node: "f"(
0,
true,
2,
"abc",
4,
5.5,
6,
{7,77},
8,
{999,9,99})
rascal>N[3..6] = [100,200,300,400,500];
node: "f"(
0,
true,
2,
100,
200,
300,
400,
500,
6,
{7,77},
8,
{999,9,99})
Replace the elements with index 1, 3, 5, 7 in L
(note how the elements from [100,200]
are used in a circular way):
rascal>N = "f"(0,true,2,"abc",4,5.5,6,{7,77},8,{9,99,999});
node: "f"(
0,
true,
2,
"abc",
4,
5.5,
6,
{7,77},
8,
{999,9,99})
rascal>N[1,3..8] = [100,200];
node: "f"(
0,
100,
2,
200,
4,
100,
6,
200,
8,
{999,9,99})
Replace the elements with index 1, 3, 5, 7 in L
(note how the unused elements from [100,200,300,400,500]
are insert at index 7):
rascal>N = "f"(0,true,2,"abc",4,5.5,6,{7,77},8,{9,99,999});
node: "f"(
0,
true,
2,
"abc",
4,
5.5,
6,
{7,77},
8,
{999,9,99})
rascal>N[1,3..8] = [100,200,300,400,500];
node: "f"(
0,
100,
2,
200,
4,
300,
6,
400,
500,
8,
{999,9,99})
13.7. Subscription
Assign a single element of a structured value.
Let V be the current value of Assignable. The value of Exp_{1} is used as index in V and the value of Exp_{2} replaces the original value at that index position. The result is a new value V' that is assigned to the Assignable.
Assignable has a list value:
rascal>L = [10,20,30];
list[int]: [10,20,30]
rascal>P = L;
list[int]: [10,20,30]
rascal>L[1] = 200;
list[int]: [10,200,30]
Observe that P
is unchanged:
rascal>P;
list[int]: [10,20,30]
Assignable has a map value:
rascal>M = ("abc": 1, "def" : 2);
map[str, int]: ("abc":1,"def":2)
rascal>M["def"] = 3;
map[str, int]: ("abc":1,"def":3)
Assignable has a tuple value:
rascal>T = <1, "abc", true>;
tuple[int,str,bool]: <1,"abc",true>
rascal>T[1] = "def";
tuple[int,str,bool]: <1,"def",true>
13.8. Variable
Assign to a variable.
The expression Exp is evaluated and its value is assigned to the variable Var.
rascal>N = 3;
int: 3
rascal>N;
int: 3
14. Block
Group statements into a block.
{ Statement_{1}; … ; Statement_{n} }
A block consists of a sequence of statements separated by semicolons.
Since a block is itself a statement, it may be used in all places where a statement is required. A block also introduces a new scope and variables that are declared in the block are local to that block. The value produced by a block is the value produced by its last statement (if any).
Here is a contrived block of three expressions (be aware of the last semicolon):
rascal>{1;2;3;}
int: 3
its value is 3
.
The effect of a local variable declared in a block can be seen as follows:
rascal>{int x = 3; x*x;}
int: 9
After the block we cannot refer to x
:
rascal>x;
prompt:///(0,1,<1,0>,<1,1>): Undeclared variable: x
Advice: http://tutor.rascalmpl.org/Errors/Static/UndeclaredVariable/UndeclaredVariable.html
ok
15. Break
End the execution of a while, do or for loop.
A break
statement is only allowed inside the body of a While, Do or For statement
and is associated with the innermost loop statement in which it is contained.
Its effect is to end the execution of the loop.
Here is an example using break to find the first number divisible by 3:
rascal>import IO;
ok
rascal>for(int i < [1 .. 10]){
>>>>>>> if(i % 3 == 0){
>>>>>>> println("i = <i> is divisible by 3");
>>>>>>> break;
>>>>>>> }
>>>>>>>}
i = 3 is divisible by 3
list[void]: []
16. Continue
Continue with the next iteration of while, do or for loop.
A continue statement is only allowed inside the body of a While, Do or For statement and is associated with the innermost loop statement in which it is contained. Its effect is to end the execution of the block for the current iteration of the loop and to continue with the next iteration of the loop.
Here is an example using continue to avoid printing numbers that are divisible by 3:
rascal>import IO;
ok
rascal>for(int i < [1 .. 10]){
>>>>>>> if(i % 3 == 0)
>>>>>>> continue;
>>>>>>> println("i = <i>");
>>>>>>>}
i = 1
i = 2
i = 4
i = 5
i = 7
i = 8
list[void]: []
17. Do
Repeat statements while condition holds.
do Statement while ( Exp );
Statement is executed repeatedly, as long as the Boolean expression Exp yields true. Expression Exp is executed from scratch in each repetition and only the first true value (if any) is used.
By default, the value of a do statement is the empty list. In general, the value of a do statement consists of all values contributed by Append statements that are executed during the repeated execution of its body Statement.
rascal>import IO;
ok
rascal>int n = 3;
int: 3
rascal>do { println("n = <n>"); n = 1; } while (n > 0);
n = 3
n = 2
n = 1
list[void]: []
Now build a list result using the append
statement:
rascal>n = 3;
int: 3
rascal>do { append n * n; n = 1; } while (n > 0);
list[int]: [9,4,1]
18. Fail
Let the current alternative of a pattern match fail.
fail;
A fail
statement is only allowed in statements that are controlled by the outcome of a pattern match:

The Patterns in a [Pattern with Action] in Switch or Visit statement controls the statements in the action part.

The test (expression) of a While or Do statement controls the statements in the body part.

The test (expressions) of a For statement control the statements in the body part.

The formal parameter declaration of a Function Declaration.
The fail
statement is associated with the innermost pattern match by which it is controlled.
When fail
is executed:

If the associated pattern has more alternatives, the next alternative is explored,

otherwise the pattern as a whole fails.

In the case of switch or visit this means that the next case will be tried.

For while, do and for, this implies that any bindings caused by the pattern are undone and that the next alternative in the test is tried; otherwise the loop is terminated.

For a function call it means that the next function declaration (or the default one) is tried.

Here is an example taken from Bubble.
It uses a fail
for the case that no unsorted element can be found in the list of numbers.
As a result, the whole case fails and the default case is used.
rascal>import IO;
ok
rascal>public list[int] sort(list[int] numbers){
>>>>>>> switch(numbers){
>>>>>>> case [*int nums1, int p, int q, *int nums2]:
>>>>>>> if(p > q){
>>>>>>> return sort(nums1 + [q, p] + nums2);
>>>>>>> } else {
>>>>>>> fail;
>>>>>>> }
>>>>>>> default: return numbers;
>>>>>>> }
>>>>>>>}
list[int] (list[int]): function(prompt:///(0,252,<1,0>,<11,1>))
rascal>sort([10, 1, 5, 3]);
list[int]: [1,3,5,10]
19. For
For loop.
for ( Exp_{1} , Exp_{2} , … , Exp_{n} ) Statement;
The forstatement executes Statement for all possible combinations of values of the expressions Exp_{i}. If one of the expressions is a boolean expression, we do try all its possible values.
By default, the value of a for statement is the empty list. In general, the value of a for statement consists of all values contributed by Append statements that are executed during the repeated execution of its body Statement.
rascal>import IO;
ok
rascal>for(int n < [1 .. 5]) println("n = <n>");
n = 1
n = 2
n = 3
n = 4
list[void]: []
rascal>for(int n < [1 .. 5]) append n * n;
list[int]: [1,4,9,16]
20. If
Conditional statement.

if ( Exp ) Statement;

if ( Exp ) Statement_{1} else Statement_{2};
Exp 
if ( Exp ) Statement; 



Exp 
Statement_{1} 
Statement_{2} 
if ( Exp ) Statement_{1} else Statement_{2}; 


T_{1} 
T_{2} 

The test Exp is evaluated and its outcome determines the statement to be executed:
Statement_{1} if Exp yields true
and Statement_{2} otherwise.
The value of an ifthen statement is equal to Statement when its test is true. Otherwise it is void.
The value of an ifthenelse statement is the value of the statement that was executed.
rascal>if( 3 > 2 ) 30; else 40;
int: 30
rascal>x = if( 3 > 2 ) 30; else 40;
int: 30
rascal>if( 3 > 2 ) 30;
int: 30
An ifthen statement yields void
when its test is false
(demonstrated by the ok that is printed by the Rascal system):
rascal>if( 2 > 3 ) 30;
ok
21. Insert
Insert a value in a tree during a Visit.
insert Exp;
An insert statement may only occur in the action part of a Pattern With Action, more precisely in a case in a Visit expression. The value matched by the pattern of this case is replaced by the value of Exp.
The following rule applies:

The static type of Exp should be a subtype of the type of the value that is replaced.
Consider the following datatype CTree
and assign a CTree value to variable T
:
rascal>data CTree = leaf(int n)  red(CTree left, CTree right)  green(CTree left, CTree right);
ok
rascal>CTree T = red(green(leaf(1), red(leaf(2), leaf(3))), red(leaf(4), leaf(5)));
CTree: red(
green(
leaf(1),
red(
leaf(2),
leaf(3))),
red(
leaf(4),
leaf(5)))
We can now switch the arguments of all red nodes as follows:
rascal>visit(T){
>>>>>>> case red(CTree l, CTree r): insert red(r,l);
>>>>>>>}
CTree: red(
red(
leaf(5),
leaf(4)),
green(
leaf(1),
red(
leaf(3),
leaf(2))))
Since this is a very common idiom, we also have a shorthand for it:
rascal>visit(T){
>>>>>>> case red(CTree l, CTree r) => red(r,l)
>>>>>>>}
CTree: red(
red(
leaf(5),
leaf(4)),
green(
leaf(1),
red(
leaf(3),
leaf(2))))
There is a glitch in the Rascal syntax that requires a semicolon after a case (as in the first example),
but refuses it in the abbreviated version using ⇒
(the second example).
22. Return
Return a value as result of a [Function].

return;

return Exp
A return statement comes in two variants: without and with an expression,
both variants end the execution of the current function.
The first variant applies to functions with void
as return type.
The second variants applies to nonvoid functions and returns the value of Exp as result of the function invocation.
The following rules apply:

The static type of Exp should be compatible with the declared return type of the function in which the return statement occurs.

In each function with a return type that is not void, every possible execution path through the body of the function should end in a return statement.
In each function with a return type that is void, a return statement is implicitly assumed at the end of each execution path through the function body.
rascal>int twice(int n) { return 2 * n; }
int (int): function(prompt:///(0,34,<1,0>,<1,34>))
rascal>twice(5);
int: 10
Functions that only return a value can be abbreviated (and the return is implicit):
rascal>int twiceb(int n) = 2 * n;
int (int): function(prompt:///(0,26,<1,0>,<1,26>))
rascal>twiceb(5);
int: 10
23. Solve
Solve a set of equalities by fixedpoint iteration.
solve(Var_{1}, Var_{2}, …, Var_{n}; Exp) Statement;
Rascal provides a solve statement for performing arbitrary fixedpoint computations. This means, repeating a certain computation as long as it causes changes. This can, for instance, be used for the solution of sets of simultaneous linear equations but has much wider applicability.
The solve statement consists of the variables for which a fixed point will be computed and a statement. Optionally, an expression Exp directly following the list of variables gives an upper bound on the number of iterations.
Statement can use and modify the listed variables Var_{i}. The statement is executed, assigning new values to the variables Var_{i}, and this is repeated as long as the value of any of the variables was changed compared to the previous repetition. Note that this computation will only terminate if the variables range over a socalled bounded monotonic lattice, in which values can only become larger until a fixed upper bound or become smaller until a fixed lower bound.
Let’s consider transitive closure as an example (transitive closure is already available as builtin operator, we use it here just as a simple illustration). Transitive closure of a relation is usually defined as:
R+ = R + (R o R) + (R o R o R) + ...
In other words, it is the union of successive Relation Compositions of R
with itself.
For a given relation R
this can be expressed as follows:
rascal>rel[int,int] R = {<1,2>, <2,3>, <3,4>};
rel[int,int]: {
<1,2>,
<3,4>,
<2,3>
}
rascal>T = R;
rel[int,int]: {
<1,2>,
<3,4>,
<2,3>
}
rascal>solve (T) {
>>>>>>> T = T + (T o R);
>>>>>>> }
rel[int,int]: {
<3,4>,
<1,3>,
<1,2>,
<1,4>,
<2,3>,
<2,4>
}
24. Switch
The switch statement is a control flow statement
where the next block is selected by pattern matching
against a number of case
patterns.
switch ( Exp ) {
case PatternWithAction_{1};
case PatternWithAction_{2};
...
default: ...
}
A switch statement is similar to a switch statement in C or Java. The value of the expression Exp is the subject term that will be matched by the successive Pattern With Actions in the switch statement. The switch statement provides only matching at the top level of the subject term and does not traverse it. The type of the pattern in each case must be identical to the type of the subject term (or be a supertype of it). If no case matches, the switch acts as a dummy statement. There is no fall through from one case to the next.
Suppose we want to naively analyze a sentence and print the topic it is about:
rascal>import IO;
ok
rascal>S = "Princess Leila sipped from her rum punch";
str: "Princess Leila sipped from her rum punch"
rascal>switch(S){
>>>>>>> case /Leila/: println("The topic is Star Wars");
>>>>>>> case /rum/: println("The topic is Drunken man");
>>>>>>> case /punch/: println("The topic is Kick Boxing");
>>>>>>>}
The topic is Star Wars
ok
From the printed message you can infer that the cases are tried in the order in which they occur.
The switch statement does not yet return a value, this will be changed.
25. Test
Test statement (deprecated).
The test
statement is deprecated and is replaced by the test
modifier in function declarations, see Function Declaration.
26. Throw
Throw any value as an exception up the call stack.
throw Exp
A throw statement causes the immediate abortion of the execution of the current function with Exp \'s value as exception value. The exception can be caught by a Try Catch statement in the current function or in one of its callers. If the exception is not caught, the execution of the Rascal program is terminated. The following rules apply:

The static type of Exp should be
RuntimeException
, see RuntimeException. 
The Rascal program may contain data declarations that extend the type
RuntimeException
.
Here is a a variant of string concatenation for ball haters:
rascal>str conc(str x, str y){ if("ball" in {x, y}) throw "I hate balls"; return x + y; }
str (str, str): function(prompt:///(0,82,<1,0>,<1,82>))
rascal>conc("fairy", "tale");
str: "fairytale"
rascal>conc("foot", "ball");
prompt:///(51,14,<1,51>,<1,65>): "I hate balls"
at conc(prompt:///(24,43,<1,24>,<1,67>))
at $shell$(prompt:///(0,21,<1,0>,<1,21>))
ok
27. Try Catch
Try to execute a statement and catch resulting exceptions.
try
Statement_{1};
catch PatternWithAction_{1};
catch PatternWithAction_{2};
...
catch: Statement_{2};
finally: Statement_{3};
A try catch statement has as purpose to catch any Exceptions that are raised during the execution of Statement_{1}. These exceptions may caused by:

The execution of an explicit Throw statement.

The Rascal system that discovers an abnormal condition, e.g., an out of bounds error when accessing a list element.
Note that all elements of the try catch statement are optional but that at least one has to be present. Their meaning is as follows:

If a pattern of some PatternWithAction_{i} matches, the corresponding action is executed.

Otherwise, Statement_{2} is executed (when present).

Before leaving the try catch statement Statement_{3} is always executed (when present).
Let’s define a variant of the head function that returns the first element of a list,
but throws an exception when the list is empty. Our variant will return 0
for an empty list:
rascal>import List;
ok
rascal>import Exception;
ok
rascal>int hd(list[int] x) { try return head(x); catch: return 0; }
int (list[int]): function(prompt:///(0,60,<1,0>,<1,60>))
rascal>hd([1,2,3]);
int: 1
rascal>hd([]);
int: 0
We can also be more specific and catch the EmptyList
exception
(which is available here since we have imported the Exception
module):
rascal>int hd2(list[int] x) { try return head(x); catch EmptyList(): return 0; }
int (list[int]): function(prompt:///(0,73,<1,0>,<1,73>))
rascal>hd2([]);
int: 0
28. Visit
The Visit expression can also be used directly as a statement
See [ExpressionVisit].
See Visit for the details.
rascal>x = [[1],[2],[3]];
list[list[int]]: [
[1],
[2],
[3]
]
rascal>if (true) {
this visit is a nested statement in an if block:
>>>>>>> visit (x) {
>>>>>>> case int i => i + 1
>>>>>>> }
>>>>>>>}
list[list[int]]: [
[2],
[3],
[4]
]
29. While
While loop.
while ( Exp ) Statement;
The Boolean expression Exp is evaluated repeatedly and Statement is executed when the test is true.
Execution ends the first time that the test yields false.
The test Exp is executed from scratch in each repetition and only the first true
value (if any) is used.
This is relevant when Exp contains a Boolean Match or Boolean NoMatch operator.
By default, the value of a while statement is the empty list. In general, the value of a while statement consists of all values contributed by Append statements that are executed during the repeated execution of its body Statement.
rascal>import IO;
ok
rascal>int n = 3;
int: 3
rascal>while( n > 0 ) { println("n = <n>"); n = 1; }
n = 3
n = 2
n = 1
list[void]: []
Now build a list result using the append
statement:
rascal>n = 3;
int: 3
rascal>while (n > 0) { append n * n; n = 1; }
list[int]: [9,4,1]
Just to be sure, a List Comprehension is the superior way to write this:
rascal>[n * n  n < [3 .. 1]];
list[int]: [9,4]