Wolf DSL Grammar Reference
This page provides a complete grammar reference for Wolf DSL, derived directly from the Xtext grammar specification. Each section shows the grammar rule along with practical examples.
This reference is generated from Flow.xtext and stays synchronized with the actual parser implementation.
Top-Level Model Structure
Model
The root grammar rule that defines a complete Wolf DSL file:
Model:
query+=QueryDefinition*
type+=TypeSystemDefinition*
node+=Node*;
Example:
// GraphQL queries (optional)
query GetUser {
user(id: $userId) {
name
email
}
}
// Type definitions (optional - usually inherited from GraphQL)
type User {
id: ID!
name: String
email: String
}
// Wolf DSL nodes (main content)
Schema UserSchema {
string name
string email
}
Flow userFlow {
// ... flow definition
}
Node Types
Node Definition
All executable nodes inherit from this base definition:
Node returns graphql::ObjectTypeDefinition:
State | Schema;
State:
Flow | Service | Mapping | SchemaAssignment |
Rulebase | GraphQLService;
Schema Definitions
Schema
Defines data structure for type safety:
Schema:
'Schema' id=AllowedKeyword '{'
schema=(Data)
'}';
Data:
entity+=Entity+;
Entity:
(annotation=Annotation)? name=AllowedKeyword op='{'
entity+=Entity*
'}'
|
(annotation=Annotation)? name=AllowedKeyword op='['
entity+=Entity+
']'
|
(annotation=Annotation)? name=AllowedKeyword op='->' schema=[graphql::ObjectTypeDefinition]
|
(annotation=Annotation)? (type=DataType|schema=[graphql::ObjectTypeDefinition]) (op="[]")? name=AllowedKeyword;
Examples:
- Simple Schema
- Nested Schema
- Array Types
Schema User {
string name
string email
boolean isActive
}
Schema Order {
string orderId
Customer customer {
string name
Address address {
string street
string city
string zipCode
}
}
LineItem[] items
}
Schema ProductCatalog {
string[] tags
Product[] products
Category categories [
string name
string description
]
}
Data Types
Built-in primitive types:
DataType:
'string' | 'boolean' | 'number';
Value Assignments
Schema Assignment (Value)
Creates data instances conforming to schemas:
SchemaAssignment:
'value' id=AllowedKeyword '->' schema=[Schema]
value = (ObjectValue | ArrayValue);
Examples:
- Object Values
- Dynamic Values
- Array Values
value userProfile -> User {
name: "John Doe"
email: "john@example.com"
isActive: true
}
value dynamicUser -> User {
name: ${"User_" + currentDate("yyyyMMdd")}
email: ${"user" + uuid() + "@example.com"}
isActive: ${@Config("default.user.active")}
}
value productList -> ProductArray {
products: [
{ name: "Product A", price: 100 },
{ name: "Product B", price: 200 }
]
}
Service Definitions
REST Service
HTTP service calls with full configuration:
Service:
(sync='synchronous')? (verbose='verbose')? 'Service' type=ID 'as' id=ID
'method' method=ServiceType ('foreach' iterator=SchemaVariable 'as' iteratoralias=AllowedKeyword)?
('input' inputModel=[graphql::ObjectTypeDefinition])?
('output' (outputModel=OutputOrAlias))? '{'
(('Url ->' url=Property)? | ('Url ->' '${'url=Expression'}')?)
('UrlEncoding ->' urlEncoding=EncodingMode)?
('Path ->' '${'path=Expression'}')?
('ProxyHost ->' '${'proxyhost=Expression'}')?
('ProxyPort ->' '${'proxyport=Expression'}')?
('Timeout ->' '${'timeout=Expression'}')?
('Retry ->' '${'retryCount=Expression'}')?
(arguments+=ServiceArguments)*
(requestArguments+=RequestArgument)*
'}';
ServiceType:
'GET' | 'POST' | 'PUT' | 'DELETE';
Examples:
- GET Request
- POST Request
- Asynchronous Service
Service userService method GET as getUserById
input UserRequest output User {
Url -> @Config("api.base.url")
Path -> ${"/users/" + UserRequest.id}
Timeout -> ${5000}
Retry -> ${3}
@Header Authorization -> ${"Bearer " + @Config("api.token")}
@Header Accept -> ${"application/json"}
}
Service createUser method POST as createNewUser
input CreateUserRequest output User {
Url -> @Config("api.base.url")
Path -> ${"/users"}
Timeout -> ${10000}
@Header Content-Type -> ${"application/json"}
@Header Authorization -> ${"Bearer " + @Config("api.token")}
@Body -> ${CreateUserRequest}
}
asynchronous verbose Service paymentProcessor method POST as processPayment
input PaymentRequest output PaymentResponse {
Url -> @Config("payment.api.url")
Path -> ${"/process"}
Timeout -> ${30000}
Retry -> ${2}
@Header ApiKey -> @Config("payment.api.key")
@Body -> ${PaymentRequest}
}
GraphQL Service
GraphQL query execution:
GraphQLService:
(sync='synchronous')? (verbose='verbose')? 'GraphQLService' id=ID 'graphqlQuery' query=QueryModel '{'
('Url ->' '${'url=Expression'}')
('Path ->' '${'path=Expression'}')?
('Timeout ->' '${'timeout=Expression'}')?
('Retry ->' '${'retryCount=Expression'}')?
(variables+=GraphQLVariable)*
(headerOrQueryOrPathParam+=HeaderORQueryOrPathParam)*
'}';
Example:
GraphQLService userGraphQL graphqlQuery GetUserQuery as fetchUserData {
Url -> @Config("graphql.endpoint")
Path -> ${"/graphql"}
Timeout -> ${5000}
@Variable userId -> ${userRequest.id}
@Header Authorization -> ${"Bearer " + @Config("graphql.token")}
}
Mapping (Data Transformation)
Mapping Definition
Transform data between schemas:
Mapping:
'Mapping' id=ID
('input' inputModel+=(InPutModel)
(',' inputModel+=(InPutModel))*
'output' outputModel=OutPutModel)
'{'
statement+=Statement*
'}';
Examples:
- Simple Mapping
- Multiple Inputs
- Conditional Logic
Mapping userTransform input RawUser output User {
User.name = RawUser.firstName + " " + RawUser.lastName
User.email = lowerCase(RawUser.emailAddress)
User.isActive = RawUser.status == "active"
}
Mapping orderSummary input Order, Customer, Inventory output OrderSummary {
OrderSummary.orderId = Order.id
OrderSummary.customerName = Customer.firstName + " " + Customer.lastName
OrderSummary.totalItems = length(Order.items)
OrderSummary.inStock = Inventory.quantity >= Order.totalQuantity
}
Mapping calculatePricing input Order output PricedOrder {
PricedOrder.subtotal = sum(Order.items, item -> item.price * item.quantity)
PricedOrder.discount = if Order.customerType == "premium"
then PricedOrder.subtotal * 0.1
else 0
PricedOrder.total = PricedOrder.subtotal - PricedOrder.discount
// Conditional statement
when (Order.total > 1000) {
PricedOrder.shippingCost = 0
}
}
Flow Control
Flow Definition
Orchestrates execution path through nodes:
Flow:
'Flow' id=ID '{'
startState = StartState
transitionStates += TransitionState*
'}';
StartState:
'Start' start=[State] '{'
('transition' '{'
transition=Transition
'}')?
'}';
TransitionState:
state=[State] '{'
('transition' '{'
transition=Transition
'}')?
'}';
Transition Logic
Controls flow between states:
Transition:
expression=Expression '?' trueState=Transition ':' falseState=Transition |
('when' caseExpressions+=Expression 'then' caseStates+=[TransitionState])+ ('otherwise' 'do' defaultState=[TransitionState]) |
transition=[TransitionState];
Examples:
- Simple Flow
- Conditional Flow
- Multi-way Branching
Flow userProcessingFlow {
Start userInput {
transition {
validateUser
}
}
validateUser {
transition {
transformUser
}
}
transformUser {}
}
Flow conditionalFlow {
Start userRequest {
transition {
userRequest.useCache == true ? getCachedUser : fetchUserFromAPI
}
}
getCachedUser {}
fetchUserFromAPI {
transition {
transformUser
}
}
transformUser {}
}
Flow priorityFlow {
Start request {
transition {
when request.priority == "high" then highPriorityProcessor
when request.priority == "medium" then mediumPriorityProcessor
when request.priority == "low" then lowPriorityProcessor
otherwise do defaultProcessor
}
}
highPriorityProcessor {}
mediumPriorityProcessor {}
lowPriorityProcessor {}
defaultProcessor {}
}
Expression System
Expression Hierarchy
Wolf DSL supports rich expressions with proper operator precedence:
Expression:
BooleanExpression;
BooleanExpression returns Expression:
Comparison
(({BooleanExpression.left=current} op=("||"|"&&"|"and"|"or")) right=Comparison)*;
Comparison returns Expression:
Membership
(({Comparison.left=current} op=("<" | ">" | "<=" | ">=")) right=Membership)*;
Membership returns Expression:
Equals
(({Membership.left=current} op=("in" | "not_in")) "[" right+=Expression(',' right+=Expression)* "]")*;
Equals returns Expression:
Addition
(({Equals.left=current} op=("==" | "!=" | "=~" | "!~" | "is") ) right=Addition)*;
Addition returns Expression:
Multiplication
(({Plus.left=current} '+' | {Minus.left=current} SIGN)
right=Multiplication)*;
Multiplication returns Expression:
Prefixed (({MultiOrDivOrModPow.left=current} op=("*"|"/"|"%"|"^")) right=Prefixed)*;
Examples:
- Arithmetic
- Boolean Logic
- Membership Testing
- Conditional
// Basic arithmetic
total = price * quantity + tax
discount = price * 0.1
finalPrice = price - discount
average = sum / count
// Boolean expressions
isValid = age >= 18 && hasPermission == true
shouldProcess = status == "active" or priority == "high"
isEligible = age >= 21 && income > 50000 && creditScore >= 700
// Membership operators
isValidStatus = status in ["active", "pending", "approved"]
isNotRestricted = country not_in ["RESTRICTED_1", "RESTRICTED_2"]
// Ternary expressions
discount = if customerType == "premium" then 0.15 else 0.05
status = if age >= 18 then "adult" else "minor"
price = if quantity > 10 then basePrice * 0.9 else basePrice
Built-in Functions
Collection Functions
Functions for array/list manipulation:
CollectionFunction:
function=CollectionFunctionCall ('[' refexp=Expression ']')?('.'resultKey+=Key)*;
CollectionFunctionCall:
RemoveFunc | FindFirstFunc | FilterFunc | MapFunc | Split | Json |
ConcatFunc | SortFunc | DedupFunc | LastFunc | ParentFunc |
LowerFunc | UpperFunc | UUIDFunc;
Examples:
- Filter & Search
- Transform
- Aggregate
// Filter collections
activeUsers = filter(users, user -> user.isActive == true)
premiumUsers = filter(users, user -> user.type == "premium")
recentOrders = filter(orders, order -> order.date >= "2023-01-01")
// Find operations
firstAdmin = findFirst(users, user -> user.role == "admin")
lastOrder = last(orders)
// Map transformations
userNames = map(users, user -> user.firstName + " " + user.lastName)
prices = map(products, product -> product.basePrice * 1.1)
// String operations
upperNames = map(names, name -> upperCase(name))
cleanEmails = map(emails, email -> lowerCase(email))
// Aggregation functions
totalUsers = length(users)
totalRevenue = sum(orders, order -> order.total)
userCount = count(users)
avgOrderValue = sum(orders, order -> order.total) / count(orders)
// Sort and deduplicate
sortedUsers = sort(users, user.lastName)
uniqueEmails = dedup(emails)
String Functions
Text manipulation functions:
Split:
'split('exp=Expression','regex=STRING')';
Contains:
'contains('input=Expression','search=Expression')';
Replace:
'replace('text=Expression','searchString=Expression','replacement=Expression')';
Date Functions
Date and time operations:
DateFormat:
'dateFormat' '(' from=('\"MM/dd/yyyy\"' | '\"yyyyMMdd\"' | '\"yyyy-MM-dd\"' | '\"ms\"' | STRING)
',' to=('\"MM/dd/yyyy\"' | '\"yyyyMMdd\"' | '\"yyyy-MM-dd\"' | '\"ms\"' | STRING)
',' exp=Expression (',' fromTimeZone=(Expression) ',' toTimeZone=(Expression) )? ')';
CurrentDate:
'currentDate('format=('\"MM/dd/yyyy\"' | '\"yyyyMMdd\"' | '\"yyyy-MM-dd\"' | '\"ms\"' | STRING)?')';
DayDifference:
'dayDifference('from=Expression','to=Expression',' formatter=('\"MM/dd/yyyy\"' | '\"yyyyMMdd\"' | '\"yyyy-MM-dd\"') ')';
Advanced Features
Rulebase (Business Rules Engine)
Define conditional rule sets:
Rulebase:
'Rulebase' (async?='asynchronous')? id=UID '{'
rules+=NewRule+
'}';
NewRule:
'Rule' id=UID ('with [' modifiers+=UID(','modifiers+=UID)*']')?
'using' (inputModel+=InPutModel)(',' inputModel+=InPutModel)*
'inject' injectedTopicId=UID ('withValue' outputModel=InPutModel)?
'when' condition=BooleanExpression;
Example:
Rulebase pricingRules {
Rule applyPremiumDiscount using Order, Customer
inject discountAmount withValue DiscountValue
when Customer.type == "premium" && Order.total > 1000
Rule applyBulkDiscount using Order
inject discountPercent withValue DiscountPercent
when length(Order.items) > 5
}
Custom Functions
User-defined function calls:
CustomFunction:
'custom('id=STRING (','arguments+=CustomFunctionArguments)* ')';
CustomFunctionArguments:
value=Expression 'as' key=ID;
Example:
result = custom("calculateTax", orderTotal as amount, "CA" as state, true as includeFees)
Comments and Documentation
Wolf DSL supports standard comment syntax:
// Single line comment
/* Multi-line comment
continues here */
Schema User {
string name // Field comment
/* Complex field with
detailed explanation */
string email
}
Validation Rules
The grammar enforces several validation rules:
- Schema References: All data must reference valid schemas
- Type Safety: Expressions must be type-compatible
- Flow Completeness: All transition targets must exist
- Variable Scoping: Variables must be in scope when referenced
- Service Configuration: Required service parameters must be provided
Grammar Evolution
This grammar reference is maintained alongside the Xtext specification. For the most current grammar rules, always refer to the source Flow.xtext file.
The grammar specification enables rich IDE support, syntax validation, and code generation while maintaining the declarative simplicity that makes Wolf DSL powerful and easy to use.