Skip to content

TEDEFO-4546-4547-summary-and-navigation-sections #1243

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 51 additions & 27 deletions efx-grammar/Efx.g4
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ options { tokenVocab=EfxLexer;}
* Currently we only allow a field-identifier or a node-identifier in the context-declaration.
* We may also add support for adding one or more predicates to the context-declaration in the future.
*/
singleExpression: StartExpression context=(FieldId | NodeId | Identifier) (Comma parameterList)? EndExpression expressionBlock EOF;
singleExpression: StartExpressionBlock context=(FieldId | NodeId | Identifier) (Comma parameterList)? EndBlock expressionBlock EOF;

/*
* An EFX template-file consists of:
Expand All @@ -52,7 +52,17 @@ singleExpression: StartExpression context=(FieldId | NodeId | Identifier) (Comma
* template-lines which are only visible within the template-block
* in which they are declared.
*/
templateFile: globalDeclaration* templateDeclaration* templateLine* EOF;
templateFile
: globalDeclaration* templateDeclaration* templateLine* otherSections? EOF
;

otherSections
: navigationSection summarySection?
| summarySection navigationSection?
;

summarySection: SummarySection templateLine*;
navigationSection: NavigationSection templateLine*;

/*
* Global-declarations allow the definition of variables and/or functions that can be used throughout the entire template-file.
Expand All @@ -76,7 +86,9 @@ globalVariableDeclaration
;


dictionaryDeclaration: Let VariablePrefix dictionaryName=Identifier Index field=fieldContext By (stringExpression | lateBoundScalar) Semicolon;
dictionaryDeclaration: Let VariablePrefix dictionaryName=Identifier index=dictionaryIndexClause key=dictionaryKeyClause Semicolon;
dictionaryIndexClause: Index field=fieldContext;
dictionaryKeyClause: By (stringExpression | lateBoundScalar);
dictionaryLookup: VariablePrefix dictionaryName=Identifier OpenBracket (stringExpression | lateBoundScalar) CloseBracket;

/*
Expand All @@ -92,7 +104,7 @@ dictionaryLookup: VariablePrefix dictionaryName=Identifier OpenBracket (stringEx
*/
templateLine
: indentation? OutlineNumber? (With contextDeclarationBlock)? (chooseTemplate | displayTemplate | invokeTemplate) Semicolon
| indentation? OutlineNumber? StartExpression contextDeclarationBlock EndExpression template CRLF
| indentation? OutlineNumber? StartExpressionBlock contextDeclarationBlock EndBlock template CRLF
;

/***
Expand All @@ -118,8 +130,17 @@ templateFragment
| textBlock templateFragment? # textTemplate
| labelBlock templateFragment? # labelTemplate
| expressionBlock templateFragment? # expressionTemplate
| linkedTextBlock templateFragment? # linkedTextTemplate
| linkedLabelBlock templateFragment? # linkedLabelTemplate
| linkedExpressionBlock templateFragment? # linkedExpressionTemplate
;

linkBlock: StartHyperlinkBlock stringExpression EndBlock;

linkedTextBlock: textBlock linkBlock;
linkedLabelBlock: labelBlock linkBlock;
linkedExpressionBlock: expressionBlock linkBlock;

/**
* A line-break is a newline character (\n).
* It is used to change line in the template without changing context or indentation.
Expand All @@ -142,15 +163,15 @@ textBlock: (Whitespace | FreeText)+ textBlock*;
* A label-block starts with a # and curly braces, and can contain a standard label reference, computed label, shorthand, or indirect label reference.
*/
labelBlock
: StartLabel assetType Pipe labelType Pipe assetId (Semicolon pluraliser)? EndLabel # standardLabelReference
| StartLabel expressionBlock (Semicolon pluraliser)? EndLabel # computedLabelReference
| StartLabel labelType Pipe BtId (Semicolon pluraliser)? EndLabel # shorthandBtLabelReference
| StartLabel labelType Pipe FieldId (Semicolon pluraliser)? EndLabel # shorthandFieldLabelReference
| StartLabel LabelType (Semicolon pluraliser)? EndLabel # shorthandLabelReferenceFromContext
: StartLabelBlock assetType Pipe labelType Pipe assetId (Semicolon pluraliser)? EndBlock # standardLabelReference
| StartLabelBlock expressionBlock (Semicolon pluraliser)? EndBlock # computedLabelReference
| StartLabelBlock labelType Pipe BtId (Semicolon pluraliser)? EndBlock # shorthandBtLabelReference
| StartLabelBlock labelType Pipe FieldId (Semicolon pluraliser)? EndBlock # shorthandFieldLabelReference
| StartLabelBlock LabelType (Semicolon pluraliser)? EndBlock # shorthandLabelReferenceFromContext
// Indirect Label References ----------------------------------------------------------------------------------------------
// If an assetType and labelType are not specified, then the label reference is an indirect label reference.
// Indirect label references derive the label text from the type and value of field.
| StartLabel FieldId (Semicolon pluraliser)? EndLabel # shorthandIndirectLabelReference
| StartLabelBlock FieldId (Semicolon pluraliser)? EndBlock # shorthandIndirectLabelReference
| ShorthandIndirectLabelReferenceFromContextField # shorthandIndirectLabelReferenceFromContextField
;

Expand Down Expand Up @@ -183,7 +204,7 @@ expressionBlock

standardExpressionBlock
: Let expression Semicolon
| StartExpression expression EndExpression // for backward compatibility
| StartExpressionBlock expression EndBlock // for backward compatibility
;

shorthandFieldValueReferenceFromContextField
Expand Down Expand Up @@ -242,13 +263,13 @@ templateVariableDeclaration
| durationVariableInitializer
;

stringVariableInitializer: Text Colon VariablePrefix variableName=Identifier Assignment (stringExpression | lateBoundExpression);
booleanVariableInitializer: Indicator Colon VariablePrefix variableName=Identifier Assignment (booleanExpression | lateBoundExpression);
numericVariableInitializer: Number Colon VariablePrefix variableName=Identifier Assignment (numericExpression | lateBoundExpression);
dateVariableInitializer : Date Colon VariablePrefix variableName=Identifier Assignment (dateExpression | lateBoundExpression);
timeVariableInitializer: Time Colon VariablePrefix variableName=Identifier Assignment (timeExpression | lateBoundExpression);
durationVariableInitializer: Measure Colon VariablePrefix variableName=Identifier Assignment (durationExpression | lateBoundExpression);
contextVariableInitializer: ContextType Colon VariablePrefix variableName=Identifier Assignment (fieldContext | nodeContext | Slash);
stringVariableInitializer: Text Colon VariablePrefix variableName=identifier Assignment (stringExpression | lateBoundExpression);
booleanVariableInitializer: Indicator Colon VariablePrefix variableName=identifier Assignment (booleanExpression | lateBoundExpression);
numericVariableInitializer: Number Colon VariablePrefix variableName=identifier Assignment (numericExpression | lateBoundExpression);
dateVariableInitializer : Date Colon VariablePrefix variableName=identifier Assignment (dateExpression | lateBoundExpression);
timeVariableInitializer: Time Colon VariablePrefix variableName=identifier Assignment (timeExpression | lateBoundExpression);
durationVariableInitializer: Measure Colon VariablePrefix variableName=identifier Assignment (durationExpression | lateBoundExpression);
contextVariableInitializer: ContextType Colon VariablePrefix variableName=identifier Assignment (fieldContext | nodeContext | Slash);

functionDeclaration
: stringFunctionDeclaration
Expand Down Expand Up @@ -300,7 +321,7 @@ parameterDeclaration
// The parameterValue rule below defines the valid parameter values.
// A parameter value must be enclosed in an expression block so that the EFX lexer can switch
// from its DEFAULT mode to EXPRESSION mode in order to recognise the parameter value.
parameterValue: StartExpression (stringLiteral | numericLiteral | dateLiteral | timeLiteral | durationLiteral | booleanLiteral) EndExpression;
parameterValue: StartExpressionBlock (stringLiteral | numericLiteral | dateLiteral | timeLiteral | durationLiteral | booleanLiteral) EndBlock;


/**************************************
Expand Down Expand Up @@ -563,6 +584,9 @@ durationLiteral: DayTimeDurationLiteral | YearMonthDurationLiteral;
References
**************************************/

// This allows some EFX keywords to be used as identifiers when they are appropriately prefixed.
identifier: Identifier | Code | Text | Number | Indicator | Date | Time | Measure | ContextType | Template;

textTypeCast: OpenParenthesis Text CloseParenthesis;
booleanTypeCast: OpenParenthesis Indicator CloseParenthesis;
numericTypeCast: OpenParenthesis Number CloseParenthesis;
Expand All @@ -579,13 +603,13 @@ timeSequenceTypeCast: OpenParenthesis Time Star CloseParenthesis;
durationSequenceTypeCast: OpenParenthesis Measure Star CloseParenthesis;
contextSequenceTypeCast: OpenParenthesis ContextType Star CloseParenthesis;

stringVariableDeclaration: Text Colon VariablePrefix variableName=Identifier;
booleanVariableDeclaration: Indicator Colon VariablePrefix variableName=Identifier;
numericVariableDeclaration: Number Colon VariablePrefix variableName=Identifier;
dateVariableDeclaration: Date Colon VariablePrefix variableName=Identifier;
timeVariableDeclaration: Time Colon VariablePrefix variableName=Identifier;
durationVariableDeclaration: Measure Colon VariablePrefix variableName=Identifier;
contextVariableDeclaration: ContextType Colon VariablePrefix variableName=Identifier;
stringVariableDeclaration: Text Colon VariablePrefix variableName=identifier;
booleanVariableDeclaration: Indicator Colon VariablePrefix variableName=identifier;
numericVariableDeclaration: Number Colon VariablePrefix variableName=identifier;
dateVariableDeclaration: Date Colon VariablePrefix variableName=identifier;
timeVariableDeclaration: Time Colon VariablePrefix variableName=identifier;
durationVariableDeclaration: Measure Colon VariablePrefix variableName=identifier;
contextVariableDeclaration: ContextType Colon VariablePrefix variableName=identifier;



Expand Down Expand Up @@ -730,4 +754,4 @@ lateBoundScalarReference
| dictionaryLookup # scalarFromDictionaryLookup
;

variableReference: VariablePrefix variableName=Identifier;
variableReference: VariablePrefix variableName=identifier;
35 changes: 20 additions & 15 deletions efx-grammar/EfxLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ OutlineNumber: DIGIT+ -> pushMode(SKIP_WHITESPACE);
// If we encounter a single curly brace in the DEFAULT mode, then we are in a line written in EFX-1 style.
// We will switch to EXPRESSION mode after first pushing the TEMPLATE and SKIP_WHITESPACE modes to the stack
// so that the lexer will find itself in the right mode after processing the expression block.
StartContextExpression: LBRACE -> pushMode(TEMPLATE), pushMode(SKIP_WHITESPACE), pushMode(EXPRESSION), type(StartExpression);
StartContextExpression: LBRACE -> pushMode(TEMPLATE), pushMode(SKIP_WHITESPACE), pushMode(EXPRESSION), type(StartExpressionBlock);

// The Let, With and When keywords should switch the lexer to EXPRESSION mode.
Let: LET -> pushMode(SKIP_WHITESPACE), pushMode(EXPRESSION);
Expand All @@ -52,6 +52,9 @@ Otherwise: OTHERWISE ((TAB | SPACE | EOL)+ DISPLAY)? -> pushMode(TEMPLATE), push
Display: DISPLAY (TAB | SPACE | EOL)+ -> pushMode(SKIP_WHITESPACE), pushMode(TEMPLATE);
Invoke: INVOKE -> pushMode(EXPRESSION);

SummarySection: '---' '-'* (TAB | SPACE)* 'SUMMARY' (TAB | SPACE)* '---' '-'* EOL*;
NavigationSection: '---' '-'* (TAB | SPACE)* 'NAVIGATION' (TAB | SPACE)* '---' '-'* EOL*;

/*
* SKIP_WHITESPACE mode
* ------------------------------------------------------------------------------------------------
Expand All @@ -72,7 +75,7 @@ mode SKIP_WHITESPACE;
// If we encounter a single curly brace in SKIP_WHITESPACE mode, then we are in a line written in EFX-1 style.
// We will switch to EXPRESSION mode after first exiting the current mode and pushing the TEMPLATE and
// SKIP_WHITESPACE modes to the stack so that the lexer will find itself in the right mode after processing the expression block.
ContextExpression: LBRACE -> popMode, pushMode(TEMPLATE), pushMode(SKIP_WHITESPACE), pushMode(EXPRESSION), type(StartExpression);
ContextExpression: LBRACE -> popMode, pushMode(TEMPLATE), pushMode(SKIP_WHITESPACE), pushMode(EXPRESSION), type(StartExpressionBlock);

LetExpression: LET -> pushMode(EXPRESSION), type(Let);
WithExpression: WITH -> pushMode(EXPRESSION), type(With);
Expand Down Expand Up @@ -106,7 +109,7 @@ WhenExpression: (TAB | SPACE | EOL)* WHEN -> popMode, pushMode(EXPRESSION), type
OtherwiseTemplate: (TAB | SPACE | EOL)* OTHERWISE ((TAB | SPACE | EOL)+ DISPLAY)? (TAB | SPACE)* -> type(Otherwise);
InvokeTemplate: (TAB | SPACE | EOL)* INVOKE -> popMode, pushMode(EXPRESSION), type(Invoke);

FreeText: (~[\r\n\f\t #$}{;\\] | OTHER_ESC_SEQ | CHAR_REF)+;
FreeText: (~[\r\n\f\t #$@}{;\\] | OTHER_ESC_SEQ | CHAR_REF)+;

EndTemplate: Whitespace? ';' Whitespace? COMMENT? -> popMode, type(Semicolon);

Expand All @@ -119,8 +122,9 @@ ValueKeyword: 'value';

ShorthandLabelType: LabelType -> type(LabelType);

StartExpression: DOLLAR LBRACE -> pushMode(EXPRESSION);
StartLabel: SHARP LBRACE -> pushMode(LABEL);
StartExpressionBlock: DOLLAR LBRACE -> pushMode(EXPRESSION);
StartLabelBlock: SHARP LBRACE -> pushMode(LABEL);
StartHyperlinkBlock: Whitespace? AT LBRACE -> pushMode(EXPRESSION);

// Comments at the end of a line.
EndOfLineComment: (TAB | SPACE)* COMMENT -> channel(HIDDEN);
Expand All @@ -140,9 +144,9 @@ mode LABEL;
Pipe: '|';
Semicolon: ';';

EndLabel: RBRACE -> popMode;
EndLabel: RBRACE -> popMode, type(EndBlock);

StartNestedExpression: DOLLAR LBRACE -> pushMode(EXPRESSION), type(StartExpression);
StartNestedExpression: DOLLAR LBRACE -> pushMode(EXPRESSION), type(StartExpressionBlock);


AssetType
Expand Down Expand Up @@ -217,8 +221,8 @@ ColonColon: '::';

// Mode switching ---------------------------------------------------------------------------------

// An RBRACE indicates the nd of an EFX-1 style expression block.
EndExpression: RBRACE -> popMode;
// An RBRACE indicates the end of an EFX-1 style expression block.
EndBlock: RBRACE -> popMode;

EndLetExpression: ';' -> popMode, type(Semicolon);

Expand Down Expand Up @@ -335,9 +339,9 @@ YearMonthDurationLiteral: '-'? 'P' IntegerLiteral ('Y' | 'M');
FieldId: FieldIdentifier;// | FieldAlias;
NodeId: NodeIdentifier;// | NodeAlias;

VariablePrefix: '$';
AttributePrefix: '@';
CodelistPrefix: '#';
VariablePrefix: DOLLAR;
AttributePrefix: AT;
CodelistPrefix: SHARP;
FunctionPrefix: '?';

BtId: ('BT' | 'OPP' | 'OPT' | 'OPA') '-' [0-9]+;
Expand Down Expand Up @@ -394,8 +398,9 @@ fragment SPACE: [ ];
fragment LBRACE: '{';
fragment RBRACE: '}';

fragment DOLLAR: '$'; // Used for label placeholders
fragment SHARP: '#'; // Used for expression placeholders
fragment AT: '@';
fragment DOLLAR: '$';
fragment SHARP: '#';
fragment CHAR_REF: '&' ('#' ([0-9]+ | [xX] [0-9A-Fa-f]+) | [a-zA-Z]+) ';';

fragment HEX4: HEX HEX HEX HEX;
Expand All @@ -406,7 +411,7 @@ fragment CHAR: ~["'\\\r\n] | ANY_ESC_SEQ;

fragment LINE_BREAK_ESC_SEQ: '\\n'; // Used for line breaks
fragment OTHER_ESC_SEQ: '\\' [dDwWsStrvfbcxu0"'\\]; // Used for allowing in free text escape sequences other than \\n
fragment ANY_ESC_SEQ: '\\' [dDwWnsStrvfbcxu0"'\\];
fragment ANY_ESC_SEQ: '\\' [dDwWnsStrvfbcxu0"'\\];

fragment CAMEL_CASE: [a-z] [a-z0-9]+ PASCAL_CASE*;
fragment PASCAL_CASE: [A-Z] [a-z0-9]+ PASCAL_CASE*;
Expand Down