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

// This pattern file defines the syntax rules and lexical structure of archetypes in BridgePoint 4.2
// References:
//     [BPAuto99] 'BridgePoint(r) - Automation', Project Technology, 1999. (on CD supplied with [Starr01])
//     [Starr01]  Leon Starr: 'Executable UML: A Case Study', Model Integration, 2001. ISBN 0-9708044-0-7

ArchetypeLanguage : // Syntax Rules

archetype := statementBlock

statementBlock := { literalTextLine | controlStatement }*

literalTextLine := ! '.' { literalText | substitutionVariable }* endOfLine

controlStatement := selectStatement
                    | forBlock
                    | breakForStatement
                    | whileBlock
                    | breakWhileStatement
                    | assignStatement
                    | ifBlock
                    | functionBlock
                    | invokeStatement
                    | emitStatement
                    | clearStatement
                    | includeStatement
                    | printStatement
                    | exitStatement

// 9.1.3. Data Access Control Statements

selectStatement := '.' SELECT ( ( ONE | ANY | MANY ) variable RELATED BY instanceChain
                              | ( ANY | MANY ) variable FROM INSTANCES OF objectKeyLetters )
                   [ WHERE condition ] endOfLine

instanceChain := variable { relationshipTraversal }+

relationshipTraversal := "->" objectKeyLetters '[' relationshipID [ '.' ( IR | RI ) ] ']'

objectKeyLetters := name // Allow keyword

condition := expression

forBlock := forStatement statementBlock endForStatement

forStatement := '.' FOR EACH variable IN variable endOfLine

endForStatement := '.' END FOR endOfLine

breakForStatement := '.' BREAK FOR endOfLine

whileBlock := whileStatement statementBlock endWhileStatement

whileStatement := '.' WHILE condition endOfLine

endWhileStatement := '.' END WHILE endOfLine

breakWhileStatement := '.' BREAK WHILE endOfLine

// 9.1.4. Transformer Control Statements

assignStatement := '.' ASSIGN variable [ '.' attribute ] '=' expression endOfLine

variable := name && ! keyword

attribute := name // Allow keyword

// 9.1.5. Tester Control Statements

ifBlock := ifStatement statementBlock { elifStatement statementBlock }*
           [ elseStatement statementBlock ] endIfStatement

ifStatement := '.' IF condition endOfLine

elifStatement := '.' ELIF condition endOfLine

elseStatement := '.' ELSE endOfLine

endIfStatement := '.' END IF endOfLine

// 9.1.6. Function Control Statements

functionBlock := functionStatement { parameterStatement }* statementBlock endFunctionStatement

functionStatement := '.' FUNCTION functionName endOfLine

functionName := name && ! keyword

parameterStatement := '.' PARAM parameterType parameterName endOfLine

parameterType := BOOLEAN | INTEGER | REAL | STRING | INST_REF | INST_REF_SET | FRAG_REF

parameterName := name && ! keyword

endFunctionStatement := '.' END FUNCTION endOfLine

invokeStatement := '.' INVOKE [ variable '=' ] functionName
                   '(' [ actualParameter { ',' actualParameter }* ] ')' endOfLine

actualParameter := rvalue

// 9.1.7. File Control Statements

emitStatement := '.' EMIT TO FILE fileName endOfLine

fileName := stringLiteral

clearStatement := '.' CLEAR endOfLine

includeStatement := '.' INCLUDE fileName endOfLine

printStatement := '.' PRINT errorMessage endOfLine

errorMessage := stringLiteral

exitStatement := '.' EXIT exitStatus endOfLine

exitStatus := integerLiteral

// 9.1.8. Rvalues

rvalue := literalValue | variable [ '.' attribute ] | SELECTED '.' attribute

literalValue := booleanLiteral | integerLiteral | realLiteral | stringLiteral

booleanLiteral := TRUE | FALSE

stringLiteral := stringQuotes { stringLiteralText | substitutionVariable }* stringQuotes

// 9.1.9. Expressions

expression := '(' unaryOperator expression ')'
              | '(' expression binaryOperator expression ')'
              | rvalue

unaryOperator := NOT | EMPTY | NOT_EMPTY | FIRST | NOT_FIRST | LAST | NOT_LAST | CARDINALITY

binaryOperator := AND | OR | '+' | '-' | '*' | '/' | '%' | '<' | "<=" | "==" | "!=" | ">=" | '>'

// 9.1.10. Substitution Variables

substitutionVariable := substitutionFormat
                        ( instanceChain '.' attribute [ ':' parseKeyword ]
                        | variable [ '.' attribute [ ':' parseKeyword ] ]
                        | INFO '.' informationAttribute
                        | SELECTED { relationshipTraversal }* '.' attribute [ ':' parseKeyword ] )
                        endOfSubstitution

parseKeyword := name // Allow keyword

informationAttribute := DATE | USER_ID | ARCH_FILE_LINE | ARCH_FILE_NAME
                        | INTERPRETER_PLATFORM | INTERPRETER_VERSION | UNIQUE_NUM

ArchetypeLanguage :: // Lexical Rules

input := { literalTextLineInput | commentLine | controlStatementLine }*

literalTextLineInput := { literalText | substitutionVariableInput }*
                        && ( { whitespace }* ( ! '.' | ".." ) ) endOfLine

literalText ::= { ! '$' ! '\n' $anyCharacter | "$$" }+

substitutionVariableInput := substitutionFormat { whitespace | token }* endOfSubstitution

substitutionFormat ::= '$' [ 'U' | 'u' | 'C' | 'c' | 'L' | 'l' ] [ '_' | 'R' | 'r' ] '{'

whitespace := ! '\n' $javaWhitespace

endOfSubstitution ::= '}'

endOfLine ::= $endOfLine

commentLine := { whitespace }* '.' ( "//" | nonTokenCOMMENT ) { ! '\n' $anyCharacter }* $endOfLine

nonTokenCOMMENT := ( "comment" | "COMMENT" | "Comment" ) ! namePart

controlStatementLine := { whitespace | token }* endOfLine

// Tokens

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

name ::= nameStart { namePart }*

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

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

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

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

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

stringLiteralInput := stringQuotes { stringLiteralText | substitutionVariableInput }* stringQuotes

stringQuotes ::= '"'

stringLiteralText ::= { ! '$' ! '"' ! '\n' $anyCharacter | "$$" | "\"\"" }+

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

// Special Name Tokens

relationshipID ::= ( 'R' | 'r' ) '1'..'9' { '0'..'9' }* ! namePart

keyword := AND | ANY | ARCH_FILE_LINE | ARCH_FILE_NAME | ASSIGN
           | BODY | BOOLEAN | BREAK | BY
           | CARDINALITY | CLEAR | COMMENT
           | DATE
           | EACH | ELIF | ELSE | EMIT | EMPTY | END | EXIT
           | FALSE | FILE | FIRST | FOR | FRAG_REF | FROM | FUNCTION
           | IF | IN | INCLUDE | INFO | INSTANCES | INST_REF | INST_REF_SET | INTEGER
                | INTERPRETER_PLATFORM | INTERPRETER_VERSION | INVOKE | IR
           | LAST
           | MANY
           | NOT | NOT_EMPTY | NOT_FIRST | NOT_LAST
           | OF | ONE | OR
           | PARAM | PRINT
           | REAL | RELATED | RI
           | SELECT | SELECTED | STRING
           | TO | TRUE
           | UNIQUE_NUM | USER_ID
           | WHERE | WHILE

AND                  ::= ( "and"                  | "AND"                  | "And"                  ) ! namePart
ANY                  ::= ( "any"                  | "ANY"                  | "Any"                  ) ! namePart
ARCH_FILE_LINE       ::= ( "arch_file_line"       | "ARCH_FILE_LINE"       | "Arch_file_line"       ) ! namePart
ARCH_FILE_NAME       ::= ( "arch_file_name"       | "ARCH_FILE_NAME"       | "Arch_file_name"       ) ! namePart
ASSIGN               ::= ( "assign"               | "ASSIGN"               | "Assign"               ) ! namePart
BODY                 ::= ( "body"                 | "BODY"                 | "Body"                 ) ! namePart
BOOLEAN              ::= ( "boolean"              | "BOOLEAN"              | "Boolean"              ) ! namePart
BREAK                ::= ( "break"                | "BREAK"                | "Break"                ) ! namePart
BY                   ::= ( "by"                   | "BY"                   | "By"                   ) ! namePart
CARDINALITY          ::= ( "cardinality"          | "CARDINALITY"          | "Cardinality"          ) ! namePart
CLEAR                ::= ( "clear"                | "CLEAR"                | "Clear"                ) ! namePart
COMMENT              ::= ( "comment"              | "COMMENT"              | "Comment"              ) ! namePart
DATE                 ::= ( "date"                 | "DATE"                 | "Date"                 ) ! namePart
EACH                 ::= ( "each"                 | "EACH"                 | "Each"                 ) ! namePart
ELIF                 ::= ( "elif"                 | "ELIF"                 | "Elif"                 ) ! namePart
ELSE                 ::= ( "else"                 | "ELSE"                 | "Else"                 ) ! namePart
EMIT                 ::= ( "emit"                 | "EMIT"                 | "Emit"                 ) ! namePart
EMPTY                ::= ( "empty"                | "EMPTY"                | "Empty"                ) ! namePart
END                  ::= ( "end"                  | "END"                  | "End"                  ) ! namePart
EXIT                 ::= ( "exit"                 | "EXIT"                 | "Exit"                 ) ! namePart
FALSE                ::= ( "false"                | "FALSE"                | "False"                ) ! namePart
FILE                 ::= ( "file"                 | "FILE"                 | "File"                 ) ! namePart
FIRST                ::= ( "first"                | "FIRST"                | "First"                ) ! namePart
FOR                  ::= ( "for"                  | "FOR"                  | "For"                  ) ! namePart
FRAG_REF             ::= ( "frag_ref"             | "FRAG_REF"             | "Frag_ref"             ) ! namePart
FROM                 ::= ( "from"                 | "FROM"                 | "From"                 ) ! namePart
FUNCTION             ::= ( "function"             | "FUNCTION"             | "Function"             ) ! namePart
IF                   ::= ( "if"                   | "IF"                   | "If"                   ) ! namePart
IN                   ::= ( "in"                   | "IN"                   | "In"                   ) ! namePart
INCLUDE              ::= ( "include"              | "INCLUDE"              | "Include"              ) ! namePart
INFO                 ::= ( "info"                 | "INFO"                 | "Info"                 ) ! namePart
INSTANCES            ::= ( "instances"            | "INSTANCES"            | "Instances"            ) ! namePart
INST_REF             ::= ( "inst_ref"             | "INST_REF"             | "Inst_ref"             ) ! namePart
INST_REF_SET         ::= ( "inst_ref_set"         | "INST_REF_SET"         | "Inst_ref_set"         ) ! namePart
INTEGER              ::= ( "integer"              | "INTEGER"              | "Integer"              ) ! namePart
INTERPRETER_PLATFORM ::= ( "interpreter_platform" | "INTERPRETER_PLATFORM" | "Interpreter_platform" ) ! namePart
INTERPRETER_VERSION  ::= ( "interpreter_version"  | "INTERPRETER_VERSION"  | "Interpreter_version"  ) ! namePart
INVOKE               ::= ( "invoke"               | "INVOKE"               | "Invoke"               ) ! namePart
IR                   ::= ( "ir"                   | "IR"                   | "Ir"                   ) ! namePart
LAST                 ::= ( "last"                 | "LAST"                 | "Last"                 ) ! namePart
MANY                 ::= ( "many"                 | "MANY"                 | "Many"                 ) ! namePart
NOT                  ::= ( "not"                  | "NOT"                  | "Not"                  ) ! namePart
NOT_EMPTY            ::= ( "not_empty"            | "NOT_EMPTY"            | "Not_empty"            ) ! namePart
NOT_FIRST            ::= ( "not_first"            | "NOT_FIRST"            | "Not_first"            ) ! namePart
NOT_LAST             ::= ( "not_last"             | "NOT_LAST"             | "Not_last"             ) ! namePart
OF                   ::= ( "of"                   | "OF"                   | "Of"                   ) ! namePart
ONE                  ::= ( "one"                  | "ONE"                  | "One"                  ) ! namePart
OR                   ::= ( "or"                   | "OR"                   | "Or"                   ) ! namePart
PARAM                ::= ( "param"                | "PARAM"                | "Param"                ) ! namePart
PRINT                ::= ( "print"                | "PRINT"                | "Print"                ) ! namePart
REAL                 ::= ( "real"                 | "REAL"                 | "Real"                 ) ! namePart
RELATED              ::= ( "related"              | "RELATED"              | "Related"              ) ! namePart
RI                   ::= ( "ri"                   | "RI"                   | "Ri"                   ) ! namePart
SELECT               ::= ( "select"               | "SELECT"               | "Select"               ) ! namePart
SELECTED             ::= ( "selected"             | "SELECTED"             | "Selected"             ) ! namePart
STRING               ::= ( "string"               | "STRING"               | "String"               ) ! namePart
TO                   ::= ( "to"                   | "TO"                   | "To"                   ) ! namePart
TRUE                 ::= ( "true"                 | "TRUE"                 | "True"                 ) ! namePart
UNIQUE_NUM           ::= ( "unique_num"           | "UNIQUE_NUM"           | "Unique_num"           ) ! namePart
USER_ID              ::= ( "user_id"              | "USER_ID"              | "User_id"              ) ! namePart
WHERE                ::= ( "where"                | "WHERE"                | "Where"                ) ! namePart
WHILE                ::= ( "while"                | "WHILE"                | "While"                ) ! namePart

// End of File