DealModel Grammar (ANTLR4)
INFO
This is the complete ANTLR4 grammar for the current DealModel DSL. It uses lowercase keywords, treats whitespace as insignificant, supports line/block comments, and encodes the primitives: model header, variable, operator, event, clause, block, and type with clause composition and conditionals (when).
Save the code block below as DealModel.g4.
antlr
// DealModel.g4 — stable grammar with clause kinds (simple, guarantee, contingent) and intrinsic
// function call fix for `amount(...)`
grammar DealModel;
// ========================= PARSER RULES =========================
model: modelHeader statement* EOF;
modelHeader:
MODEL LBRACE DEALTYPE COLON (TEXT | STRING) COMMA VERSION COLON SEMVER RBRACE;
statement:
inputsBlock
| overridesBlock
| selectorsBlock
| computationsBlock
| variableDecl
| operatorDef
| eventDef
| clauseDef
| blockDef
| typeDef;
inputsBlock:
INPUTS LBRACE (
SCHEMA COLON (TRIPLE_STRING | STRING)
| REF COLON STRING
) RBRACE;
overridesBlock:
OVERRIDES LBRACE TEMPLATES COLON TRIPLE_STRING RBRACE;
selectorsBlock: SELECTORS LBRACE selectorEntry+ RBRACE;
selectorEntry: ID COLON (STRING | TEXT) SEMI?;
computationsBlock:
COMPUTATIONS LBRACE (metricDef | outputDef)+ RBRACE;
metricDef: METRIC ID ASSIGN expr SEMI?;
outputDef: OUTPUT ID ASSIGN expr SEMI?;
variableDecl: VAR ID (ASSIGN expr)? SEMI?;
// Arithmetic / functional expression
expr:
SUB expr # unaryMinus
| expr MUL expr # mul
| expr DIV expr # div
| expr ADD expr # add
| expr SUB expr # sub
| funcCall # call
| LPAREN expr RPAREN # group
| NUMBER # num
| ID # name;
funcCall: (ID | AMOUNTKW) LPAREN (argList)? RPAREN;
argList: expr (COMMA expr)*;
// Boolean expressions (events)
boolExpr:
boolExpr ANDAND boolExpr
| boolExpr OROR boolExpr
| NOT boolExpr
| TRUE
| FALSE
| expr CMP expr
| LPAREN boolExpr RPAREN;
// Operators
operatorDef:
OPERATOR LBRACE NAME COLON ID DISPLAY COLON (TEXT | STRING) TYPEKW COLON operatorType RBRACE;
operatorType: AND | OR;
// Events
eventDef:
EVENT LBRACE NAME COLON ID DESCRIPTION COLON (TEXT | STRING) CONDITION COLON boolExpr RBRACE;
// Clauses with kind, amount, payable
clauseDef:
CLAUSE LBRACE NAME COLON ID KIND COLON clauseKind DESCRIPTION COLON (
TEXT
| STRING
) (WHEN COLON ID)? (AMOUNTKW COLON expr)? (
PAYABLE COLON payableSpec
)? (TEMPLATE COLON TRIPLE_STRING)? RBRACE;
clauseKind: SIMPLE | GUARANTEE | CONTINGENT;
payableSpec: ON ID | BY_SCHEDULE ID;
// Clause Blocks
blockDef:
BLOCK LBRACE NAME COLON ID EXPR COLON clauseExpr (
WHEN COLON ID
)? (TEMPLATE COLON TRIPLE_STRING)? RBRACE;
clauseExpr: clauseTerm (ID clauseTerm)*;
clauseTerm: ID | LPAREN clauseExpr RPAREN;
// Deal Type
typeDef:
TYPEKW LBRACE NAME COLON ID COMPOSE COLON clauseExpr (
TEMPLATE COLON TRIPLE_STRING
)? RBRACE;
// ========================= LEXER RULES =========================
// Header keywords
MODEL: 'model';
DEALTYPE: 'deal_type';
VERSION: 'version';
// Primitives
INPUTS: 'inputs';
OVERRIDES: 'overrides';
SELECTORS: 'selectors';
COMPUTATIONS: 'computations';
VAR: 'var';
OPERATOR: 'operator';
EVENT: 'event';
CLAUSE: 'clause';
BLOCK: 'block';
TYPEKW: 'type';
// Fields
SCHEMA: 'schema';
REF: 'ref';
TEMPLATES: 'templates';
NAME: 'name';
DISPLAY: 'display';
DESCRIPTION: 'description';
KIND: 'kind';
WHEN: 'when';
AMOUNTKW: 'amount';
PAYABLE: 'payable';
ON: 'on';
BY_SCHEDULE: 'by_schedule';
CONDITION: 'condition';
EXPR: 'expr';
COMPOSE: 'compose';
TEMPLATE: 'template';
IN: 'in';
AND: 'and';
OR: 'or';
// Clause kinds
SIMPLE: 'simple';
GUARANTEE: 'guarantee';
CONTINGENT: 'contingent';
// Computations
METRIC: 'metric';
OUTPUT: 'output';
// Logical
ANDAND: '&&';
OROR: '||';
NOT: '!';
TRUE: 'true';
FALSE: 'false';
// Punctuation
LBRACE: '{';
RBRACE: '}';
COLON: ':';
COMMA: ',';
SEMI: ';';
ASSIGN: '=';
LPAREN: '(';
RPAREN: ')';
// Operators
ADD: '+';
SUB: '-';
MUL: '*';
DIV: '/';
CMP: '==' | '!=' | '>=' | '<=' | '>' | '<';
// Tokens
ID: [a-zA-Z_][a-zA-Z_0-9]*;
// Semantic version
SEMVER: INT '.' INT '.' INT ( '-' PRERELEASE)? ( '+' BUILD)?;
fragment INT: '0' | [1-9][0-9]*;
fragment PRERELEASE: IDENT ('.' IDENT)*;
fragment BUILD: IDENT ('.' IDENT)*;
fragment IDENT: [0-9A-Za-z-]+;
// Numbers, currency
NUMBER: [0-9]+ ('.' [0-9]+)?;
ISO_CCY: [A-Z]{3};
// Dates
DATE: [0-9]{4} '-' [0-9]{2} '-' [0-9]{2};
// Strings
TRIPLE_STRING: '"""' ( . | '\r' | '\n')*? '"""';
STRING: '"' ( '\\' . | ~["\\\r\n])* '"';
TEXT: (
~[{}(),:="\r\n \u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]
)+;
// Whitespace & Comments (Unicode-safe)
fragment UNI_WS_CHAR:
'\u0009'
| '\u000B'
| '\u000C'
| '\u0020'
| '\u00A0'
| '\u1680'
| '\u2000' ..'\u200A'
| '\u202F'
| '\u205F'
| '\u3000';
WS: (UNI_WS_CHAR | '\r' | '\n')+ -> skip;
HASH_COMMENT: '#' ~[\r\n]* -> skip;
LINE_COMMENT: '//' ~[\r\n]* -> skip;
BLOCK_COMMENT: '/*' .*? '*/' -> skip;Notes
- Lowercase keywords are required (e.g.,
model,event,block). - Whitespace is ignored by the lexer (
WSrule), so formatting is flexible. - Use events with
when:to guard clauses/blocks; use operators insideexpr:to compose logic. - The same
TYPEKW: 'type'token names the exported composition; it is also used as a field key where applicable. - Extend
TEXTor add quoted-string rules if you need commas or braces inside descriptions.