// Copyright (c) 2008-2010 by Kavanagh Consultancy Limited. All rights reserved.

ActionLanguage : // Syntax Rules

code := statementBlock

statementBlock := { statement ';' }*

statement := ifBlock
             | switchBlock
             | forEachBlock
             | whileBlock
             | breakStatement
             | continueStatement
             | createObjectStatement
             | deleteObjectStatement
             | migrateStatement
             | selectFromStatement
             | relateStatement
             | unrelateStatement
             | selectRelatedByStatement
             | generateStatement
             | createEventStatement
             | deleteEventStatement
             | invokeStatement
             | returnStatement
             | assignStatement
             | declareStatement

// Control Structures

ifBlock := IF '(' booleanExpression ')'
               statementBlock
           { ELIF '(' booleanExpression ')'
               statementBlock }*
           [ ELSE
               statementBlock ]
           END IF

switchBlock := SWITCH '(' enumeratedExpression ')'
               { CASE legalValue { ',' legalValue }* ':'
                   statementBlock }+
               END SWITCH

forEachBlock := FOR EACH variable IN ( variableOrInputParameter | '(' expression ')' )
                    statementBlock
                END FOR

whileBlock := WHILE '(' booleanExpression ')'
                  statementBlock
              END WHILE [ numericExpression ]

breakStatement := { BREAK }+

continueStatement := { BREAK }* CONTINUE

// Objects

createObjectStatement := CREATE OBJECT ( INSTANCE [ variableOrSelf ] OF objectSpecification
                                       | INSTANCES [ variableOrSelf '=' ] objectSpecification
                                                   { ',' [ variableOrSelf '=' ] objectSpecification }* )

objectSpecification := objectReference [ '(' [ attribute ':' expression
                                                 { ',' attribute ':' expression }*
                                                 [ ',' CURRENT_STATE ':' enumeratedExpression ]
                                             | CURRENT_STATE ':' enumeratedExpression ] ')' ]

deleteObjectStatement := DELETE OBJECT ( INSTANCE | INSTANCES ) objectInstanceExpression

migrateStatement := MIGRATE OBJECT INSTANCES objectInstanceExpression TO
                        [ variable '=' ] objectSpecification
                        { ',' [ variable '=' ] objectSpecification }*

selectFromStatement := SELECT ( ANY | MANY ) variable
                           FROM ( INSTANCES OF objectReference | objectInstanceExpression )
                           [ whereClause ] [ orderedByClause ]

whereClause := WHERE booleanExpression

// Relationships

relateStatement := RELATE objectInstanceExpression TO objectInstanceExpression
                       ACROSS relationshipSpecification [ USING objectInstanceExpression ]

relationshipSpecification := relationshipID [ '.' verbPhrase ] | verbPhrase

unrelateStatement := UNRELATE objectInstanceExpression FROM objectInstanceExpression
                         ACROSS relationshipSpecification [ USING objectInstanceExpression ]

selectRelatedByStatement := SELECT ( ONE | ANY | MANY ) variable RELATED BY instanceChain
                                [ whereClause ] [ orderedByClause ]

instanceChain := objectInstanceExpression { "->" objectReference [ '[' relationshipSpecification ']' ] }+

orderedByClause := [ REVERSE ] ORDERED BY ( [ REVERSE ] attribute { ',' [ REVERSE ] attribute }*
                                          | relationshipSpecification )

// Events

// Can use event instance or complete transfer vector expression in generate statement
generateStatement := GENERATE ( eventSpecification | eventInstanceExpression ) [ delayClause ]

eventSpecification := ( eventLabel [ ':' eventMeaning ] | eventMeaning )
                      [ '(' [ eventDataItem ':' expression { ',' eventDataItem ':' expression }* ] ')' ]
                      ( TO ( objectReference CREATOR
                           | ( objectReference | relationshipReference ) ASSIGNER [ USING objectInstanceExpression ]
                           | objectReference CLASS
                           | terminatorReference
                           | objectInstanceExpression )
                      | FROM eventInstanceExpression )

delayClause := AFTER numericExpression // Delay in seconds

createEventStatement := CREATE EVENT INSTANCE variable OF eventSpecification

deleteEventStatement := DELETE EVENT INSTANCE eventInstanceExpression

// Operations

// Can only invoke bridging processes from actions and simple processes
// Can only invoke synchronous services from bridge mappings and domain observers
invokeStatement := ( [ TRANSFORM [ assignTarget | invokeTarget ] ] objectReference "::" stateModelProcess
                   | [ BRIDGE [ assignTarget | invokeTarget ] ] terminatorReference "::" bridgingProcess
                   | [ domainQualifier ] "::" function
                   | variableOrSelf '.' stateModelProcess // State model or polymorphic process
                   | variable '.' RETURN ) // Return coordinate or partial transfer vector
                   '(' [ inputParameter ':' expression { ',' inputParameter ':' expression }* ] ')'

invokeTarget := outputParameter ':' variable { ',' outputParameter ':' variable }* '='

returnStatement := RETURN [ expression | outputParameter ':' expression { ',' outputParameter ':' expression }* ]

// Variables

assignStatement := [ ASSIGN ] ( assignTarget expression | invokeTarget invokeExpression )

assignTarget := ( variable ! '.' | variableOrSelf '.' attribute ) '='

declareStatement := DECLARE variable AS [ [ EMPTY OR ] ( ONE | MANY ) ] dataType [ '=' expression ]

// We would like to use the following rule but can't since predefined type names are fuzzy matched
// dataType := ( "Boolean" | "String" | "Integer" | "Real" | "Date" | "Timestamp" | "Arbitrary_ID" ) [ '<' '>' ]
//             | "Subtype" '<' relationshipReference '>'
//             | "State" '<' stateModelReference '>'
//             | "Object_Instance" '<' objectReference '>'
//             | "Event_Instance" '<' eventReference '>'
//             | "Return_Coordinate" '<' [ terminatorReference "::" ] synchronousService '>'
//             | "Transfer_Vector" '<' [ [ terminatorReference "::" ] asynchronousReturnWormhole ] '>'
//             | externalName
dataType := externalName [ '<' [ relationshipReference | stateModelReference | objectReference | eventReference
                               | [ terminatorReference "::" ] ( synchronousService
                                                              | asynchronousReturnWormhole ) ] '>' ]

// We would like to use the following rule but can't since predefined type names are fuzzy matched
// enumeratedType := "Subtype" '<' relationshipReference '>'
//                   | "State" '<' stateModelReference '>'
//                   | externalName
enumeratedType := externalName [ '<' ( relationshipReference | stateModelReference ) '>' ]

// Expressions

expression := logicalOrExpression

booleanExpression := logicalOrExpression

enumeratedExpression := term

numericExpression := addExpression

objectInstanceExpression := term

eventInstanceExpression := term

logicalOrExpression := logicalAndExpression { OR logicalAndExpression }*

logicalAndExpression := comparisonExpression { AND comparisonExpression }*

comparisonExpression := addExpression [ ( "==" | "!=" | '<' | "<=" | '>' | ">=" ) addExpression ]

addExpression := multiplyExpression { ( '+' | '-' ) multiplyExpression }*

multiplyExpression := unaryExpression { ( '*' | '/' | '%' ) unaryExpression }*

unaryExpression := [ NOT | '+' | '-' | EMPTY | NOT_EMPTY | CARDINALITY ] term

term := readValue | invokeExpression | '(' expression ')'

readValue := literalValue | variableAccess | attributeAccess | eventDataItemAccess | parameterAccess | '?'

literalValue := booleanLiteral | enumeratedLiteral | stringLiteral | integerLiteral | realLiteral

booleanLiteral := TRUE | FALSE

enumeratedLiteral := enumeratedType "::" legalValue ! '('

variableAccess := variableSelfOrSelected ! '.'

variableSelfOrSelected := variableOrSelf | SELECTED

variableOrSelf := variable | SELF

// We don't allow nested expressions below since attribute access is a read value
attributeAccess := variableSelfOrSelected '.' ( attribute ! '('
                                              | CURRENT_SUBTYPE [ '<' relationshipID '>' ]
                                              | CURRENT_STATE [ '<' stateModelLabelPrefix '>' ] )
                   | CURRENT_STATE '<' stateModelReference '>' | CURRENT_TIME

eventDataItemAccess := RCVD_EVT '.' eventDataItem

parameterAccess := PARAM '.' inputParameter

invokeExpression := ( [ TRANSFORM ] objectReference "::" stateModelProcess
                    | [ BRIDGE ] terminatorReference "::" bridgingProcess
                    | [ domainQualifier ] "::" function
                    | variableSelfOrSelected '.' stateModelProcess )
                    '(' [ inputParameter ':' expression { ',' inputParameter ':' expression }* ] ')'

// External References

domainQualifier := externalName '@' // Domain qualifiers are only used in bridge mappings

objectReference := [ domainQualifier ] externalName // Object name OR object key letters

attribute := externalName

relationshipReference := [ domainQualifier ] relationshipID

verbPhrase := externalName // Verb phrase OR role

legalValue := externalName

stateModelReference := [ domainQualifier ] stateModelLabelPrefix

stateModelLabelPrefix := keyLetters [ '-' assignerSuffix ] | relationshipID '-' assignerSuffix

terminatorReference := [ domainQualifier ] externalName // Terminator name OR terminator key letters

eventReference := [ domainQualifier ] eventLabel

eventLabel := simpleEventLabel | keyLetters '-' assignerEventSuffix
              | relationshipID '-' ( assignerEventSuffix | polymorphicEventSuffix )

eventMeaning := externalName

eventDataItem := externalName

function := externalName

stateModelProcess := externalName

bridgingProcess := externalName

synchronousService := externalName

inputParameter := externalName

outputParameter := externalName

variable := externalName

variableOrInputParameter := externalName

ActionLanguage :: // Lexical Rules

input := { $javaWhitespace | comment | token }*

comment := "//" { ! '\n' $anyCharacter }* $endOfLine

token := name | unconstrainedName | stringLiteral | integerLiteral | realLiteral | separatorOrOperator

name ::= nameStart { namePart }*

nameStart := $javaIdentifierStart | '#'

namePart := $javaIdentifierPart | '#'

unconstrainedName ::= '\'' { ! '\n' ! '\'' ! '\\' $anyCharacter | javaEscapeSequence }+ '\''

javaEscapeSequence := '\\' ( 'b' | 't' | 'n' | 'f' | 'r' | '"' | '\'' | '\\'
                           | [ '0'..'3' ] '0'..'7' [ '0'..'7' ]
                           | 'u' hexDigit hexDigit hexDigit hexDigit )

hexDigit := '0'..'9' | 'a'..'f' | 'A'..'F'

stringLiteral ::= '"' { ! '\n' ! '"' ! '\\' $anyCharacter | javaEscapeSequence }* '"'

integerLiteral ::= [ '-' ] { '0'..'9' }+ ! '.'

realLiteral ::= [ '-' ] { '0'..'9' }+ '.' { '0'..'9' }+

separatorOrOperator ::= "!=" | "->" | "::" | "<=" | "==" | ">=" | '%' | '(' | ')' | '*' | '+' | ','
                        | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | ']'

// Special Name Tokens

externalName ::= unconstrainedName | constrainedName // Fuzzy matched

constrainedName ::= name && ! keyword && ! relationshipID

keyword := ACROSS | AFTER | AND | ANY | AS | ASSIGN | ASSIGNER
           | BREAK | BRIDGE | BY
           | CARDINALITY | CASE | CLASS | CONTINUE | CREATE | CREATOR | CURRENT_STATE | CURRENT_SUBTYPE | CURRENT_TIME
           | DECLARE | DELETE
           | EACH | ELIF | ELSE | EMPTY | END | EVENT
           | FALSE | FOR | FROM
           | GENERATE
           | IF | IN | INSTANCE | INSTANCES
           | MANY | MIGRATE
           | NOT | NOT_EMPTY
           | OBJECT | OF | ONE | OR | ORDERED
           | PARAM
           | RCVD_EVT | RELATE | RELATED | RETURN | REVERSE
           | SELECT | SELECTED | SELF | SWITCH
           | TO | TRANSFORM | TRUE
           | UNRELATE | USING
           | WHERE | WHILE

ACROSS          ::= ( "across"          | "ACROSS"          | "Across"          ) ! namePart
AFTER           ::= ( "after"           | "AFTER"           | "After"           ) ! namePart
AND             ::= ( "and"             | "AND"             | "And"             ) ! namePart
ANY             ::= ( "any"             | "ANY"             | "Any"             ) ! namePart
AS              ::= ( "as"              | "AS"              | "As"              ) ! namePart
ASSIGN          ::= ( "assign"          | "ASSIGN"          | "Assign"          ) ! namePart
ASSIGNER        ::= ( "assigner"        | "ASSIGNER"        | "Assigner"        ) ! namePart
BREAK           ::= ( "break"           | "BREAK"           | "Break"           ) ! namePart
BRIDGE          ::= ( "bridge"          | "BRIDGE"          | "Bridge"          ) ! namePart
BY              ::= ( "by"              | "BY"              | "By"              ) ! namePart
CARDINALITY     ::= ( "cardinality"     | "CARDINALITY"     | "Cardinality"     ) ! namePart
CASE            ::= ( "case"            | "CASE"            | "Case"            ) ! namePart
CLASS           ::= ( "class"           | "CLASS"           | "Class"           ) ! namePart
CONTINUE        ::= ( "continue"        | "CONTINUE"        | "Continue"        ) ! namePart
CREATE          ::= ( "create"          | "CREATE"          | "Create"          ) ! namePart
CREATOR         ::= ( "creator"         | "CREATOR"         | "Creator"         ) ! namePart
CURRENT_STATE   ::= ( "current_state"   | "CURRENT_STATE"   | "Current_state"   ) ! namePart
CURRENT_SUBTYPE ::= ( "current_subtype" | "CURRENT_SUBTYPE" | "Current_subtype" ) ! namePart
CURRENT_TIME    ::= ( "current_time"    | "CURRENT_TIME"    | "Current_time"    ) ! namePart
DECLARE         ::= ( "declare"         | "DECLARE"         | "Declare"         ) ! namePart
DELETE          ::= ( "delete"          | "DELETE"          | "Delete"          ) ! namePart
EACH            ::= ( "each"            | "EACH"            | "Each"            ) ! namePart
ELIF            ::= ( "elif"            | "ELIF"            | "Elif"            ) ! namePart
ELSE            ::= ( "else"            | "ELSE"            | "Else"            ) ! namePart
EMPTY           ::= ( "empty"           | "EMPTY"           | "Empty"           ) ! namePart
END             ::= ( "end"             | "END"             | "End"             ) ! namePart
EVENT           ::= ( "event"           | "EVENT"           | "Event"           ) ! namePart
FALSE           ::= ( "false"           | "FALSE"           | "False"           ) ! namePart
FOR             ::= ( "for"             | "FOR"             | "For"             ) ! namePart
FROM            ::= ( "from"            | "FROM"            | "From"            ) ! namePart
GENERATE        ::= ( "generate"        | "GENERATE"        | "Generate"        ) ! namePart
IF              ::= ( "if"              | "IF"              | "If"              ) ! namePart
IN              ::= ( "in"              | "IN"              | "In"              ) ! namePart
INSTANCE        ::= ( "instance"        | "INSTANCE"        | "Instance"        ) ! namePart
INSTANCES       ::= ( "instances"       | "INSTANCES"       | "Instances"       ) ! namePart
MANY            ::= ( "many"            | "MANY"            | "Many"            ) ! namePart
MIGRATE         ::= ( "migrate"         | "MIGRATE"         | "Migrate"         ) ! namePart
NOT             ::= ( "not"             | "NOT"             | "Not"             ) ! namePart
NOT_EMPTY       ::= ( "not_empty"       | "NOT_EMPTY"       | "Not_empty"       ) ! namePart
OBJECT          ::= ( "object"          | "OBJECT"          | "Object"          ) ! namePart
OF              ::= ( "of"              | "OF"              | "Of"              ) ! namePart
ONE             ::= ( "one"             | "ONE"             | "One"             ) ! namePart
OR              ::= ( "or"              | "OR"              | "Or"              ) ! namePart
ORDERED         ::= ( "ordered"         | "ORDERED"         | "Ordered"         ) ! namePart
PARAM           ::= ( "param"           | "PARAM"           | "Param"           ) ! namePart
RCVD_EVT        ::= ( "rcvd_evt"        | "RCVD_EVT"        | "Rcvd_evt"        ) ! namePart
RELATE          ::= ( "relate"          | "RELATE"          | "Relate"          ) ! namePart
RELATED         ::= ( "related"         | "RELATED"         | "Related"         ) ! namePart
RETURN          ::= ( "return"          | "RETURN"          | "Return"          ) ! namePart
REVERSE         ::= ( "reverse"         | "REVERSE"         | "Reverse"         ) ! namePart
SELECT          ::= ( "select"          | "SELECT"          | "Select"          ) ! namePart
SELECTED        ::= ( "selected"        | "SELECTED"        | "Selected"        ) ! namePart
SELF            ::= ( "self"            | "SELF"            | "Self"            ) ! namePart
SWITCH          ::= ( "switch"          | "SWITCH"          | "Switch"          ) ! namePart
TO              ::= ( "to"              | "TO"              | "To"              ) ! namePart
TRANSFORM       ::= ( "transform"       | "TRANSFORM"       | "Transform"       ) ! namePart
TRUE            ::= ( "true"            | "TRUE"            | "True"            ) ! namePart
UNRELATE        ::= ( "unrelate"        | "UNRELATE"        | "Unrelate"        ) ! namePart
USING           ::= ( "using"           | "USING"           | "Using"           ) ! namePart
WHERE           ::= ( "where"           | "WHERE"           | "Where"           ) ! namePart
WHILE           ::= ( "while"           | "WHILE"           | "While"           ) ! namePart

relationshipID ::= ( 'R' | 'r' ) positiveInteger

positiveInteger ::= '1'..'9' { '0'..'9' }* ! namePart

keyLetters ::= { keyLettersPart }+ ! namePart

keyLettersPart := 'A'..'Z' | 'a'..'z' | '_'

assignerSuffix ::= ( 'A' | 'a' ) ! namePart

simpleEventLabel ::= { keyLettersPart }+ positiveInteger

assignerEventSuffix ::= ( 'A' | 'a' ) positiveInteger

polymorphicEventSuffix ::= ( 'P' | 'p' ) positiveInteger

// End of File