Clinical Decision Support Work Group | Maturity Level: 4 | Ballot Status: STU 2.1 |
The formal specification for the CQL syntax is defined using the ANTLR4 grammar framework. This framework is a general purpose cross-platform technology for describing computer languages. For more information on this framework, refer to the ANTLR website http://www.antlr.org/.
The material in this section is necessarily technical and assumes familiarity with language definition in general, and ANTLR4 grammars in particular. In addition, the g4 presented here is somewhat simplified for ease of reference and is provided for informative use only. For the complete, normative g4 definition, refer to the CQL.g4 file included with the specification package.
The CQL grammar is defined in a single ANTLR4 grammar file, CQL.g4. The root production rule is library, which specifies the overall structure for a library file:
library
:
libraryDefinition?
usingDefinition*
includeDefinition*
codesystemDefinition*
valuesetDefinition*
codeDefinition*
conceptDefinition*
parameterDefinition*
statement*
;
Other than statement, these production rules define the declarations available for a library.
libraryDefinition
: 'library' identifier ('version' versionSpecifier)?
;
usingDefinition
: 'using' modelIdentifier ('version' versionSpecifier)?
;
includeDefinition
: 'include' identifier ('version' versionSpecifier)? ('called' localIdentifier)?
;
localIdentifier
: identifier
;
accessModifier
: 'public'
| 'private'
;
parameterDefinition
: accessModifier? 'parameter' identifier typeSpecifier? ('default' expression)?
;
codesystemDefinition
: accessModifier? 'codesystem' identifier ':' codesystemId
('version' versionSpecifier)?
;
valuesetDefinition
: accessModifier? 'valueset' identifier ':' valuesetId
('version' versionSpecifier)? codesystems?
;
codesystems
: 'codesystems' '\{' codesystemIdentifier (',' codesystemIdentifier)* '}'
;
codesystemIdentifier
: (libraryIdentifier '.')? identifier
;
libraryIdentifier
: identifier
;
codeDefinition
: accessModifier? 'code' identifier ':' codeId
'from' codesystemIdentifier displayClause?
;
conceptDefinition
: accessModifier? 'concept' identifier ':' '\{' codeIdentifier
(',' codeIdentifier)* '}' displayClause?
;
codeIdentifier
: (libraryIdentifier '.')? identifier
;
codesystemId
: STRING
;
valuesetId
: STRING
;
versionSpecifier
: STRING
;
codeId
: STRING
;
The typeSpecifier production rule defines all type specifiers available in the language.
typeSpecifier
: namedTypeSpecifier
| listTypeSpecifier
| intervalTypeSpecifier
| tupleTypeSpecifier
| choiceTypeSpecifier
;
namedTypeSpecifier
: (modelIdentifier '.')? identifier
;
modelIdentifier
: identifier
;
listTypeSpecifier
: 'List' '<' typeSpecifier '>'
;
intervalTypeSpecifier
: 'Interval' '<' typeSpecifier '>'
;
tupleTypeSpecifier
: 'Tuple' '\{' tupleElementDefinition (',' tupleElementDefinition)* '}'
;
tupleElementDefinition
: identifier typeSpecifier
;
choiceTypeSpecifier
: 'Choice' '<' typeSpecifier (',' typeSpecifier)* '>'
;
The main body of the library then consists of any number of statements, defined by the statement production rule:
statement
: expressionDefinition
| contextDefinition
| functionDefinition
;
expressionDefinition
: 'define' accessModifier? identifier ':' expression
;
contextDefinition
: 'context' identifier
;
functionDefinition
: 'define' accessModifier? 'function' identifier
'(' (operandDefinition (',' operandDefinition)*)? ')'
('returns' typeSpecifier)?
':' (functionBody | 'external')
;
operandDefinition
: identifier typeSpecifier
;
functionBody
: expression
;
The query production rule defines the syntax for queries within CQL:
querySource
: retrieve
| qualifiedIdentifier
| '(' expression ')'
;
aliasedQuerySource
: querySource alias
;
alias
: identifier
;
queryInclusionClause
: withClause
| withoutClause
;
withClause
: 'with' aliasedQuerySource 'such that' expression
;
withoutClause
: 'without' aliasedQuerySource 'such that' expression
;
retrieve
: '[' namedTypeSpecifier (':' (codePath 'in')? terminology)? ']'
;
codePath
: identifier
;
terminology
: qualifiedIdentifier
| expression
;
qualifier
: identifier
;
query
: sourceClause
letClause?
queryInclusionClause*
whereClause?
returnClause?
sortClause?
;
sourceClause
: singleSourceClause
| multipleSourceClause
;
singleSourceClause
: aliasedQuerySource
;
multipleSourceClause
: 'from' aliasedQuerySource (',' aliasedQuerySource)*
;
letClause
: 'let' letClauseItem (',' letClauseItem)*
;
letClauseItem
: identifier ':' expression
;
whereClause
: 'where' expression
;
returnClause
: 'return' ('all' | 'distinct')? expression
;
sortClause
: 'sort' ( sortDirection | ('by' sortByItem (',' sortByItem)*) )
;
sortDirection
: 'asc' | 'ascending'
| 'desc' | 'descending'
;
sortByItem
: expressionTerm sortDirection?
;
qualifiedIdentifier
: (qualifier '.')* identifier
;
The expression production rule defines the syntax for all expressions within CQL:
expression
: expressionTerm
| retrieve
| query
| expression 'is' 'not'? ('null' | 'true' | 'false')
| expression ('is' | 'as') typeSpecifier
| 'cast' expression 'as' typeSpecifier
| 'not' expression
| 'exists' expression
| expression 'properly'? 'between' expressionTerm 'and' expressionTerm
| pluralDateTimePrecision 'between' expressionTerm 'and' expressionTerm
| 'difference' 'in'
pluralDateTimePrecision 'between' expressionTerm 'and' expressionTerm
| expression ('⇐' | '<' | '>' | '>=') expression
| expression intervalOperatorPhrase expression
| expression ('=' | '!=' | '!=' | '~' | '!~') expression
| expression ('in' | 'contains') dateTimePrecisionSpecifier? expression
| expression 'and' expression
| expression ('or' | 'xor') expression
| expression 'implies' expression
| expression ('|' | 'union' | 'intersect' | 'except') expression
;
dateTimePrecision
: 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond'
;
dateTimeComponent
: dateTimePrecision
| 'date'
| 'time'
| 'timezone'
;
pluralDateTimePrecision
: 'years' | 'months' | 'weeks' | 'days'
| 'hours' | 'minutes' | 'seconds' | 'milliseconds'
;
expressionTerm
: term
| expressionTerm '.' invocation
| expressionTerm '[' expression ']'
| 'convert' expression 'to' typeSpecifier
| ('+' | '-') expressionTerm
| ('start' | 'end') 'of' expressionTerm
| dateTimeComponent 'from' expressionTerm
| 'duration' 'in' pluralDateTimePrecision 'of' expressionTerm
| 'width' 'of' expressionTerm
| 'successor' 'of' expressionTerm
| 'predecessor' 'of' expressionTerm
| 'singleton' 'from' expressionTerm
| 'point' 'from' expressionTerm
| ('minimum' | 'maximum') namedTypeSpecifier
| expressionTerm '^' expressionTerm
| expressionTerm ('*' | '/' | 'div' | 'mod') expressionTerm
| expressionTerm ('+' | '-' | '&') expressionTerm
| 'if' expression 'then' expression 'else' expression
| 'case' expression? caseExpressionItem+ 'else' expression 'end'
| ('distinct' | 'collapse' | 'flatten') expression
;
caseExpressionItem
: 'when' expression 'then' expression
;
dateTimePrecisionSpecifier
: dateTimePrecision 'of'
;
relativeQualifier
: 'or before'
| 'or after'
;
offsetRelativeQualifier
: 'or more'
| 'or less'
;
exclusiveRelativeQualifier
: 'more than'
| 'less than'
;
quantityOffset
: (quantityLiteral offsetRelativeQualifier? )
| (exclusiveRelativeQualifier quantityLiteral)
;
intervalOperatorPhrase
: ('starts' | 'ends' | 'occurs')? 'same' dateTimePrecision?
(relativeQualifier | 'as') ('start' | 'end')?
| 'properly'? 'includes' dateTimePrecisionSpecifier? ('start' | 'end')?
| ('starts' | 'ends' | 'occurs')? 'properly'? ('during' | 'included in')
dateTimePrecisionSpecifier?
| ('starts' | 'ends' | 'occurs')? quantityOffset? ('before' | 'after')
('start' | 'end')?
| ('starts' | 'ends' | 'occurs')? 'properly'? 'within' quantityLiteral 'of'
('start' | 'end')?
| 'meets' ('before' | 'after')? dateTimePrecisionSpecifier?
| 'overlaps' ('before' | 'after')? dateTimePrecisionSpecifier?
| 'starts' dateTimePrecisionSpecifier?
| 'ends' dateTimePrecisionSpecifier?
;
The term production rule defines the syntax for core expression terms within CQL:
term
: invocation
| literal
| externalConstant
| intervalSelector
| tupleSelector
| instanceSelector
| listSelector
| codeSelector
| conceptSelector
| '(' expression ')'
;
invocation
: identifier
| identifier '(' expression (',' expression)*')'
| '$this'
;
intervalSelector
'Interval' ('['|'(') expression ',' expression (']'|')')
;
tupleSelector
: 'Tuple'? '\{' (':' | (tupleElementSelector (',' tupleElementSelector)*)) '}'
;
tupleElementSelector
: identifier ':' expression
;
instanceSelector
: namedTypeSpecifier '\{' (':' | (instanceElementSelector
(',' instanceElementSelector)*)) '}'
;
instanceElementSelector
: identifier ':' expression
;
listSelector
: ('List' ('<' typeSpecifier '>')?)? '\{' expression? (',' expression)* '}'
;
displayClause
: 'display' stringLiteral
;
codeSelector
: 'Code' stringLiteral 'from' codesystemIdentifier displayClause?
;
conceptSelector
: 'Concept' '\{' codeSelector (',' codeSelector)* '}' displayClause?
;
literal
: nullLiteral
| booleanLiteral
| stringLiteral
| dateTimeLiteral
| timeLiteral
| quantityLiteral
;
nullLiteral
: 'null'
;
booleanLiteral
: 'true'
| 'false'
;
stringLiteral
: STRING
;
dateTimeLiteral
: DATETIME
;
timeLiteral
: TIME
;
quantityLiteral
: QUANTITY unit?
;
unit
: dateTimePrecision
| pluralDateTimePrecision
| STRING // UCUM syntax for units of measure
;
identifier
: IDENTIFIER | QUOTEDIDENTIFIER
| 'all'
| 'Code'
| 'Concept'
| 'contains'
| 'date'
| 'display'
| 'distinct'
| 'end'
| 'exists'
| 'not'
| 'start'
| 'time'
| 'timezone'
| 'version'
| 'where'
;
The lexer rules define the terminal production rules in the language:
IDENTIFIER
: ([A-Za-z] | '')([A-Za-z0-9] | '')*
;
QUANTITY
: ('.'[0-9])?
;
QUOTEDIDENTIFIER
: '"' (ESC | .)*? '"'
;
STRING
: ('\'') (ESC | .)*? ('\'')
;
WS
: (' ' | '\r' | '\t') → channel(HIDDEN)
;
NEWLINE
: ('\n') → channel(HIDDEN)
;
COMMENT
: '/' .? '/' *→ channel(HIDDEN)
;
LINE_COMMENT
: '//' ~[\r\n]* → channel(HIDDEN)
;