Skip to content
This repository was archived by the owner on Dec 12, 2022. It is now read-only.

Document Notation

Derk Norton edited this page Sep 3, 2021 · 53 revisions

Bali Document Notation™

The follow sections define the formal language specification (using the ANTLR 4 language syntax) for the Bali Document Notation™.

Components

This section defines the rules that are used to define components. For a graphical view of these rules click here.

component: value parameters? note?;

value: element | sequence | procedure;

parameters: '(' catalog ')';

note: NOTE;

sequence: '[' collection ']';

collection: range | list | catalog;

range: expression? connector=('<..<' | '<..' | '..<' | '..') expression?;

list:
    expression (',' expression)* |
    EOL (expression EOL)* |
    /* no items */
;

catalog:
    association (',' association)* |
    EOL (association EOL)* |
    ':' /* no associations */
;

association: element ':' expression;

procedure: '{' code '}';

code:
    statement (';' statement)* |
    EOL (statement EOL)* |
    /* no statements */
;

Statements

This section defines the rules that are used to define statements. For a graphical view of these rules click here.

statement: comment | mainClause handleClause?;

comment: NOTE | COMMENT;

mainClause:
    evaluateClause |
    saveClause |
    discardClause |
    signClause |
    checkoutClause |
    publishClause |
    postClause |
    retrieveClause |
    acceptClause |
    rejectClause |
    ifClause |
    selectClause |
    withClause |
    whileClause |
    continueClause |
    breakClause |
    returnClause |
    throwClause
;

handleClause: 'handle' symbol (('with' block) | ('matching' expression 'with' block)+);

block: '{' code '}';

evaluateClause: (recipient operator=(':=' | '+=' | '-=' | '*='))? expression;

// save document as $citation
saveClause: 'save' expression ('as' recipient)?;

// discard document
discardClause: 'discard' expression;

// sign contract as /acme/reports/Q3/v1.4
signClause: 'sign' expression 'as' expression;

// checkout level 2 of $contract from /acme/reports/Q3/v1.3.6
checkoutClause: 'checkout' ('level' expression 'of')? recipient 'from' expression;

// publish event
publishClause: 'publish' expression;

// post message to /acme/blogs/v3.2
postClause: 'post' expression 'to' expression;

// retrieve $message from /acme/blogs/v3.2
retrieveClause: 'retrieve' recipient 'from' expression;

// accept message
acceptClause: 'accept' expression;

// reject message
rejectClause: 'reject' expression;

ifClause: 'if' expression 'then' block ('else' 'if' expression 'then' block)* ('else' block)?;

selectClause: 'select' expression 'from' (expression 'do' block)+ ('else' block)?;

withClause: 'with' ('each' symbol 'in')? expression 'do' block;

whileClause: 'while' expression 'do' block;

continueClause: 'continue' 'loop';

breakClause: 'break' 'loop';

returnClause: 'return' expression?;

throwClause: 'throw' expression;

recipient: symbol | attribute;

attribute: variable '[' indices ']';

Expressions

This section defines the rules that are used to define expressions. For a graphical view of these rules click here.

expression:                  // Precedence (highest to lowest)
    component                                                            #componentExpression     |
    variable                                                             #variableExpression      |
    function '(' arguments ')'                                           #functionExpression      |
    '(' expression ')'                                                   #precedenceExpression    |
    '@' expression                                                       #dereferenceExpression   |
    expression operator=('.' | '<-') message '(' arguments ')'           #messageExpression       |
    expression '[' indices ']'                                           #attributeExpression     |
    expression '&' expression                                            #concatenationExpression |
    expression '!'                                                       #factorialExpression     |
    <assoc=right> expression '^' expression                              #exponentialExpression   |
    operator=('-' | '/' | '*') expression                                #inversionExpression     |
    expression operator=('*' | '/' | '//' | '+' | '-') expression        #arithmeticExpression    |
    '|' expression '|'                                                   #magnitudeExpression     |
    expression operator=('<' | '=' | '>' | 'IS' | 'MATCHES') expression  #comparisonExpression    |
    'NOT' expression                                                     #complementExpression    |
    expression operator=('AND' | 'SANS' | 'XOR' | 'OR') expression       #logicalExpression       |
    expression '?' expression                                            #defaultExpression
;

variable: IDENTIFIER;

function: IDENTIFIER;

message: IDENTIFIER;

arguments:
    expression (',' expression)* |
    /* no expressions */
;


indices: expression (',' expression)*;

Elements

This section defines the rules that are used to define elements. For a graphical view of these rules click here.

element:
    angle |
    binary |
    boolean |
    duration |
    moment |
    name |
    number |
    pattern |
    percentage |
    probability |
    resource |
    symbol |
    tag |
    text |
    version
;

angle: ANGLE;

binary: BINARY;

boolean: 'false' | 'true';

duration: DURATION;

moment: MOMENT;

name: NAME;

real: '-'? REAL;

imaginary: '-'? IMAGINARY;

number:
    'undefined' |
    '0' |
    '∞' |
    'infinity' |
    real |
    imaginary |
    '(' real (',' imaginary | 'e^' angle 'i') ')'
;

pattern: 'none' | REGEX | 'any';

percentage: PERCENTAGE;

probability: FRACTION | '1.';

resource: RESOURCE;

symbol: SYMBOL;

tag: TAG;

text: QUOTE | NARRATIVE;

version: VERSION;

Tokens

This section defines the rules that are used to define tokens. For a graphical view of these rules click here.

/* TOKEN RULES
 It's important to remember that tokens are recognized by the
 lexer in the order declared. The longest first matching token
 is returned regardless of how many others might match. Also,
 prefix any tokens that are just used as subtokens with the
 "fragment" keyword.
*/

ANGLE: '~' ('0' | '-'? REAL);

BINARY: '\'' (BASE64 | SPACE)* ('=' ('=')?)? SPACE* '\'';

DURATION: '~' '-'? 'P' (SPAN 'W' | (SPAN 'Y')? (SPAN 'M')? (SPAN 'D')? ('T' (SPAN 'H')? (SPAN 'M')? (SPAN 'S')?)?);

FRACTION: '.' ('0'..'9')+;

PERCENTAGE: ('0' | '-'? REAL) '%';

// Note: An imaginary number must be higher precedence than a real number.
IMAGINARY: FLOAT 'i' | 'e i' | 'pi i' | 'π i' | 'phi i' | 'φ i' | 'tau i' | 'τ i';

REAL: FLOAT | 'e' | 'pi' | 'π' | 'phi' | 'φ' | 'tau' | 'τ';

MOMENT: '<' YEARS ('-' MONTHS ('-' DAYS ('T' HOURS (':' MINUTES (':' SECONDS FRACTION?)?)?)?)?)? '>';

NAME: ('/' LABEL)+;

RESOURCE: '<' LABEL ':' CONTEXT '>';

REGEX: '"' TEXT '"?';

SYMBOL: '$' IDENTIFIER ('-' NUMBER)?;

TAG: '#' BASE32*;

// Note: A narrative takes precedence over a quote and may contain any character.
NARRATIVE: '"' EOL CHARACTER*? EOL SPACE* '"';

QUOTE: '"' TEXT '"';

// Note: A version like 'v12' takes precedence over an identifier like 'value'.
VERSION: 'v' NUMBER ('.' NUMBER)*;

IDENTIFIER: ('a'..'z'|'A'..'Z') ('a'..'z'|'A'..'Z'|'0'..'9')*;

NOTE: '--' ~[\r\n]*;

COMMENT: '/*' EOL (COMMENT | CHARACTER)*? EOL SPACE* '*/';

EOL: '\r'? '\n';

SPACE: ('\t'..'\r' | ' ') -> channel(HIDDEN);

fragment
TEXT: (ESCAPE | '\\"' | ~["\r\n])*?;

fragment
CHARACTER: .;

fragment
NUMBER: '1'..'9' ('0'..'9')*;

fragment
FLOAT: (NUMBER FRACTION? | '0' FRACTION) ('E' '-'? NUMBER)?;

fragment
INTEGER: '0' | '-'? NUMBER;

fragment
SPAN: INTEGER FRACTION?;

fragment
LABEL: ('a'..'z' | 'A'..'Z' | '0'..'9' | '+' | '-' | '.')+;

fragment
CONTEXT: ('!'..'=' | '?'..'~')*;  // skip the space and '>' characters

fragment
YEARS: INTEGER;

fragment
MONTHS: (('0' '0'..'9') | ('1' '0'..'2'));

fragment
DAYS: (('0'..'2' '0'..'9') | ('3' '0'..'1'));

fragment
HOURS: (('0'..'1' '0'..'9') | ('2' '0'..'3'));

fragment
MINUTES: ('0'..'5' '0'..'9');

// Note: We must include 60 to handle leap seconds.
fragment
SECONDS: (('0'..'5' '0'..'9') | '60');

fragment
BASE16: '0'..'9' | 'A'..'F';

// Note: This avoids confusion and possible offensive strings by eliminating
//       the 'E', 'I', 'O', and 'U' characters.
fragment
BASE32: '0'..'9' | 'A'..'D' | 'F'..'H' | 'J'..'N' | 'P'..'T' | 'V'..'Z';

fragment
BASE64: '0'..'9' | 'A'..'Z' | 'a'..'z' | '+' | '/';

// Note: The escaped sequences are replaced with actual characters when read.
fragment
ESCAPE: '\\' ('u' BASE16+ | 'b' | 'f' | 'r' | 'n' | 't' | '\\');

Clone this wiki locally