Syntax Specification

The grammar and lexical specification for the standard Expression syntax is shown below in ANTLR4 form.

//
//  description: Antlr4 grammar for openEHR Rules core syntax.
//  author:      Thomas Beale <thomas.beale@openehr.org>
//  contributors:Pieter Bos <pieter.bos@nedap.com>
//  support:     openEHR Specifications PR tracker <https://openehr.atlassian.net/projects/SPECPR/issues>
//  copyright:   Copyright (c) 2016- openEHR Foundation <http://www.openEHR.org>
//  license:     Apache 2.0 License <http://www.apache.org/licenses/LICENSE-2.0.html>
//

grammar base_expressions;
import cadl2_primitives, odin_values;

//
//  ======================= Top-level _objects ========================
//

statement_block: statement+ ;

// ------------------------- statements ---------------------------
statement: declaration | assignment | assertion;

declaration:
      variable_declaration
    | constant_declaration
    ;

variable_declaration: local_variable ':' type_id ( SYM_ASSIGNMENT expression )? ;

constant_declaration: constant_name ':' type_id  ( SYM_EQ primitive_object )? ;

assignment:
      binding
    | local_assignment
    ;

//
// The following is the means of binding a data context path to a local variable
// TODO: remove this rule when proper external bindings are supported
binding: local_variable SYM_ASSIGNMENT bound_path ;

local_assignment: local_variable SYM_ASSIGNMENT expression ;

assertion: ( ( ALPHA_LC_ID | ALPHA_UC_ID ) ':' )? boolean_expr ;

//
// -------------------------- _expressions --------------------------
//
expression:
      boolean_expr
    | arithmetic_expr
    ;

//
// _expressions evaluating to boolean values, using standard precedence
// The equality_binop ones are not strictly necessary, but allow the use
// of boolean_leaf = true, which some people like
//
boolean_expr:
      SYM_NOT boolean_expr
    | boolean_expr SYM_AND boolean_expr
    | boolean_expr SYM_XOR boolean_expr
    | boolean_expr SYM_OR boolean_expr
    | boolean_expr SYM_IMPLIES boolean_expr
    | boolean_leaf equality_binop boolean_leaf
    | boolean_leaf
    ;

//
// Atomic Boolean-valued expression elements
// TODO: SYM_EXISTS alternative to be replaced by defined() predicate
boolean_leaf:
      boolean_literal
    | for_all_expr
    | there_exists_expr
    | SYM_EXISTS ( bound_path | sub_path_local_variable )
    | '(' boolean_expr ')'
    | relational_expr
    | equality_expr
    | constraint_expr
    | value_ref
    ;

boolean_literal:
      SYM_TRUE
    | SYM_FALSE
    ;

//
//  Universal and existential quantifier
// TODO: 'in' probably isn't needed in the long term
for_all_expr: SYM_FOR_ALL VARIABLE_ID ( ':' | 'in' ) value_ref '|'? boolean_expr ;

there_exists_expr: SYM_THERE_EXISTS VARIABLE_ID ( ':' | 'in' ) value_ref '|'? boolean_expr ;

// Constraint expressions
// This provides a way of using one operator (matches) to compare a
// value (LHS) with a value range (RHS). As per ADL, the value range
// for ordered types like Integer, Date etc may be a single value,
// a list of values, or a list of intervals, and in future, potentially
// other comparators, including functions (e.g. divisible_by_N).
//
// For non-ordered types like String and Terminology_code, the RHS
// is in other forms, e.g. regex for Strings.
//
// The matches operator can be used to generate a Boolean value that
// may be used within an expression like any other Boolean (hence it
// is a booleanLeaf).
// TODO: non-primitive objects might be supported on the RHS in future.
constraint_expr: ( arithmetic_expr | value_ref ) SYM_MATCHES  ( '{' c_inline_primitive_object '}' | CONTAINED_REGEXP );

//
// _expressions evaluating to arithmetic values, using standard precedence
//
arithmetic_expr:
      <assoc=right> arithmetic_expr '^' arithmetic_expr
    | arithmetic_expr ( '/' | '*' | '%' ) arithmetic_expr
    | arithmetic_expr ( '+' | '-' ) arithmetic_expr
    | arithmetic_leaf
    ;

arithmetic_leaf:
      integer_value
    | real_value
    | date_value
    | date_time_value
    | time_value
    | duration_value
    | value_ref
    | '(' arithmetic_expr ')'
    ;

//
// Equality expression between any arithmetic value; precedence is
// lowest, so only needed between leaves, since () will be needed for
// larger expressions anyway
//
equality_expr: arithmetic_expr equality_binop arithmetic_expr ;

equality_binop:
      SYM_EQ
    | SYM_NE
    ;

//
// Relational expressions of arithmetic operands generating Boolean values
//
relational_expr: arithmetic_expr relational_binop arithmetic_expr ;

relational_binop:
      SYM_GT
    | SYM_LT
    | SYM_LE
    | SYM_GE
    ;

//
// instances references: data references, variables, and function calls.
// TODO: Remove bound_path from this rule when external binding supported
//
value_ref:
      function_call
    | bound_path
    | sub_path_local_variable
    | local_variable
    | constant_name
    ;

local_variable: VARIABLE_ID ;

// TODO: change to [] form, e.g.     book_list [{title.contains("Quixote")}]
sub_path_local_variable: VARIABLE_WITH_PATH;

// TODO: Remove this rule when external binding supported
bound_path: ADL_PATH ;

constant_name: ALPHA_UC_ID ;

function_call: ALPHA_LC_ID '(' function_args? ')' ;

function_args: expression ( ',' expression )* ;

type_id: ALPHA_UC_ID ( '<' type_id ( ',' type_id )* '>' )? ;