Expressions

This part describes all language features that are currently supported by OCL.js.

Context

Every OCL rule runs in a specific context. The context constraints the execution of a rule to a specific type. Even though the type system of JavaScript is very basic, the context expression tries to guess the type as follows:

function Person() {}    => Person
class Person {}         => Person
{}                      => Object
function() {}           => undefined

To make the type guessing algorithm more flexible to your needs, the function that determines the type can be overwritten by a custom implementation. Checkout the documentation of the OclEngine to see how to override the default behavior.

When calling an OCL rule like the one below, it will only apply on objects which are of type “Person”. “Type of” in context of OCL means, that the object has to be a direct instance of the given type. E.g.: class A extends B then an instance of A is type of A but not type of B.

context Person inv:
    [...]

Invariant

An invariant is a constraint that has to be always true. Whenever an invariant is violated, the whole OCL rule is violated. One can define multiple invariants per context which are started using the keyword inv.

inv: self.variable = "value"

Definition

When one wants to define additional variables before invariants are executed, one can use the keyword def for creating variable definitions.

def: let name: "value"

Mathematical operators

The operators =, <, <=, >= and <> can be used to compare literals.

Furthermore, mathematical operations like +, -, *, /, and mod are supported.

Logic gates

Boolean expressions can be concatenated by using the keywords and, or, xor and implies. The way how logic gates work is the same as in all programming languages. But there are two special kinds: xor and implies

AND

and is used whenever both sides of the condition have to be fulfilled.

context Person
    inv: self.actsAs = "student" and self.actsAs = "employee"

OR

or is used whenever one of both (or both) sides of the condition have to be fulfilled.

context Person
    inv: self.actsAs = "student" or self.actsAs = "employee"

XOR

xor is used whenever one of two expressions have to be true. In case of the example A xor B, either A or B but not both may be true to fulfill the condition.

context Person
    inv: self.actsAs = "student" xor self.actsAs = "employee"

Implies

implies is used whenever one condition leads to another truthy condition: A implies B states, that whenever A is true, B has to be true as well. If A is false, we are not interested in B at all.

context Person
    inv: self.age >= 0 implies self.isAlive = true

Literals

The current implementation supports String, Boolean, Number and Nil literals.

Collection operations

exists

Operation which checks whether a collection contains an element specified by expr.

self.collection->exists(item | item.name = "random")

forAll

Runs the expression for all elements in collection and returns true if the expression is true for all, false otherwise.

self.collection->forAll(c | c.attribute < 10)
self.collection->forAll(c1, c2 | c1.attribute <> c2.attribute)

select

Selects all elements from collection which fit the expr.

self.collection->select(item | item.name = "random")

isEmpty

Returns true when collection is empty, false otherwise.

self.collection->isEmpty()

isNotEmpty

Returns false when collection is empty, true otherwise.

self.collection->isNotEmpty()

union

Concatenates the two given collections and returns one single collection.

self.collection->union(self->anotherCollection)

at

Returns the element of the collection at index index.

self.collection->at(2)

first

Returns the first element of the collection.

self.collection->first()

last

Returns the last element of the collection.

self.collection->last()

asSet

Returns the given collection as set, containing unique entries.

self.collection->asSet()

size

Returns the length of the given collection.

self.collection->size()