Deal Model Grammar v2
This code block contains the ANTLR4 spec for the deal model based on the clause-deal-instance construct.
antlr
// DealModel-v2.g4 — Deal Engine grammar supporting Clause Type Composition Model
//
// This grammar supports three top-level constructs:
// 1. clause_type - Reusable building blocks with schema, logic, and financial structure
// 2. deal_type - Templates that suggest clause compositions
// 3. deal_instance - Runtime structure (typically generated, not hand-authored)
//
// Key features:
// - for_each construct for iterating over collections
// - Dynamic event naming with {item.field} interpolation
// - Cross-clause references via @clause.output syntax
// - Null coalescing operator (??)
// - Collection operations (sum, count, max, min) with where clauses
// - if-then-else expressions
// - Two-dimensional clause classification (category × value_type)
//
// Version: 2.0.0
// Date: 2025-01-09
grammar DealModel;
// ========================= PARSER RULES =========================
// ---------------- Top-Level Structure ----------------
// A file contains one or more definitions
file: definition+ EOF;
definition
: clauseTypeDef
| dealTypeDef
;
// ---------------- Clause Type Definition ----------------
clauseTypeDef
: CLAUSE_TYPE LBRACE
clauseTypeHeader
schemaSection?
inputsSection?
logicSection?
financialSection?
outputsSection?
templateSection?
RBRACE
;
clauseTypeHeader
: ID_FIELD COLON identifier
VERSION_FIELD COLON SEMVER
CATEGORY_FIELD COLON categoryValue
(VALUE_TYPE_FIELD COLON valueTypeValue)?
NAME_FIELD COLON stringLiteral
DESCRIPTION_FIELD COLON stringLiteral
;
categoryValue
: GUARANTEE
| CONTINGENT
| SIMPLE
;
valueTypeValue
: EARNING
| REIMBURSEMENT
| THIRD_PARTY
| IN_KIND
;
// ---------------- Deal Type Definition ----------------
dealTypeDef
: DEAL_TYPE LBRACE
dealTypeHeader
schemaSection?
suggestedClausesSection?
logicSection?
outputsSection?
RBRACE
;
dealTypeHeader
: ID_FIELD COLON identifier
VERSION_FIELD COLON SEMVER
NAME_FIELD COLON stringLiteral
DESCRIPTION_FIELD COLON stringLiteral
(DEPARTMENT_FIELD COLON identifier)?
(TAGS_FIELD COLON tagList)?
;
tagList
: LBRACKET (identifier (COMMA identifier)*)? RBRACKET
;
// ---------------- Schema Section ----------------
// Schema is defined as embedded JSON Schema (as a string) or external reference
schemaSection
: SCHEMA LBRACE
( schemaInline | schemaRef )
RBRACE
;
schemaInline
: TRIPLE_STRING
;
schemaRef
: REF COLON stringLiteral
;
// ---------------- Inputs Section ----------------
// Declares deal-level data and cross-clause references this clause needs
inputsSection
: INPUTS LBRACE
inputDecl*
RBRACE
;
inputDecl
: identifier COLON inputSource
;
inputSource
: dealFieldRef // deal.parties.talent.name
| clauseOutputRef // @clause_name.output_name
;
dealFieldRef
: DEAL DOT fieldPath
;
clauseOutputRef
: AT identifier DOT identifier // @clause.output
| AT identifier LBRACKET STAR RBRACKET DOT identifier // @clause_type[*].output
;
// ---------------- Logic Section ----------------
// Contains variables, for_each loops, events, and computations
logicSection
: LOGIC LBRACE
logicElement*
RBRACE
;
logicElement
: variableDecl
| forEachBlock
| eventDef
| computationsBlock
;
// Variable declaration
variableDecl
: VAR identifier (ASSIGN expr)?
;
// ---------------- For Each Block ----------------
// Iterates over a collection, scoping events and computations to each item
forEachBlock
: FOR_EACH identifier IN identifier LBRACE
forEachElement*
RBRACE
;
forEachElement
: eventDef
| computationsBlock
| forEachBlock // Nested for_each allowed
;
// ---------------- Event Definition ----------------
eventDef
: EVENT LBRACE
NAME_FIELD COLON eventName
DESCRIPTION_FIELD COLON stringLiteral
CONDITION_FIELD COLON boolExpr
RBRACE
;
// Event names can include interpolation for dynamic naming inside for_each
eventName
: identifier
| INTERP_STRING // "show_occurred_{show.id}"
;
// ---------------- Computations Block ----------------
computationsBlock
: COMPUTATIONS LBRACE
computationDef*
RBRACE
;
computationDef
: metricDef
| outputDef
;
// Metrics are intermediate values; target can include item.field for for_each
metricDef
: METRIC fieldPath ASSIGN expr
;
// Outputs are exposed values
outputDef
: OUTPUT identifier ASSIGN expr
;
// ---------------- Financial Section ----------------
// The core financial structure for guarantee/contingent clauses
financialSection
: FINANCIAL LBRACE
AMOUNT_FIELD COLON expr
(EARNED_FIELD COLON scheduleRef)?
(RECEIVED_FIELD COLON scheduleRef)?
(WHEN_FIELD COLON boolExpr)?
RBRACE
;
scheduleRef
: ON identifier // on earning_schedule
;
// ---------------- Outputs Section ----------------
// Declares values exposed to deal level and other clauses
outputsSection
: OUTPUTS LBRACE
outputDecl*
RBRACE
;
outputDecl
: identifier COLON typeAnnotation
;
typeAnnotation
: NUMBER_TYPE
| BOOLEAN_TYPE
| STRING_TYPE
;
// ---------------- Suggested Clauses Section (Deal Types) ----------------
suggestedClausesSection
: SUGGESTED_CLAUSES LBRACE
suggestedClause*
RBRACE
;
suggestedClause
: LBRACE
TYPE_FIELD COLON identifier
(CARDINALITY_FIELD COLON cardinalityValue)?
(REQUIRED_FIELD COLON boolLiteral)?
(DESCRIPTION_FIELD COLON stringLiteral)?
(DEPENDS_ON_FIELD COLON identifierList)?
RBRACE
;
cardinalityValue
: ONE
| MANY
;
identifierList
: LBRACKET (identifier (COMMA identifier)*)? RBRACKET
;
// ---------------- Template Section ----------------
templateSection
: TEMPLATE LBRACE
TRIPLE_STRING
RBRACE
;
// ========================= EXPRESSIONS =========================
// ---------------- Arithmetic/Value Expressions ----------------
expr
: expr NULLCOALESCE expr # nullCoalesce
| expr MUL expr # mul
| expr DIV expr # div
| expr ADD expr # add
| expr SUB expr # sub
| SUB expr # unaryMinus
| ifExpr # conditional
| collectionExpr # collection
| funcCall # call
| LPAREN expr RPAREN # groupExpr
| NUMBER # numLiteral
| stringLiteral # strLiteral
| NULL # nullLiteral
| clauseOutputRef # clauseRef
| fieldPath # fieldAccess
;
// If-then-else expression
ifExpr
: IF boolExpr THEN expr ELSE expr
;
// Collection operations
collectionExpr
: collectionFunc LPAREN collectionArg (COMMA identifier)? RPAREN
;
collectionFunc
: SUM
| COUNT
| MAX
| MIN
;
// Collection argument: collection[*].field or collection with where clause
collectionArg
: fieldPath LBRACKET STAR RBRACKET DOT identifier // shows[*].earned
| identifier WHERE whereCondition (COMMA identifier)? // shows where show.settled == true, earned
;
whereCondition
: boolExpr
;
// Function call (for extensibility)
funcCall
: identifier LPAREN argList? RPAREN
;
argList
: expr (COMMA expr)*
;
// ---------------- Boolean Expressions ----------------
boolExpr
: boolExpr ANDAND boolExpr # andExpr
| boolExpr OROR boolExpr # orExpr
| NOT boolExpr # notExpr
| expr compareOp expr # comparison
| LPAREN boolExpr RPAREN # groupBool
| boolLiteral # boolLit
| identifier # eventRef
;
compareOp
: EQ | NEQ | LT | LTE | GT | GTE
;
boolLiteral
: TRUE
| FALSE
;
// ---------------- Field Paths ----------------
// Supports item.field, item.nested.field, collection[*].field
fieldPath
: identifier (DOT identifier)*
;
// ---------------- Identifiers and Literals ----------------
identifier
: ID
;
stringLiteral
: STRING
| TRIPLE_STRING
;
// ========================= LEXER RULES =========================
// ---------------- Keywords - Top Level ----------------
CLAUSE_TYPE : 'clause_type';
DEAL_TYPE : 'deal_type';
// ---------------- Keywords - Sections ----------------
SCHEMA : 'schema';
INPUTS : 'inputs';
LOGIC : 'logic';
FINANCIAL : 'financial';
OUTPUTS : 'outputs';
TEMPLATE : 'template';
SUGGESTED_CLAUSES : 'suggested_clauses';
COMPUTATIONS : 'computations';
// ---------------- Keywords - Fields ----------------
ID_FIELD : 'id';
VERSION_FIELD : 'version';
CATEGORY_FIELD : 'category';
VALUE_TYPE_FIELD: 'value_type';
NAME_FIELD : 'name';
DESCRIPTION_FIELD : 'description';
DEPARTMENT_FIELD: 'department';
TAGS_FIELD : 'tags';
TYPE_FIELD : 'type';
CARDINALITY_FIELD : 'cardinality';
REQUIRED_FIELD : 'required';
DEPENDS_ON_FIELD: 'depends_on';
AMOUNT_FIELD : 'amount';
EARNED_FIELD : 'earned';
RECEIVED_FIELD : 'received';
WHEN_FIELD : 'when';
CONDITION_FIELD : 'condition';
REF : 'ref';
// ---------------- Keywords - Category Values ----------------
GUARANTEE : 'guarantee';
CONTINGENT : 'contingent';
SIMPLE : 'simple';
// ---------------- Keywords - Value Type Values ----------------
EARNING : 'earning';
REIMBURSEMENT : 'reimbursement';
THIRD_PARTY : 'third_party';
IN_KIND : 'in_kind';
// ---------------- Keywords - Cardinality ----------------
ONE : 'one';
MANY : 'many';
// ---------------- Keywords - Type Annotations ----------------
NUMBER_TYPE : 'number';
BOOLEAN_TYPE : 'boolean';
STRING_TYPE : 'string';
// ---------------- Keywords - Control Flow ----------------
FOR_EACH : 'for_each';
IN : 'in';
IF : 'if';
THEN : 'then';
ELSE : 'else';
WHERE : 'where';
// ---------------- Keywords - Declarations ----------------
VAR : 'var';
METRIC : 'metric';
OUTPUT : 'output';
EVENT : 'event';
ON : 'on';
DEAL : 'deal';
// ---------------- Keywords - Collection Functions ----------------
SUM : 'sum';
COUNT : 'count';
MAX : 'max';
MIN : 'min';
// ---------------- Keywords - Literals ----------------
TRUE : 'true';
FALSE : 'false';
NULL : 'null';
// ---------------- Operators - Logical ----------------
ANDAND : '&&';
OROR : '||';
NOT : '!';
// ---------------- Operators - Comparison ----------------
EQ : '==';
NEQ : '!=';
LTE : '<=';
GTE : '>=';
LT : '<';
GT : '>';
// ---------------- Operators - Arithmetic ----------------
ADD : '+';
SUB : '-';
MUL : '*';
DIV : '/';
// ---------------- Operators - Special ----------------
NULLCOALESCE : '??';
AT : '@';
STAR : '*';
// ---------------- Punctuation ----------------
LBRACE : '{';
RBRACE : '}';
LBRACKET : '[';
RBRACKET : ']';
LPAREN : '(';
RPAREN : ')';
COLON : ':';
COMMA : ',';
SEMI : ';';
ASSIGN : '=';
DOT : '.';
// ---------------- Tokens ----------------
// Identifier: starts with letter or underscore
ID : [a-zA-Z_][a-zA-Z_0-9]*;
// Semantic version: major.minor.patch with optional prerelease/build
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 (integer or decimal)
NUMBER : [0-9]+ ('.' [0-9]+)?;
// Interpolated string for dynamic event names: identifier_{item.field}
INTERP_STRING : [a-zA-Z_][a-zA-Z_0-9]* ('{' [a-zA-Z_][a-zA-Z_0-9]* ('.' [a-zA-Z_][a-zA-Z_0-9]*)* '}')+;
// Triple-quoted string (for schemas, templates)
TRIPLE_STRING : '"""' .*? '"""';
// Double-quoted string
STRING : '"' ('\\' . | ~["\\\r\n])* '"';
// ---------------- Whitespace and Comments ----------------
WS : [ \t\r\n]+ -> skip;
LINE_COMMENT : '//' ~[\r\n]* -> skip;
HASH_COMMENT : '#' ~[\r\n]* -> skip;
BLOCK_COMMENT : '/*' .*? '*/' -> skip;