Skip to content

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;

Confidential. For internal use only.