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

// This pattern file defines the syntax and lexical rules for Action Language code in BridgePoint 4.2 onwards
// References:
//     [BPAL97]  'BridgePoint(r) 3.3 Action Langage Manual', Project Technology, 1997. (on CD supplied with [Starr01])
//     [Starr01] Leon Starr: 'Executable UML: A Case Study', Model Integration, 2001. ISBN 0-9708044-0-7
//     [OAL02]   'Object Action Language(tm) Manual - Document Version: 1.4', Project Technology, 2002.
//     [OAL08]   'Object Action Language Reference Manual', Mentor Graphics, 2008.

ObjectActionLanguage : // Syntax Rules

code := statementBlock

statementBlock := { statement ';' }*

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

// Control Structures

// Parentheses around control structure conditions are strongly recommended but not required
ifBlock := IF booleanExpression
               statementBlock
           { ELIF booleanExpression
               statementBlock }*
           [ ELSE
               statementBlock ]
           END IF

forEachBlock := FOR EACH variable IN variable
                    statementBlock
                END FOR

whileBlock := WHILE booleanExpression
                  statementBlock
              END WHILE

breakStatement := BREAK

continueStatement := CONTINUE

// BPAL97 defines control stop statement but OAL02 drops it completely
controlStopStatement := CONTROL STOP

// Objects

createObjectStatement := CREATE OBJECT INSTANCE [ variable ] OF objectKeyLetters

deleteObjectStatement := DELETE OBJECT INSTANCE variable

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

whereClause := WHERE booleanExpression

// Relationships

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

relationshipSpecification := relationshipID [ '.' verbPhrase ]

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

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

instanceChain := variableOrSelf { "->" objectKeyLetters '[' relationshipSpecification ']' }+

// Events

// OAL08 adds attribute access as generate target
generateStatement := GENERATE ( eventSpecification | variableAccess | attributeAccess )

// BPAL97 uses the ASSIGNER keyword as a suffix below while OAL02 uses the CLASS keyword instead
eventSpecification := eventLabel [ ':' eventMeaning ]
                      [ '(' [ eventDataItem ':' expression { ',' eventDataItem ':' expression }* ] ')' ]
                      TO ( objectKeyLetters ( CREATOR | ASSIGNER | CLASS ) | terminatorKeyLetters | variableOrSelf )

createEventStatement := CREATE EVENT INSTANCE variable OF eventSpecification

// Operations

invokeStatement := ( [ TRANSFORM [ assignTarget ] ] objectKeyLetters "::"
                   | [ BRIDGE [ assignTarget ] ] terminatorKeyLetters "::"
                   | "::" | variableOrSelf '.' )
                   operation '(' [ parameter ':' expression { ',' parameter ':' expression }* ] ')'

returnStatement := RETURN [ expression ]

// Variables

// OAL08 drops event data item access as assign target
assignStatement := [ ASSIGN ] ( assignTarget | eventDataItemAccess '=' ) expression

// OAL08 adds parameter access as assign target
assignTarget := ( variableAccess | attributeAccess | parameterAccess ) '='

// Expressions

booleanExpression := expression

expression := logicalOrExpression

logicalOrExpression := logicalAndExpression { OR logicalAndExpression }*

logicalAndExpression := comparisonExpression { AND comparisonExpression }*

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

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

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

unaryExpression := [ NOT | '+' | '-' ] term

term := ( EMPTY | NOT_EMPTY | CARDINALITY ) variable
        | readValue | invokeExpression | '(' ( [ assignTarget ] expression ) ')'

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

// OAL08 adds enumerated literals
literalValue := booleanLiteral | enumeratedLiteral | stringLiteral | integerLiteral | realLiteral

booleanLiteral := TRUE | FALSE

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

variableAccess := variableSelfOrSelected ! '.'

variableSelfOrSelected := variableOrSelf | SELECTED

variableOrSelf := variable | SELF

attributeAccess := variableSelfOrSelected '.' attribute ! '('
// OAL08 adds array element indexing and nested attribute access
// attributeAccess := variableSelfOrSelected '[' expression ']'
//                    | variableSelfOrSelected [ '[' expression ']' ] { '.' attribute [ '[' expression ']' ] }+

eventDataItemAccess := RCVD_EVT '.' eventDataItem

parameterAccess := PARAM '.' parameter

invokeExpression := ( [ TRANSFORM ] objectKeyLetters "::"
                    | [ BRIDGE ] terminatorKeyLetters "::"
                    | "::" | variableSelfOrSelected '.' )
                    operation '(' [ parameter ':' expression { ',' parameter ':' expression }* ] ')'

// External References

objectKeyLetters := constrainedName

attribute := name // Names after '.' are not treated as keywords

// OAL08 allows constrained name as verb phrase
verbPhrase := unconstrainedName | constrainedName

enumeratedType := constrainedName

legalValue := constrainedName

// OAL08 adds '*' suffix for polymorphic event labels
eventLabel := constrainedName [ '*' ]

eventMeaning := unconstrainedName | constrainedName

eventDataItem := name // Names after '.' and before ':' are not treated as keywords

terminatorKeyLetters := constrainedName

operation := constrainedName

parameter := name // Names after '.' and before ':' are not treated as keywords

variable := constrainedName

ObjectActionLanguage :: // Lexical Rules

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

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

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

name ::= nameStart { namePart }*

nameStart := 'a'..'z' | 'A'..'Z' | '_' | '#'

namePart := 'a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '#'

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

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

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

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

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

// Special Name Tokens

constrainedName ::= name && ! keyword

// OAL02 adds CLASS keyword and drops CONTROL and STOP keywords
// OAL08 adds SEND and SENDER keywords
keyword := ACROSS | AND | ANY | ASSIGN | ASSIGNER
           | BREAK | BRIDGE | BY
           | CARDINALITY | CLASS | CONTINUE | CONTROL | CREATE | CREATOR
           | DELETE
           | EACH | ELIF | ELSE | EMPTY | END | EVENT
           | FALSE | FOR | FROM
           | GENERATE
           | IF | IN | INSTANCE | INSTANCES
           | MANY
           | NOT | NOT_EMPTY
           | OBJECT | OF | ONE | OR
           | PARAM
           | RCVD_EVT | RELATE | RELATED | RETURN
           | SELECT | SELECTED | SELF | SEND | SENDER | STOP
           | TO | TRANSFORM | TRUE
           | UNRELATE | USING
           | WHERE | WHILE

ACROSS      ::= ( "across"      | "ACROSS"      | "Across"      ) ! namePart
AND         ::= ( "and"         | "AND"         | "And"         ) ! namePart
ANY         ::= ( "any"         | "ANY"         | "Any"         ) ! 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
CLASS       ::= ( "class"       | "CLASS"       | "Class"       ) ! namePart
CONTINUE    ::= ( "continue"    | "CONTINUE"    | "Continue"    ) ! namePart
CONTROL     ::= ( "control"     | "CONTROL"     | "Control"     ) ! namePart
CREATE      ::= ( "create"      | "CREATE"      | "Create"      ) ! namePart
CREATOR     ::= ( "creator"     | "CREATOR"     | "Creator"     ) ! 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
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
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
SELECT      ::= ( "select"      | "SELECT"      | "Select"      ) ! namePart
SELECTED    ::= ( "selected"    | "SELECTED"    | "Selected"    ) ! namePart
SELF        ::= ( "self"        | "SELF"        | "Self"        ) ! namePart
SEND        ::= ( "send"        | "SEND"        | "Send"        ) ! namePart
SENDER      ::= ( "sender"      | "SENDER"      | "Sender"      ) ! namePart
STOP        ::= ( "stop"        | "STOP"        | "Stop"        ) ! 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

// End of File