Language Specification
Contens
- Introduction
- Notation
- Source code representation
- Lexical elements
- Objects declaration
- Date and time
- Common objects’ parts
- Logic programming
- Expressions
- Statements
- "import" statement
- Expression statement
- Variable declaration statement
- "error" statement
- "try-catch" statement
- "set is" statement
- "await" statement
- "wait" statement
- "complete action" statement
- "break action" statement
- "cancel action" statement
- "weak cancel action" statement
- "repeat" statement
- "while" statement
- "return" statement
- "if-elif-else" statement
- "continue loop" statement
- "break loop" statement
- "Set as default state" statement
- "Set as state" statement
- "complete state" statement
- "break state" statement
- "reject" statement
- "exec" statement
- event declaration statement
Introduction
This is manual for SymOntoClay DSL.
This document contains all implemented grammar. You can use It.
SymOntoClay DSL is in development now. So new parts will be added here right after implementation and internal testing. I will try to do this as soon as possible.
Notation
The syntax is specified using Extended Backus-Naur Form (EBNF).
Source code representation
There are two views of source code file: as set of characters and as set of code entities.
Symbols
Characters
Source code is Unicode text encoded in UTF-8.
Letters and digits
The underscore character _ (U+005F) is considered a letter.
Kind of source code files
There are different kinds of source code files which can contain different code entities.
World source code file
The file contains World declaration. There can be only one World declaration in the file. Also this file can contain other content which is allowed in Class source code file.
App source code file
The file contains App declaration. There can be only one App declaration in the file. Also this file can contain other content which is allowed in Class source code file.
Lib source code file
The file contains Lib declaration. There can be only one Lib declaration in the file. Also this file can contain other content which is allowed in Class source code file.
Class source code file
The file contains all possible code entities, except World and App declarations. There exist special source code files for these code entities. But content of Class source code file can be included into World and App source code files.
Lexical elements
Comments
SymOntoClay supports both single and multiline comments. It is a programmer-readable explanation or annotation of source code like in many other programming languages. Also It helps to cut temporarily unused code fragments.
You can see examples here.
Tokens
Tokens form the vocabulary of the SymOntoClay DSL. There are four classes: identifiers, keywords, operators and punctuation, and literals.
Identifiers
Identifiers name code entities.
Since SymOntoClay has many kinds of code entities, I have decided It will be better to recognize kind of code entity by identifier. So SymOntoClay has many kinds of identifiers with different prefixes. Each of these identifiers has Its own meaning in code.
Concept identifier
Names a concept (or type).
Predefined concept identifiers
Some concepts are predefined and reperesent code entities.
Instance identifier
Names an instance of concept.
Fact identifier
Names a rule or fact.
Variable identifier
Names a variable.
System variable identifier
Names a system variable
Logic variable identifier
Names special variable for Logic rule or Fact.
Channel identifier
Names Channel.
Keywords
Some words is used as keywords in syntax. But the words can be used as identifiers in other places.
action | down | insert | select |
actions | duration | is | state |
add | each | leave | states |
alias | elif | lib | synonym |
app | else | linvar | terms |
as | ensure | new | true |
await | enter | not | try |
break | error | null | use |
cancel | exec | on | var |
canceled | fact | once | wait |
catch | false | op | weak |
class | for | priority | where |
complete | fun | range | while |
completed | idle | reject | with |
constraints | if | rel | world |
continue | import | relation | |
ctor | inh | repeat | |
default | inheritance | return |
Operators and punctuation
The following character sequences represent operators and punctuation:
- | ! | {: | <= |
-> | ? | } | = |
, | ( | * | => |
; | ) | / | > |
: | [ | & | >= |
:} | ] | + | >> |
:> | { | < | | |
Integer literal
An integer literal is a sequence of digits representing an integer constant. Now integer literal has only decimal base.
Floating-point literal
A floating-point literal is a decimal representation of a floating-point constant.
A floating-point literal consists of an integer part (decimal digits), a decimal point and a fractional part (decimal digits). Now floating-point literal has only decimal base.
String literal
A string literal represents a string constant obtained from concatenating a sequence of characters.
You can see examples here.
NULL literal
The NULL literal represents special value which means unknown or undefined data.
Objects declaration
Everything is an object. The classical type-instance relationship is using, but there is not strict and fundamental distinction between the two.
Some objects have a special meaning. For example Class represents a general concept which can have many instances.
Some objects have special engine support to make writing code easier and faster, or as entry point locators.
Object literal
Instantiates an object or collection and performs member assignments in a single statement.
[ { [ CtorDecl ]
[ FactDeclSet ]
[ FieldDeclSet ]
[ FunCallOverloadingDeclSet ]
[ LinguisticVariableDeclSet ]
[ LogicRuleDeclSet ]
[ MemberAccessModifiersSectionDeclSet ]
[ MethodDeclSet ]
[ RelationMetadataDeclSet ]
[ TriggersContentDeclSet ] } ]
"}" .
You can see examples here.
Class
Represents a general concept which can have many instances.
In general, It is similar to the concept 'class' in other OOP languages.
"{"
[ { [ CtorDecl ]
[ FactDeclSet ]
[ FieldDeclSet ]
[ FunCallOverloadingDeclSet ]
[ LinguisticVariableDeclSet ]
[ LogicRuleDeclSet ]
[ MemberAccessModifiersSectionDeclSet ]
[ MethodDeclSet ]
[ RelationMetadataDeclSet ]
[ TriggersContentDeclSet ] } ]
"}" .
You can see examples here.
App
It is root object and entry point of App.
"{"
[ { [ CtorDecl ]
[ FactDeclSet ]
[ FieldDeclSet ]
[ FunCallOverloadingDeclSet ]
[ IdleActionsDecl ]
[ ImportStatement ]
[ LinguisticVariableDeclSet ]
[ LogicRuleDeclSet ]
[ MemberAccessModifiersSectionDeclSet ]
[ MethodDeclSet ]
[ RelationMetadataDeclSet ]
[ SetDefaultStateDirective ]
[ SetStateDirective ]
[ TriggersContentDeclSet ] } ]
"}" .
You can see examples here.
World
It is root object of World.
"{"
[ { [ FactDeclSet ]
[ FieldDeclSet ]
[ FunCallOverloadingDeclSet ]
[ ImportStatement ]
[ LinguisticVariableDeclSet ]
[ LogicRuleDeclSet ]
[ MemberAccessModifiersSectionDeclSet ]
[ MethodDeclSet ]
[ RelationMetadataDeclSet ] } ]
"}" .
Lib
It is root object of Lib.
Target library can be imported by "import" statement.
Conditional entity
Conditional entity represents an entity from the world around, which is described by condition. During code execution the condition entity will be resolved to concrete entity from the world around, which is fit to the condition.
There exist two kind of expression for conditional entity:
- Short expression also called ConditionalEntityExpr
- Fact with special logic variable $_
The short expression is more graceful for describing conditional entity. But fact can describe conditional entity more precisely and with contractions which are absent in short expression now.
During resolving short expression is converted to fact. The following expressions describe the same condition:
Concept this is converted to $_:
Example of using:
Conditional entity constraints
Constraints allow to resolve conditional entity to entity on game level that is the fittest to the situation.
Nearest
The conditional entity should be resolved to nearest game object on game level.
Random
The conditional entity should be resolved to random game object on game level.
Waypoint
Represents a point in space, abstracting from the game engine's coordinate system.
Coordinates of points are presented in a more convenient way, similar to that is used by people in everyday life.
Now It is supported the coordinate system what is similar to Polar coordinate system. The radial coordinate is the distance from center of NPC to target. And the angular coordinate (in degrees only) starts from the sagittal plane of NPC in front of the NPC.
SymOntoClay engine provides mapping to the game engine's coordinate system.
You can see examples here.
Linguistic variable
Provides non-numeric fuzzy values.
You can read more details in here.
"{"
[ LinguisticVariableBodyContent ]
"}" .
You can see examples here.
Terms
Terms are non-numeric fuzzy values.
Term combines its name and membership function. See LinguisticVariableTermsItem in SymOntoClay's garammar description.
SymOntoClay still doesn't contain means for full defining function's body. The means will be added in the future, but now you can use Predefined membership functions instead of manual defining.
Each term must be terminated by ";".
If Linguistic variable consists only of terms, the terms can be put directly into body of the Linguistic variable.
A term can be used in FuzzyExpr as NonNumericFuzzyExpr. It looks as using usual concept instead of numeric value.
You can see examples here and here.
Terms can be combined with fuzzy operators.
You can see examples here and here.
Predefined membership functions
SymOntoClay still doesn't contain means for full defining function's body. The means will be added in the future, but now you can use Predefined membership functions instead of manual defining.
There exist few predefined standard membership functions in the SymOntoClay. I am going to add more functions in the future.
L Function
You can see examples here.
Trapezoid Function
You can see examples here.
S Function
The count of params can be reduced to
You can see examples here.
Predefined operators
Fuzzy logic allows us to add special logic operators to usual logic operators and, or, not. The additional unary operators modify result of membership function.
SymOntoClay still doesn't contain means for full defining function's body. The means will be added in the future, but now you can use Predefined operators instead of manual defining.
Operators can be used only in combination with terms.
You can see examples here and here.
Very
You can see examples here and here.
Domain of a linguistic variable
Defines base set for linguistic variable. Thems are mapped to the set by membership functions.
Each linguistic variable has its own domain.
If linguistic variable doesn't have explicitly defined domain, the linguistic variable has implicit domain from -∞ to +∞.
You can define domain of linguistic variable explicitly by keyword range. See LinguisticVariableDomainDecl in SymOntoClay's garammar description.
You can see examples here.
Defining custom domain (range) for linguistic variable will be helpful for using terms of different linguistic variables with the same mames but different membership functions. For example, the term near can be different for distances on a table, in a room and in Space. Domain (range) allows us using term near as pure name without namespaces or something else.
This range is from negative infinity to positive infinity (Unbounded at both ends):
This range is also from negative infinity to positive infinity:
This range is open.
This range is closed.
This range is left-open and right-closed.
This range is left-closed and right-open.
Constraints
Defines conditions when the linguistic variable should be used.
Now you can define:
- Using terms of linguistic variable for operations with inheritance.
- Using terms of linguistic variable only in concrete logic relations.
You can see examples here.
Constraint for inheritance also generates constraint for relation "is" automatically.
Constraint for for relation "is" also generates constraint for inheritance automatically.
Defuzzification
Defuzzification transforms term of lingiustic variables (non numeric value) into numeric value.
You can read more details in here.
There are many different methods of defuzzification. SymOntoClay uses Centre of Gravity (CoG) for defuzzification.
Centre of Gravity (CoG)
Centre of Gravity (CoG) calculates by formula:
If term of linguistic variable is used with fuzzy operators,
Function
Function is first-class object.
"{"
StatementsSet
"}" .
Without parameters:
Minimal parameters declaration:
Type of parameter:
Parameter's type uses in dispatching: what function should be used in this case.
It allows us to have many functions with the same name and count of parameters but with different types of parameters.
Also the type of parameter can be tuple of types.
You can combine different ways.
Default value of parameter:
A value can be associated with parameter. The value is used when parameter is missed in function call.
You can see examples here.
Action
Action it is an object which can be call as function or method.
It is similar to C++ functor.
Action is automatically put into engine of method detection and can be called like usual method or function. Action doesn't require any manual initialization for call.
During Action call the instance of the Action is implicitly created. So all calls of Action are isolated from each other.
Entry point of action is function call overloading. One action can have many entry points with different parameters. Leaving entry point stops the action. Uncaught on action level Error in entry point crash the action can be caught on code level which called the action.
The main goal of Actions to provide triggers in context of the doing. Action's trigger starts when the Action is called. The triggers can check some condition and make additional doing related to main doing of the Action. Uncaught error in handlers of child triggers or functions which have been called from the handlers performs nothing on code level which called the action. When the action has been done then their triggers stop their activity and handlers which have been started previously.
Any time the action can be terminated from handlers of child triggers or functions which have been called from the action's entry points or handlers of child triggers.
The statement complete action terminates action by the reason of achieving goal of the action.
The statement break action breakes the action. It is similar to Error statement. But "Error statement" can break Action only in action's entry points or functions which have been called from the action's entry points. The statement break action can break Action in any place of the Action.
"{"
[ { [ CtorDecl ]
[ FactDeclSet ]
[ FieldDeclSet ]
[ FunCallOverloadingDeclSet ]
[ LinguisticVariableDeclSet ]
[ LogicRuleDeclSet ]
[ MemberAccessModifiersSectionDeclSet ]
[ MethodDeclSet ]
[ RelationMetadataDeclSet ]
[ TriggersContentDeclSet ] } ]
"}" .
Sometime entry points of action mustn't do anything. In this case the action is only context for Its child triggers. Statement await provides waiting in entry point of the Action for termination the Action by child triggers.
You can see examples here.
State
State describes behavior which can be turn on or turn off fast.
State is implementation of state pattern. It is close to the concept of finite-state machines.
States and App can be overviewed as partial object with switchable parts that are states. States have full access to App's members (even for private). State's members are isolated so do not visible for App and another states.
"{"
[ { [ ActivatingConditionsDeclSet ]
[ CtorDecl ]
[ DeactivatingConditionsDeclSet ]
[ FactDeclSet ]
[ FieldDeclSet ]
[ FunCallOverloadingDeclSet ]
[ LinguisticVariableDeclSet ]
[ LogicRuleDeclSet ]
[ MemberAccessModifiersSectionDeclSet ]
[ MethodDeclSet ]
[ RelationMetadataDeclSet ]
[ TriggersContentDeclSet ] } ]
"}" .
One State can be automatically activated during starting App by "set state" directive.
Target State can be activated any time from any place of code by "Set as state" statement.
State can can be automatically activated by conditions using Activating conditions.
State can can be automatically deactivated by conditions using Deactivating conditions.
One of States can be set as default state by "Set default state" directive on App declaration or anytime in any place of code by "Set as default state" statement. The default state will be activated if current state is closed without activation new state explicitly by "complete state" or "break state" statements.
You can see examples here.
Mutually exclusive states
Declares set of states what can not be active simultaneously. If one of states of the set is activated another active state of the set will be deactivated automatically.
There can be many sets of mutually exclusive states in the code. And one state can be in many sets of mutually exclusive states.
You can see examples here.
Set default state
One of States can be set as default state.
The default state will be activated if current state is closed without activation new state explicitly.
There can be many directives on one object and on many levels of inheritance. There will be used only one directive which has maximal rank of inheritance. If object with maximal rank of inheritance has many directives there will be used last (bottom) directive.
You can see examples here.
Set state
Declares target set which will be started automatically with starting App.
There can be many directives on one object and on many levels of inheritance. There will be used only one directive which has maximal rank of inheritance. If object with maximal rank of inheritance has many directives there will be used last (bottom) directive.
You can see examples here.
Activating conditions
Declares list of conditions for activating State.
The State will be activated automatically if It is inactive and at least one of Activating conditions is true.
Activating condition can bind captured in logic variable value with an automatically created Field by BindingVariableItemDecl.
In the example identifier of an detected enemy will be put into automatically created Field @target. The field can be used into the state Attacking for killing the detected enemy. So you should not write any additional code for detecting target entity in the state.
You can see examples here.
Deactivating conditions
Declares list of conditions for deactivating State.
The State will be deactivated automatically if It is active and at least one of Deactivating conditions is true.
You can see examples here.
Synonym
Synonym provides an alternative name for another indentifier.
You can see examples here.
Date and time
Currently only time is implemented in SymOntoClay. Date implementation requires calendar implementation, which is planned for future releases.
Time in SymOntoClay is not accurate. But its accuracy is enough for the needs of game development.
In the future, it is planned to create custom calendars with in-game time. Therefore, the concepts of "second" and "millisecond" are reserved for these calendars as subject-specific and which can differ significantly in duration from their seconds and milliseconds from the real world.
System units of time available for use:
- tick. It is the basic calendar-independent system unit of time in SymOntoClay. One tick is approximately equal to 1 millisecond from the real world.
- internal millisecond (system millisecond). Approximately equal to 1 millisecond from the real world.
- internal second (system second). Approximately equal to 1 second from the real world.
Common objects’ parts
The following parts can be in all or almost all kinds of objects.
Inheritance
SymOntoClay DSL has multiple fuzzy prototype-based inheritance.
That is, one object can have many “is a” relationships with other objects. A descendant object is related to a base object by the “is a” relationship, and is not its clone.
Additionally each relation has a float-point rank in range from 0 to 1. 1 is the highest rank, and 0 indicates the total absence of an "is a" relationship between these objects. By default the inheritance rank equals 1.
In operations using inheritance, the total inheritance rank between two objects is calculated by formula:
In this formula
If inheritance has formed a rhombus, and there are several chains with different rank, then rank of chain with the minimum count of chain elements is taken.
Inheritance relationship can be read with operator "is", and It can be changed run time with "set is" statement.
Member access modifiers
[ [ FactDeclSet ] [ FieldDeclSet ] [ FunCallOverloadingDeclSet ] [ LogicRuleDeclSet ] [ MethodDeclSet ] [ TriggersContentDeclSet ] ] .
Use the access modifiers to specify one of the following declared accessibility levels for members.
Declared accessibility | Meaning |
---|---|
public | Access is not restricted. |
protected | Access is limited to the containing object derived from the containing object. |
private | Access is limited to the containing object. |
Access modifiers are optional.
Code without access modifiers is protected.
You can see examples here.
Additional settings
Declares additional setting of object or member.
You can see examples here.
Priority
Declares priority of object or member.
Now It is allowed only for method, function or trigger.
You can see examples here.
Field
A field is a variable of any type that is declared directly in a object. Fields are members of their containing object.
In code a field can be used as usual variable.
You can see examples here.
Constructor
Whenever an instance is created, its constructor is called. An object may have multiple constructors that take different arguments. Constructors enable the programmer to set default values, limit instantiation, and write code that is flexible and easy to read.
[ ":" CallCtorsExpr ][ "=>" ]
"{"
StatementsSet
"}" .
You can see examples here.
Method
A method is a function associated with a message and an object.
In another point of view, a method is an object's behavior.
Technically a method is an object's named slot which contains a pointer to a function.
In details the method's declaration grammar is described in function's chapter .
You can see examples here.
Idle actions
Declares list of actions which can be executed when NPC is idle.
You can see examples here.
Operator overloading
A predefined SymOntoClay operator can be overloaded.
Now only function call can be overloaded.
Function call overloading
An object can declare an operator () function, which provides function call semantics for the object.
You can see examples here.
Trigger
A trigger is a code that is automatically executed in response to certain events.
Now both Logic coditional and Lifecycle triggers are available. In the future I am going to develop other kinds of triggers.
SetTriggerHandler will be executed when the trigger has been set.
DownTriggerHandler will be executed only in Logic conditional triggers when the trigger has been reset (down).
Also Logic conditional trigger can be an active rule.
Named triggers
Trigger name or alias can be used in trigger condition(TriggerLogicExpr). When the trigger is set it is true in that condition, otherwise false.
Life cycle triggers
Every object has a life cycle.
If there exist inheritance relation between object, then life cycle triggers of base object execute before the life cycle triggers of descendant object.
Enter
Executes when an object has been activated.
Enter trigger of App is a first code which is executed for the App. So It is an entrypoint of the App.
Also It is an entrypoint of State and Action. Enter trigger executes each time then the State or Action has been activated.
In chain of inheritance each Enter trigger of the chain will be called in order from the farthest item to the root item.
You can see examples here.
Leave
Executes when an object has been activated.
This trigger allows to perform some finalization actions. For example to stop shooting when state of killing enemy has been finished. There can be more reasons to finish killing enemy: enemy has been died, NPC must run away. But in any case killing the enemy must be stopped.
In chain of inheritance each Leave trigger of the chain will be called in order from the root item to the farthest item.
You can see examples here and here.
Conditional triggers
Conditional trigger sets and sometimes resets by condition. You can read more about how to set and reset trigger here.
Logic conditional triggers
Logic сonditional trigger sets and sometimes resets by logic condition. You can read more about how to set and reset trigger here.
Trigger's condition can be a fact, duration (only for reset), trigger name, field or combination of many different kinds of conditions. TriggerLogicExpr allows operators (exclude "=") and synchronous method call.
You can see examples here.
Explicit and implicit reset
Logic сonditional trigger fires (set) when logic condition is true and trigger is reset.
If the trigger has binding variables then SetTriggerHandler will be executed as many times as needed. If the trigger has already been set then the trigger continues to be set.
The trigger can be reset (down) in two ways:
- Explicitly
- Implicitly
Logic сonditional trigger can be reset explicitly by TriggersLogicDownCondition when the condition is true.
Logic сonditional trigger can be reset implicitly when the TriggersLogicSetCondition is false.
If Logic сonditional trigger has both TriggersLogicSetCondition and TriggersLogicDownCondition there can be a situation when the trigger should set and reset simultaneously. The situation is resolved by TriggersLogicDoubleConditionsStrategy.
There are strategies:
- Equal - "(=)". Both conditions are equal. So set-condition sets trigger immediately and reset-condition resets trigger immediately.
- Priority set - "(set)". Trigger can be reset only if set-condition is false.
- Priority reset - "(down)". Trigger can be set only if reset-condition is false.
Default strategy is Priority set.
Reset by timeout
Logic сonditional trigger can be reset explicitly by timeout.
The timeout without units of measurement is specified in internal seconds.
Timeout can be combined with other kinds of conditions.
Binding variables
Conditional trigger can bind captured in logic variable value with imperative variable by BindingVariableItemDecl.
Reset-condition can have its own binding variables to use in reset-handler.
If trigger has only set-condition with a binding variables and reset-handler then the reset-handler can not use the binding variables of the set-condition. So the reset-handler is executed without any binding variables.
You can see examples here.
"each" timer
Generates recurring events at the specified interval.
The interval without units of measurement is specified in internal seconds.
You can see examples here.
"once" timer
Generates an one-time event after a set interval.
The interval without units of measurement is specified in internal seconds.
You can see examples here.
Triggers on adding facts
Triggers on adding facts fires before the fact will have been added into storage. It allows to modify, reject of just log the fact.
If fact is not rejected it will be added to storage. Then logic conditional trigger could be fired with the fact.
If one fact is processed by many Triggers on adding facts the result follows the rules:
- Rejection has bigger priority then modification.
- If a modality is modified in many triggers the result will have the biggest set value of the modality.
Fact modification
Now only modalities can be modified.
Modalities can be modified using variable with captured fact, PointerOpExpr and ModalityName.
1 is set as value of obligation modality.
`middle` is set as value of self obligation modality.
Fact rejecting
A fact can be rejected with "reject" statement. In this case the fact will not be added into storage and will be ignored.
In this example the trigger rejects all facts which fit contition "{: hear(I, $x) & gun($x) :}";
Active rule
Active rule is a conditional trigger with special simple syntax which adds rules or facts when the trigger sets and removes the rules or facts when the trigger resets.
Error handling
Error is special situation what breaks the normal way of code execution. It is assumed the fired error cannot be handled and resolved in the place of occurrence. So error firing is an alternative way of execution from place of occurrence to handler which can react to the occured error.
Error handling makes NPC's logic and behaviour closer to human's logic and behaviour. For instance in some situations a human understands something like "It's error!", "It's definitely wrong way!", "It's obstacle!", stops wrong action and makes another decision. Congratulate! It's error handling!
The root of error handling is a fact what describes error, obstacle or danger situation.
Error statement captures the fact and fires error based on the fact. The normal way of execution brakes.
The error value combains the reason fact and information about execution during error: stack trace and place where this error occurred. But I think It will be better and convenient consider the error as usual fact on syntax level.
The fired error can be caught or ignored by try-catch statement. Otherwise the execution async function or trigger will be stopped.
As parallel the NPC can react to the error by conditional trigger.Annotation
Annotation provides a powerful method of associating metadata, or declarative information, with code.
After an annotation is associated with a program entity, the annotation can be queried at run time by using a technique called reflection.
Now the reflection is still not available in user code. I am going to implement this in the future. The reflection can be consumed only automatically by engine's components.
Concept
Adds additional meaning of the code entity. This meaning will be used for transformations and linking by meaning.
Key - value
Adds additional settings to code expressions.
Timeout
Sets timeout for idle actions or asynchronous call.
Executing operation will be automatically canceled after target period.
The period without units of measurement is specified in internal seconds.
By default, timeout performs weak cancel. But this behavior can be changed with some concepts.
Using concept cancel produce cancellation (with canceling callers).
Using concept weak cancel produce weak cancellation (without canceling callers).
Priority
Sets priority of operation.
Events
Events are fired when a method finishes execution.
First of all, It allows us to detect and handle finish of execution synchronous functions. I think this will be easier than creating a variable, starting execution the function in asynchronous mode and waiting for finishing function the function.
Annotation events are allowed for both synchronous and asynchronous mode.
Annotation events can be executed in both synchronous and asynchronous mode. Asynchronous annotation event contains "~".
Synchronous annotation event:
Asynchronous annotation event:
In general It looks like this:
Complete event
Fires if function is completed.
You can see examples here.
Weak cancel event
Fires if function is weak canceled (without canceling callers).
Logic programming
SymOntoClay provides Logic programming means.
SymOntoClay's Logic programming are parallel to imperative programming.
Logic and imperative means connect by
- set inheritance during Objects declaration
- Logic сonditional triggers
- select (Operator "?")
- insert
- "set is" statement
Fact
Represents knowledge in declarative way. It is an element of Logic programming.
Now the fact is a predicate sentence with small syntactic sugar for better inclusion into SymOntoClay DSL.
For example, expression "cat (#Alisa)" is equivalent to "#Alisa is a cat".
In the future, I am going to move away from the predicate form to a more human-readable one. In this case, the predicate form will be saved as an alternative way of describing.
Modalities (ModalityDeclSet) allows to describe an additional information about a fact outside FactSentence and without using another fact for describing this fact.
You can see examples here.
Logic rule
Represents a logic conclusion rule. It allows to find and use facts which are not defined explicitly. It is an element of Logic programming.
A rule defines relation between two sets of facts during logic conclusion.
Logic searching uses depth-first search (DFS) with backtracking.
A rule consists of head (LogicRulePrimarySection) and body (LogicRuleSecondarySection). The head is true if the body is true. Both head and body are predicate sentences with small syntactic sugar for better inclusion into SymOntoClay DSL.
In the future, I am going to move away from the predicate form to a more human-readable one. In this case, the predicate form will be saved as an alternative way of describing.
Conjunctions can only appear in the body, not in the head of a rule. Only special variables can be used in the rule, the scope of which is limited by this rule.
Now logic searching happens when the select operator is only called explicitly. In the future, the area of using logic searching (conclusion) in SymOntoClay will be significantly expanded.
You can see examples here.
Modalities
Modalities allows to describe an additional information about a fact outside FactSentence and without using another fact for describing this fact.
Now modalities can be used only for facts.
Facts can use only constant expression in modality:
Queries can use all types of expressions in modality.
Modalities can be modified in Triggers on adding facts.
Obligation modality
This modality is helpful for describing commands. For two facts with the same sentences high level of obligation modality defines a command and low or zero level of obligation modality defines a general description.
Obligation modality means a general obligation which meant by someone else. The NPC can have own personal obligation called Self obligation modality which can be different from Obligation modality.
Self obligation modality
This modality is similar to Obligation modality but means own personal obligation of the NPC which can be different from Obligation modality.
For instance, enemy commander makes an order. Technically It is a fact width obligation modality = 1. But for the NPC self obligation modality of the fact will be 0, because this fact represent an order of enemy commander. So the NPC must not to execute the order.
Relation metadata
Relation metadata provides machine-readable meaning of the relation.
Now It needs for conversion fact to text.
Meaning of relation's argument is provided by concepts in argument's annotation. You can read here about recommended concepts.
Standard inheritance in relation
Conversion fact to text consumes the following concepts as superclass for relations:
- event - represents an event.
- act - represents an action.
- state - represents a state.
Standard relation argument roles
Conversion fact to text consumes the following concepts as meaning of relation's argument:
- agent - someone or something who does an action.
- subject - synonym of agent.
- experiencer - someone or something who a state.
- object - who was affected by the action.
- owner - someone or something who has possessions.
- possessions - something which is property of the owner.
Semantics of Logic sentence
Predicate calculus is very flexible way. But we must keep in our mind the meaning of predicate's parameters.
Here the meaning of predicate's parameters for SymOntoClay will be described.
In the future I am going to make logic sentences closer to natural language phrases.
Semantics of unary predicate
Unary predicate discribes inheritance relationship.
Backgroundly the unary predicate transforms to predicate "is".
Semantics of binary predicate
In many cases binary predicate means relation between an object and its property.
It equals phrase "#dog1 has black color".
Also binary predicate means relation between two objects.
It equals phrase "#Piter is a parent of #Tom".
The predicate "is" has special meaning for defining inheritance relationship.
Semantics of ternary predicate
Meaning of ternary predicate is close to binary predicate.
The third parameter of ternary predicate means a value linked to the relation.
Semantics of predicate "is"
The predicate "is" has special meaning for defining inheritance relationship.
"is" is a ternary predicate. The third parameter means rank of inheritance.
Predicate "is" can be used as binary predicate. In this case rank of inheritance will be implicit and equal 1.
Expressions
An expression specifies the computation of a value by applying operators and methods to operands.
Constant expression
Constant expressions may contain only literals and are evaluated at compile time.
Fuzzy expression
Fuzzy expression can be NumberExpr in range [0, 1] or term of linguistic variable.
true represents 1. false represents 0.
Logic expression
Grouping
Expressions in round brackets executes as single expression.
Variable
A variable is a storage location for holding a value.
Both reading and writing are allowed for variables.
Default value of variable is NULL.
You can see examples here.
System variable
It's a special variable, which value is only written by engine.
Only reading is allowed for system variables.
Available system variables
@@self
Contains a link to the current App.
You can see examples here.
@@host
Contains a link to the C# methods of this App which are defined at the Unity3D level of the NPC logic or Thing.
Allows to call low-level C# methods for interaction with Unity3D.
It does nothing when It launched with the "CLI run".
You can see examples here.
Logic variable
Logic variable can be used only in Logic expression and Binding variables in Logic сonditional triggers.
Available logic variables
$_
The logic variable is used in:
- Conditional entity and represents concrete entity which fits the condition.
- Modal query and reperesents current modal value in the fact.
Channel
Channels are a conduit through which you can send and receive values with the stream operator.
Now only sending has been implemented.
Available system channels
@>log
A channel for writing information to the log in text form.
Logging targets are determined by the engine settings.
You can see examples here.
@>say
A channel for writing information to game sound bus. The information can be perceived by other NPCs' trigges as speech.
For players this information can be shown as tooltips or subtitles or converted to voice.
String will be converted to fact automatically. So you do not have to create special trigger for the string value in parallel with trigger for the fact.
Anonymous function
"{"
StatementsSet
"}" .
Anonymous function can be passed as parameter, assigned to a variable, returned as a result or called immediately.
You can see examples here.
Operators
Operators combine operands into expressions.
Operator precedence
Precedence | Operators | Associativity |
---|---|---|
2
highest |
. | Left-to-right |
() | ||
select | ||
? | ||
insert | ||
3 | ! | Left-to-right |
Unary + | ||
Unary - | new||
new | ||
5 | * | Left-to-right |
/ | ||
6 | + | Left-to-right |
- | ||
9 | > | Left-to-right |
>= | ||
< | ||
<= | ||
10 | is | Left-to-right |
is not | ||
use is | ||
14 | & | Left-to-right |
15 | | | Left-to-right |
16 | >> | Left-to-right |
17 | = | Right-to-left |
18 | , | Left-to-right |
Operator "new"
The new operator creates a new instance of a type.
You can see examples here.
Assignment operators
Operator "="
Associativity: Right-to-left.
In imperative code:
Writes a value from the right operand to the left operand and returns the value of the right operand, which can be used in further calculations.
The left operand must be a variable.
In logic expression:
Defines alias for logic expression. This alias can be used in logic expressions as usual Logic variable.
Now the alias can be created only for predicates.
In conditional entity expression:
It is a short representation relations between object and values in conditional entity expression instead of predicate.
It is the same like:
Relational operators
Operator "is"
Returns inheritance rank. The left operand contains a checked object. The right-hand operand contains a possible base object.
Using "not" returns 1 if inheritance relationship is not exist between two operands otherwise returns 0.
You can see examples here.
Operator "is" is used in Logic expressions for comparison. The comparison uses inheritance relationship. Also operator "is" can compare NumericFuzzyExpr and NonNumericFuzzyExpr.
You can see examples here.
Predicate
Represents relations between objects or objects and values.
Predicate can be only used in Logic expression.
You can read here about semantics of predicates.
Predicate's metadata can be described by Relation metadata.
You can see examples here.
Operator ">"
In Logic expression It has sucess if left-hand operand is greater than its right-hand operand, otherwise fail.
You can see examples of rules, facts and logic queries here.
In imperative code It returns true if left-hand operand is greater than its right-hand operand, otherwise false.
You can see examples of imperative code here.
Operator ">="
In Logic expression It has sucess if left-hand operand is greater than or equal to its right-hand operand, otherwise fail.
You can see examples of rules, facts and logic queries here.
In imperative code It returns true if left-hand operand is greater than or equal to its right-hand operand, otherwise false.
You can see examples of imperative code here.
Operator "<"
In Logic expression It has sucess if left-hand operand is less than its right-hand operand, otherwise fail.
You can see examples of rules, facts and logic queries here.
In imperative code It returns true if left-hand operand is less than its right-hand operand, otherwise false.
You can see examples of imperative code here.
Operator "<="
In Logic expression It has sucess if left-hand operand is less than or equal to its right-hand operand, otherwise fail.
You can see examples of rules, facts and logic queries here.
In imperative code It returns true if left-hand operand is less than or equal to its right-hand operand, otherwise false.
You can see examples of imperative code here.
Logic operators
Operator "&"
Operator of logical conjunction (logical and).
You can see examples of rules, facts and logic queries here.
You can see examples of imperative code here.
Operator "|"
Operator of logical disjunction (logical or).
You can see examples of rules, facts and logic queries here.
You can see examples of imperative code here.
Operator "!"
Operator of logical negation (logical not).
You can see examples of rules, facts and logic queries here.
You can see examples of imperative code here.
Arithmetic operators
Operator "+"
The addition operator "+" computes the sum of its operands.
If one (or two) operand is null the result also will be null.
If two operands are string the result will be concatenation of the strings. If an operand is string and another operand is not string the non string operand will be converted to string and the result will be concatenation.
You can see examples here.
Operator unary "+"
The unary "+" operator computes absolute value (or modulus) of its operand.
If the operand is null the result also will be null.
You can see examples here.
Operator "-"
The subtraction operator "-" subtracts its right-hand operand from its left-hand operand
If one (or two) operand is null the result also will be null.
You can see examples here.
Operator unary "-"
The unary "-" operator computes the numeric negation of its operand. If the operand is already negative the operator returns the value of its operand.
If the operand is null the result also will be null.
You can see examples here.
Operator "*"
The multiplication operator "*" computes the product of its operands.
If one (or two) operand is null the result also will be null.
You can see examples here.
Operator "/"
The division operator "/" divides its left-hand operand by its right-hand operand.
If the right-hand operand is 0 the result also will be null.
If one (or two) operand is null the result also will be null.
You can see examples here.
Member access operators
Operator "."
Gets a reference to a member (specified in the right operand) of an object (specified in the left operand).
The right-hand operand must contain the member's identifier.
Call operators
Operator "()"
Calls an object (or member reference) with parameters specified in round brackets.
Whether a call is synchronous or asynchronous is determined by the presence of a "~" or "~~" before the opening round bracket of the parameter list.
Named parameter:
Positional parameters:
Without parameters:
A synchronous call is made when there is no "~" or "~~". In this case, the operator returns directly the result of the called method.
You can see examples here, here or here.
An asynchronous call is made when "~" or "~~" is present. In this case, the operator returns a reference to the object which represents the asynchronous operation.
"~" starts child asynchronous operation. The operation will be automatically cancelled after finishing parent operation.
"~~" starts independent asynchronous operation. The operation will executes after finishing parent operation.
You can see examples here, here or here.
Stream operators
Operator ">>"
Copies data from a source (SourceOfStreamOpExpr) to a destination DestOfStreamOpExpr.
The source (SourceOfStreamOpExpr) cannot be a channel. The destination (DestOfStreamOpExpr) must only be a channel.
In the future I am going to extend the functionality of this operator.
Data source operators
select (Operator "?")
Performs a logical search and returns an object which contains the results of the search.
Now the result of a logical search can only be logged for demonstrating this search. In the future, I am going to develop means for practical using results of logical searching in game development.
Searched values are defined by the question variables in the searching query.
You can see examples here.
You can see examples here.
Question variables can be used for searching predicates.
You can see examples here.
In the absence of question variables, only general result will be obtained: is it possible or not to find such facts in the knowledge database.
You can see examples here.
insert
Writes a fact into the knowledge storage of current App. Returns the added fact.
You can see examples here.
Statements
Statements control execution.
"import" statement
Imports target library.
Libraries which imported on world level are common for all apps of the world.
Expression statement
Executes an expression line.
Variable declaration statement
Declares a local variable. Optyonaly you can specify its types and initial value.
"error" statement
Signals the occurrence of an error during program execution.
In details the error handling is described in the chapter "Error handling".
You can see examples here.
"try-catch" statement
This statement provides safe code execution, catching errors and blocks of guaranteed code execution.
The full statement contains try, catch, else and ensure blocks.
The statement can be call by blocks which It consists of. For example, try-catch, try-catch-else-ensure, try-ensure.
[ CatchBlockOfTryCatchStatement [{ CatchBlockOfTryCatchStatement }]]
[ ElseBlockOfTryCatchStatement ]
[ EnsureBlockOfTryCatchStatement ] .
"{"
[ StatementsSet ]
"}" .
The try block contains the guarded code that may cause the error. The block is executed until an error is fired or it is completed successfully.
When an error is fired, the engine looks for the catch statement that handles this error. If the currently executing method does not contain such a catch block, the engine looks at the method that called the current method, and so on up the call stack. If no catch block is found, then the engine stops execution of the trigger.
The else block runs when try block finished without error.
The ensure block is guaranteed to be run.
The order of execution of blocks:
-
try-catch-else-ensure:
- with error: try → catch → ensure
- without error: try → else → ensure
-
try-catch-ensure:
- with error: try → catch → ensure
- without error: try → ensure
-
try-catch-else:
- with error: try → catch
- without error: try → else
-
try-catch:
- with error: try → catch
- without error: try
-
try-else:
- with error: try
- without error: try → else
-
try-ensure:
- with error: try → ensure
- without error: try → ensure
-
try-else-ensure:
- with error: try → ensure
- without error: try → else → ensure
Full statement (try-catch-else-ensure):
try-catch:
try-catch-ensure:
try-ensure:
try-else:
try-else-ensure:
try:
In details the error handling is described in the chapter "Error handling".
You can see examples here.
"set is" statement
Sets an inheritance relationship ("is a") between two objects.
Using "not" removes the inheritance relationship.
You can see examples here.
"await" statement
The await statement suspends evaluation of the enclosing method until the action will be completed, broken, canceled or weak canceled by handlers of child triggers or functions which have been called from the handlers.
Statements after await will not be executed.
"wait" statement
"wait" statement suspends excution of the enclosing method.
You can see examples here.
Wait timeout
"wait" statement suspends excution of the enclosing method for the specified amount of time.
The amount of time without units of measurement is specified in internal seconds.
Wait callPointer
"wait" statement suspends excution of the enclosing method while callPointers is running.
"complete action" statement
The statement complete action terminates action by the reason of achieving goal of the action.
You can see examples here.
"break action" statement
The statement break action breakes the action. It is similar to Error statement. But "Error statement" can break Action only in action's entry points or functions which have been called from the action's entry points. The statement break action can break Action in any place of the Action.
You can see examples here.
"cancel action" statement
The statement cancel action canceles the action. All parents callers will also be canceled.
"weak cancel action" statement
The statement cancel action canceles the action. But all parents callers will not be canceled.
"repeat" statement
"repeat" statement defines the infinite loop.
You can see examples here.
"while" statement
The while statement executes a statement or a block of statements while a specified logic expression evaluates to true (1). Because that expression is evaluated before each execution of the loop, a while loop executes zero or more times.
You can see examples here.
"return" statement
The return statement terminates execution of the function in which it appears and returns control and the function's result, if any, to the caller.
If a function member doesn't compute a value, you use the return statement without expression.
You can see examples here.
"if-elif-else" statement
Selects a statement to execute based on the value of a logic expression.
"{"
[ StatementsSet ]
"}"
[ "elif" "(" ImperativeLogicExpr ")"
"{"
[ StatementsSet ]
"}"
{ "elif" "(" ImperativeLogicExpr ")"
"{"
[ StatementsSet ]
"}"
}]
[ "else"
"{"
[ StatementsSet ]
"}" ] .
An if statement with an else part selects one of the two statements to execute based on the value of a Logic expression. An if statement executes if the Logic expression evaluates to true (1).
An if statement without an else part executes its body only if a Logic expression evaluates to true (1).
You can use elif statements to check multiple conditions.
if:
if-else:
if-elif:
if-elif-elif:
if-elif-elif-else:
if-elif-else:
You can see examples here.
"continue loop" statement
The continue statement starts a new iteration of the closest enclosing iteration statement (that is, repeat, or while).
You can see examples here.
"break loop" statement
The break statement terminates the closest enclosing iteration statement (that is, repeat, or while). The break statement transfers control to the statement that follows the terminated statement, if any.
You can see examples here.
"Set as default state" statement
One of States can be set as default state.
The default state will be activated if current state is closed without activation new state explicitly.
You can see examples here.
"Set as state" statement
Activates target State explicitly.
Current State will be deactivated.
You can see examples here.
"complete state" statement
Finishes current State and markes It as completed.
You can see examples here.
"break state" statement
Finishes current State and markes It as broken.
If "break state" statement has ReasonOfBreakStateStatement, the reason will be put into global storage and triggers are able to react to the the reason.
You can see examples here.
"reject" statement
Special statement for Trigger on adding facts which rejects added Fact. In this case the fact will not be added into storage and will be ignored.
The statement can be called only in body of Trigger on adding facts.
The statement does not break execution of the body of the trigger's handler.
In this example the trigger rejects all facts which fit contition "{: hear(I, $x) & gun($x) :}";
"exec" statement
Converts Fact to imperative code and executes the code.
You can see examples here.
event declaration statement
Adds trigger to an object in function body.
Complete event
Fires if function is completed.
Weak cancel event
Fires if function is weak canceled (without canceling callers).