OCL Feature Compatibility Matrix β
This page provides a comprehensive overview of OCL (Object Constraint Language) features supported by ocl.js compared to the OMG OCL 2.4 specification.
Overall Coverage
OCL.js implements approximately 78% of common OCL operations, with excellent coverage of core functionality.
Legend β
- β Implemented - Feature is fully implemented and tested
- β Not Implemented - Feature is not currently available
- π§ Partial - Feature is partially implemented or has limitations
Collection Operations β
Implemented β β
| Operation | Syntax | Description | Example |
|---|---|---|---|
| select | collection->select(expr) | Filters elements matching condition | persons->select(age > 18) |
| reject | collection->reject(expr) | Filters elements not matching condition | persons->reject(age < 18) |
| collect | collection->collect(expr) | Maps/transforms each element | persons->collect(name) |
| forAll | collection->forAll(expr) | Universal quantifier - all must satisfy | persons->forAll(age >= 0) |
| exists | collection->exists(expr) | Existential quantifier - at least one satisfies | persons->exists(age > 100) |
| any | collection->any(expr) | Returns first element matching expression | persons->any(name = 'John') |
| one | collection->one(expr) | Exactly one element must satisfy | persons->one(isAdmin = true) |
| isUnique | collection->isUnique(expr) | Checks if all elements are unique | persons->isUnique(email) |
| size | collection->size() | Returns number of elements | persons->size() |
| isEmpty | collection->isEmpty() | Returns true if empty | persons->isEmpty() |
| notEmpty | collection->notEmpty() | Returns true if not empty | persons->notEmpty() |
| sum | collection->sum() | Sums numeric elements | prices->sum() |
| union | collection->union(c) | Combines two collections | set1->union(set2) |
| append | collection->append(element) | Adds element to end | list->append(newItem) |
| asSet | collection->asSet() | Converts to set (removes duplicates) | collection->asSet() |
| at | collection->at(index) | Returns element at index (1-based) | list->at(1) |
| first | collection->first() | Returns first element | list->first() |
| last | collection->last() | Returns last element | list->last() |
| includes | collection->includes(object) | Tests if element exists in collection | collection->includes(42) |
| includesAll | collection->includesAll(c) | Tests if all elements from c exist in collection | collection->includesAll(subset) |
| excludes | collection->excludes(object) | Tests if element does not exist in collection | collection->excludes(99) |
| excludesAll | collection->excludesAll(c) | Tests if no elements from c exist in collection | collection->excludesAll(forbidden) |
Not Implemented β β
| Operation | Syntax | Description |
|---|---|---|
| including | collection->including(object) | Adds element (immutable) |
| excluding | collection->excluding(object) | Removes element (immutable) |
| intersection | collection->intersection(c) | Set intersection |
| symmetricDifference | collection->symmetricDifference(c) | Elements in either but not both |
| flatten | collection->flatten() | Flattens nested collections |
| count | collection->count(object) | Counts occurrences of object |
| sortedBy | collection->sortedBy(expr) | Sorts collection by expression |
| closure | collection->closure(expr) | Transitive closure |
| iterate | collection->iterate(...) | General-purpose iterator |
| collectNested | collection->collectNested(expr) | Collect without flattening |
| selectByKind | collection->selectByKind(Type) | Filters by type with inheritance |
| selectByType | collection->selectByType(Type) | Filters by exact type |
| product | collection->product(c) | Cartesian product |
String Operations β
Implemented β β
| Operation | Syntax | Description | Example |
|---|---|---|---|
| size | string.size() | Returns string length | 'hello'.size() = 5 |
| concat | string.concat(s) | Concatenates strings | 'hello'.concat(' world') |
| substring | string.substring(start, end) | Extracts substring (1-based) | 'hello'.substring(2, 4) = 'ell' |
| toUpperCase | string.toUpperCase() | Converts to uppercase | 'hello'.toUpperCase() |
| toLowerCase | string.toLowerCase() | Converts to lowercase | 'HELLO'.toLowerCase() |
| indexOf | string.indexOf(s) | Returns 1-based index or 0 if not found | 'hello'.indexOf('ll') = 3 |
| toInteger | string.toInteger() | Converts to integer | '42'.toInteger() |
| toReal | string.toReal() | Converts to real number | '3.14'.toReal() |
| characters | string.characters() | Returns sequence of characters | 'hello'.characters() |
| equalsIgnoreCase | string.equalsIgnoreCase(s) | Case-insensitive comparison | 'Hello'.equalsIgnoreCase('hello') |
| toBoolean | string.toBoolean() | String to boolean conversion | 'true'.toBoolean() |
| lastIndexOf | string.lastIndexOf(s) | Last occurrence index | 'hello'.lastIndexOf('l') |
| replace | string.replace(old, new) | Replaces first occurrence | 'hello world'.replace('world', 'OCL') |
| replaceAll | string.replaceAll(old, new) | Replaces all occurrences | 'foo foo'.replaceAll('foo', 'bar') |
| matches | string.matches(regex) | Regular expression matching | 'hello123'.matches('[a-z]+') |
| trim | string.trim() | Remove leading/trailing whitespace | ' hello '.trim() |
| startsWith | string.startsWith(s) | Tests if string starts with prefix | 'hello'.startsWith('he') |
| endsWith | string.endsWith(s) | Tests if string ends with suffix | 'hello'.endsWith('lo') |
| at | string.at(index) | Returns character at 1-based index | 'hello'.at(1) = 'h' |
Math / Numeric Operations β
Implemented β β
| Operation | Syntax | Description | Example |
|---|---|---|---|
| Addition | a + b | Addition | 5 + 3 = 8 |
| Subtraction | a - b | Subtraction | 5 - 3 = 2 |
| Multiplication | a * b | Multiplication | 5 * 3 = 15 |
| Division | a / b | Real division | 5 / 2 = 2.5 |
| Integer Division | a div b | Integer division (floor) | 5 div 2 = 2 |
| Modulo | a mod b | Remainder | 5 mod 2 = 1 |
| Power | a ^ b | Exponentiation | 2 ^ 3 = 8 |
| abs | number.abs() | Absolute value | (-5).abs() = 5 |
| sqrt | number.sqrt() or number.sqrt(n) | Square root or nth root | 9.sqrt() = 3 |
| round | number.round() | Rounds to nearest integer | 3.7.round() = 4 |
| max | a.max(b) | Maximum of two numbers | 5.max(3) = 5 |
| min | a.min(b) | Minimum of two numbers | 5.min(3) = 3 |
| floor | number.floor() | Floor function (largest integer β€ self) | 3.7.floor() = 3 |
| ceil | number.ceil() | Ceiling function (smallest integer β₯ self) | 3.2.ceil() = 4 |
| toString | number.toString() | Number to string conversion | 42.toString() = '42' |
Not Implemented β β
| Operation | Syntax | Description |
|---|---|---|
| oclAsType | object.oclAsType(Type) | Type casting |
| oclIsInvalid | object.oclIsInvalid() | Check for invalid value |
| oclIsNew | object.oclIsNew() | Check if object is newly created |
| allInstances | Type.allInstances() | Get all instances of a type |
Navigation / Property Access β
All Implemented β β
| Operation | Syntax | Description | Example |
|---|---|---|---|
| Property Access | object.property | Direct property navigation | self.name |
| Nested Navigation | object.a.b.c | Deep property access | self.company.address.city |
| Collection Flattening | collection.property | Auto-flattens when navigating through collections | self.employees.name |
| Array Indexing | array[index] | Array element access (0-based) | self.items[0] |
Context & Constraint Operations β
All Implemented β β
| Operation | Syntax | Description | Example |
|---|---|---|---|
| context | context Type | Defines constraint context | context Person |
| inv | inv: expression | Invariant constraint | inv: age >= 0 |
| inv (named) | inv name: expression | Named invariant | inv positiveAge: age >= 0 |
| pre | pre: expression | Precondition | pre: amount > 0 |
| post | post: expression | Postcondition | post: balance = balance@pre - amount |
| init | init: expression | Initial value constraint | init: 0 |
| derive | derive: expression | Derived value | derive: firstName + ' ' + lastName |
| def | def: name = expression | Helper definitions | def: isAdult = age >= 18 |
| Classifier Context | context ClassName | Class-level context | context Person inv: ... |
| Operation Context | context Type::operation() | Operation-level context | context Person::rename(n: String) |
| Property Context | context Type::property | Property-level context | context Person::age |
Control Flow β
All Implemented β β
| Operation | Syntax | Description | Example |
|---|---|---|---|
| if-then-else | if cond then expr1 else expr2 endif | Conditional expression | if age >= 18 then 'adult' else 'minor' endif |
| let | let var = expr in body | Local variable binding | let discount = 0.1 in price * (1 - discount) |
Literal Values β
Implemented β β
| Type | Syntax | Example |
|---|---|---|
| Boolean | true, false | true, false |
| Integer | 42, -5 | 42, -5, 0 |
| Real | 3.14, -2.5 | 3.14, -2.5 |
| String | 'text' or "text" | 'hello', "world" |
| Null | null | null |
Not Implemented β β
| Type | Syntax | Description |
|---|---|---|
| Tuple | Tuple{a=1, b=2} | Tuple literals |
| Set | Set{1,2,3} | Set literal |
| Sequence | Sequence{1,2,3} | Ordered collection literal |
| Bag | Bag{1,1,2} | Bag (multiset) literal |
Special Features β
Implemented β β
| Feature | Description | Example |
|---|---|---|
| Enumeration Access | Access enum values | Color::RED |
| Native JS Function Calls | Fallback to JavaScript methods | Native method invocation on JS objects |
| Comments | Single and multi-line comments | -- comment or /* comment */ |
| Metamodel Provider | Custom type system integration | See Metamodel Provider Guide |
| Package Declarations | Package namespacing | package MyPackage |
| Multiple Iterators | Multiple variables in iterators | collection->forAll(x, y | x <> y) |
Usage Examples β
Collection Operations β
ocl
-- Filter adults
context Company inv:
self.employees->select(age >= 18)->notEmpty()
-- Check all employees have unique emails
context Company inv:
self.employees->isUnique(email)
-- Calculate total salary
context Company inv:
self.employees->collect(salary)->sum() <= budget
-- Check if specific employee exists
context Company inv:
self.employees->collect(id)->includes(self.managerId)
-- Validate required skills are present
context Developer inv:
self.skills->includesAll(self.project.requiredSkills)String Operations β
ocl
-- Name validation
context Person inv:
self.name.size() > 0 and
self.name.toUpperCase() = self.name.toUpperCase()
-- Email format check
context Person inv:
self.email.indexOf('@') > 0Type Operations β
ocl
-- Type checking with inheritance
context Employee inv:
self.oclIsKindOf(Person)
-- Exact type check
context Manager inv:
self.oclIsTypeOf(Manager)Control Flow β
ocl
-- Age-based discount
context Person def:
discount: Real = if age >= 65 then 0.2 else 0.0 endif
-- Complex calculation with let
context Order def:
totalPrice: Real =
let basePrice = items->collect(price)->sum() in
let discount = if customer.isPremium then 0.1 else 0.0 endif in
basePrice * (1 - discount)Summary Statistics β
| Category | Implemented | Not Implemented | Coverage |
|---|---|---|---|
| Collection Operations | 22 | 13 | 63% |
| String Operations | 19 | 0 | 100% |
| Math Operations | 15 | 0 | 100% |
| Comparison Operations | 6 | 0 | 100% |
| Boolean Operations | 5 | 0 | 100% |
| Type Operations | 3 | 4 | 43% |
| Navigation | 4 | 0 | 100% |
| Context/Constraints | 10 | 0 | 100% |
| Control Flow | 2 | 0 | 100% |
| Literals | 4 | 2 | 67% |
| Overall | 91 | 25 | ~78% |