This is the authoritive reference on the Perspectives Language. It is a work in progress. Currently, it is mostly about syntax. Semantical constraints will be added later. This is not the only source of information on PL:
All types are identified by qualified names. These are qualified names:
||A domain name itself is qualified. These names are used in prefix declaration expressions:
||A fully qualified case name.|
||A fully qualifid role name.|
||A fully qualifid property name.|
||A prefixed name is a qualified name as long as we have a use statement for the prefix:
Quite often the parser/compiler can guess the qualified name from just the local part of that name. If not, an error is signalled. The
use...for statement may be used to abbreviate longer namespaces, e.g.
use mrl for model:MyModel$MyCase$MyRole lets us identify the property given in the table as
If the parser finds multiple qualified names with the same local part, either fully qualify the offending name or prefix it with enough segments to make it unique. For example, given the roles:
the single segment
MyRole does not uniquely identify either. However,
ACase$MyRole does and the system does not complain.
Finally, each context and role act as namespace containers. Hence, qualified names can become quite long!
There are five kinds of context. Each can be declared with a specific keyword. Each can house some, but not all, other context declarations.
||A domain is the top level context of a model. A domain can contain roles and contexts, and
||A case revolves around a central concept (a role) and must contain the user roles that have a perspective on that concept|
||A party is for the purpose of introducing user roles that can be referred from cases. Use party to structure an organisation. A party can contain other parties.|
||An activity is about doing things in a context with clear responsibilities. An activity may contain states.|
||A state is a case or activity with specific values for roles or attributes. A state may introduce new roles|
Context declarations can only be nested inside other Context definitions, with limitations:
There are five kinds of roles. Each can be declared with a specific keyword inside a context definition.
||A user role represents living persons that perform actions. Actions are collected in a perspective. A user role can only be filled by another user role.|
||A thing role has no perspective. It represents everything that is not an agent. A thing role can only be filled by another thing role.|
||A context role is bound to the External Role of a context. It represents a context (instance) within another context (instance). A context role can only be filled by another context role, or by an external role.|
||A bot role is for a particular user role and has a perspective. Its actions are carried out automatically when their conditions are met. A bot role cannot be filled.|
||An external role is a role that represents a context. An external role cannot be filled.|
Use these keywords to create Roles. Restrictions apply on filling roles:
||Declare a User role with default attributes: not mandatory, functional.|
||Declare a User role with explicit attributes.|
||User role with default attributes, filled with the Person role.|
||SystemUser is the root user and is never filled with another role|
||User role filled by either of two roles.|
||User role with attributes, filled with the Person role.|
||User role filled by two roles simultaneously. One role provides personal details, the other the drivers license.|
||Calculate a role with an expression.|
||A call to a (fictitious) API function that results in instances of the type Document. We call a role that is created in this way a computed role.|
||A property with default attributes and a String range:
||A property with defined attributes and range|
||Calculate a property with an expression.|
Adding an aspect uses the same syntax for contexts and roles:
||A perspective with all Verbs (Create, Consult, Change, Delete), for all properties of SomeRole|
||A perspective with all Verbs, but just for the properties in the view AView|
||A perspective with just the Verb Change, but for all properties|
||A perspective just the properties in AView and just the Verbs Change and Delete.|
Perspective expressions over multiple lines:
Here the Action with the Change Verb uses the view AnotherView on SomeRole, while the Actions with the Verbs Consult and Create use the default view AView.
The Action with the Verb Change is conditional on the (Boolean) value of the expression.
A bot can have a perspective, too. It's Actions are all about creating, changing or deleting contexts, roles and property values.
The condition must be an expression with a Boolean Value (see Expressions, below).
<assignment> takes on one of three forms:
This is a let* expression:
Assignment statements are explained below.
When a rule fires, it is applied in an environment in which the variable
object is bound, automatically, to the current object set. This is the set of objects of the Perspective of the bot. This variable can be used in every assignment and in the expressions for the
This is how to change the instances of a role in a context. Below,
<role-expression> is a query evaluate with respect to the current context (the context of the bot executing the assignment). The same holds for
NOTE: the text Assignment has a more in-depth treatment of the subject.
||Select the role instances to remove, in any context|
||Create a new instance of the role and attach it to the current context, or to the context selected with the optional
||Move the selected role instances to the current context, or the selected context. Notice that both contexts have to have the same type!|
||Delete all selected instances, from any context.|
||To fill a role with another role, use bind (when A fills B, we say that B is bound to A. A is the binding; B is the binder).
||Instead of creating new instances, this syntax allows you to select an (empty) binder and fill it with the binding. Notice that both queries must select a single instance!|
||Select bindings - that is, the roles that are bound - and release them from their binders. When RoleType is given, just release them from binders of that Type.|
||Select a single binding and and release it from the selected single binder.|
This is how to change the values of a property for some role. The assignment statements below change the roles in the current object set, unless one or more role is selected with
<role-expression>. The current object set is determined by the object of the perspective.
||Add a value to the list of values for SomePropertyType. It is an error if the type of
||Remove the value from the list of values for SomePropertyType. It is an error if the type of
||Completely replace all values of
||Completely remove all values of
Creating a context is different from creating a role. It is not possible to create a role instance without immediately inserting it into a context. However, it is entirely possible to create a context without binding it into some other context. This is not useful, however. So why not immediately bind a new context instance? Because it is not obvious where, as a context instance may be bound in multiple contexts. A role instance, however, is always bound in just a single context. See the assignment section above on how to create a role instance.
||Create a new instance of
Combine a context creation expression with a role binding expression like this:
Perspectives has a mechanism to extend the language with external functions. These functions should be thought of as external with respect to the core language. Such functions are defined in namespaces and added through modules that are compiled with the PDR. One can call them through the use of two keywords:
callExternalallows one to create a Role or Property that is computed by an external function;
callEffectallows one to make changes to the Perspectives state by calling an external function.
For example, this ContextRole declaration:
adds a Role that is computed by the function Models in the module identified by the (standard) prefix
model:Couchdb. As another example, consider this statement in the then-part of a rule:
This external function loads a model file from an Url and adds it to the local store of model files in Couchdb.
The general form for calling these functions and statements is
qualifiedName( <expression>* ), where each argument must be provided by ordinary Perspectives expressions (as detailed below).
A view is merely a list of properties.
It is an error if
AnotherProperty are not the identifiers of Properties.
Expressions have a highly recursive structure. They are built from three primary forms: (assignments are not expressions!):
Here is the full expression syntax:
Operator precedence is ruled by weights for each operator. Parentheses can be used to override these precedences.
Note that the unary operators
available have lower precedence than any of these binary operators. For example,
not is always applied to the entire expression behind it. So if that expression is a conjunction, it is applied to the entire conjunction - not to its left term!
is the same as
Strings, Numbers, Booleans and DateTime values are written as follows:
|"a string"||A string should be enclosed in quotes. Any character can be inside a string, that is not a double quote, a backslash or an ampersand. Escape character sequences are allowed, too, but they are not documented here. We refer to the source code of Text.Parsing.Parser.Token|
|true, false||These are the entire population of the Boolean type.|
|123||Number representation has yet to be decided on. Right now only integers can be used.|
Copyright 2019 Joop Ringelberg and Cor Baars