Language Grammar and Syntax
Keywords, comments, literals, and operators in PolicyFlow
This section provides a detailed reference for the fundamental building blocks of the PolicyFlow language, including keywords, comments, literals, and operators.
Keywords
PolicyFlow uses a set of reserved keywords to define its structure and logic.
Declaration Keywords
Keyword | Description | Example |
---|---|---|
policy | Declares a new policy | policy DocumentAccess { ... } |
schema | Declares a new schema in a .pfs file | schema AuthSchema { ... } |
test | Declares a test suite in a .pftest file | test DocumentAccessTests for DocumentAccess { ... } |
type | Declares a new complex object type | type CorporateUser { ... } |
enum | Declares a new enumeration | enum Status { ACTIVE, PENDING } |
Designated Type Keywords
Keyword | Description | Example |
---|---|---|
User | Designates a type as a User | User type CorporateUser { ... } |
Resource | Designates a type as a Resource | Resource type Document { ... } |
Context | Designates a type as a Context | Context type RequestContext { ... } |
Relationship | Designates a type as a Relationship | Relationship type TeamMembership { ... } |
Module System Keywords
Keyword | Description | Example |
---|---|---|
import | Imports types from other files | import * as Auth from "@/schemas/auth.pfs"; |
from | Specifies the import source | See above |
as | Creates an alias for imports | See above |
Policy Structure Keywords
Keyword | Description | Example |
---|---|---|
rules | Defines the rules block | rules { ... } |
rule | Declares an individual rule | rule OwnerAccess { ... } |
when | Starts a condition | when user.id == resource.ownerId |
then | Specifies the decision | then ALLOW |
priority | Sets rule priority | priority: 1000 |
reason | Provides explanation | reason: "Owner has full access" |
Comments
Comments are used to document code and are ignored by the compiler. PolicyFlow supports three styles:
Single-Line Comments
Start with //
and continue to the end of the line.
// This rule checks for ownership.
when user.id == resource.ownerId then ALLOW
Multi-Line Comments
Start with /*
and end with */
. They can span multiple lines.
/*
This policy is part of the compliance module
and should not be edited without approval from the security team.
*/
policy ComplianceSOX { ... }
Documentation Comments
A special type of multi-line comment starting with /**
. These are parsed by IDEs and tooling for contextual information.
/**
* Defines the standard user model for our application.
* Includes core attributes like email and clearance level.
*/
User type CorporateUser { ... }
Literals
Literals are notations for representing fixed values in source code.
String Literals
Enclosed in double quotes with support for escape sequences.
const message = "Hello, World!";
const multiline = "First line\nSecond line";
const withTab = "Column1\tColumn2";
Number Literals
Whole numbers (integers) with optional underscores for readability. The Number
type represents 64-bit signed integers.
const count = 123;
const negative = -50;
const million = 1_000_000; // Underscores for readability
Decimal Literals
Numbers with fractional parts. The Decimal
type provides high-precision floating-point arithmetic.
const price = 99.9;
const precise = -0.123;
const percentage = 0.15;
Boolean Literals
const isActive = true;
const isDeleted = false;
Null Literal
const manager = null; // No manager assigned
Assignment Syntax
PolicyFlow uses different assignment operators depending on the context:
In Type Definitions
Use :
(colon) for property definitions and default values:
schema Example {
type User {
name: String // Property type
age: Number // Property type
isActive: Boolean = true // Property with default
}
}
policy MyPolicy {
description: "Policy description" // Metadata field
version: "1.0.0" // Metadata field
}
In Rule Logic
Use =
(equals) for variable assignments:
rule Example {
when {
const userName = user.name; // Variable assignment
let count = 0; // Mutable variable
count = count + 1; // Reassignment
return count > 0;
}
then ALLOW
}
Actions and Wildcards
An Action is a string that represents the operation a user is attempting to perform. Actions are typically namespaced using colons.
Action Patterns
policy DocumentAccess {
actions: ["documents:**"] // This policy handles all document actions
rules {
rule ReadAccess {
when action == "documents:read"
then ALLOW
}
rule WriteAccess {
when action.Matches("documents:write:*")
then ALLOW
}
}
}
Action Wildcard Matching
The action
variable has a special .Matches()
method that supports wildcard patterns. This is specific to the action
variable and uses PolicyFlow's wildcard syntax, not regular expressions.
Pattern | Description | Example Matches | Does NOT Match |
---|---|---|---|
* | Matches one segment | documents:read , users:view | documents:read:all , read |
** | Matches zero or more segments | documents , documents:read , documents:system:restart | read |
documents:* | Matches one segment after documents | documents:read , documents:write | documents:read:all |
documents:** | Matches any action in the namespace | documents , documents:read , documents:write:draft | users:read |
**:read | Matches any action ending with :read | documents:read , files:public:read | read , documents:read:all |
rule WildcardExamples {
when {
// Check if action matches specific patterns
const isReadAction = action.Matches("**:read");
const isDocumentAction = action.Matches("documents:**");
const isSpecificWrite = action.Matches("documents:write:*");
return isReadAction OR (isDocumentAction AND user.hasDocumentAccess);
}
then ALLOW
}
Note: The .Matches()
method on regular String
types uses regular expressions, while action.Matches()
uses PolicyFlow's wildcard syntax.
Variables and Constants
Environment Variables
Access global configuration through the env
map. Environment variables in the .env
file support automatic type detection.
Type Detection in .env Files
The parser for .env
files automatically detects the following types:
- Boolean:
true
orfalse
(without quotes). - Number: Any integer value (e.g.,
1000
,-50
). - Decimal: Any floating-point value (e.g.,
0.08
,15.5
). - String: Any value enclosed in double quotes (e.g.,
"system-admin"
).
# .env file with different types:
# Strings
ADMIN_ROLE = "system-admin"
COMPANY_DOMAIN = "example.com"
# Numbers
API_RATE_LIMIT = 1000
MAX_RETRIES = 3
MIN_CLEARANCE_LEVEL = 4
# Decimals
TAX_RATE = 0.08
DISCOUNT_PERCENTAGE = 15.5
MAX_CPU_THRESHOLD = 85.0
# Booleans
FEATURE_ENABLED = true
DEBUG_MODE = false
Using Environment Variables in Policies
rule AdminAccess {
// ADMIN_ROLE is a string
when env["ADMIN_ROLE"] in user.roles
then ALLOW
priority: 1000
}
rule RateLimit {
when {
// API_RATE_LIMIT is a Number
const limit = env["API_RATE_LIMIT"];
return user.requestCount > limit;
}
then DENY
reason: "Rate limit exceeded"
}
rule TaxCalculation {
when {
// TAX_RATE is a Decimal
const taxRate = env["TAX_RATE"];
const totalWithTax = resource.price * (1 + taxRate);
return totalWithTax <= user.budget;
}
then ALLOW
}
rule ClearanceLevelCheck {
when {
// MIN_CLEARANCE_LEVEL is a Number
return user.clearanceLevel >= env["MIN_CLEARANCE_LEVEL"];
}
then ALLOW
}
// For booleans, use direct comparison
rule MaintenanceMode {
when env["DEBUG_MODE"] == true
then DENY
priority: 0
reason: "System under maintenance"
}
Scoped Variables
Use const
for immutable values and let
for mutable ones:
rule ComplexCheck {
when {
const adminRole = env["ADMIN_ROLE"]; // Immutable
let effectiveClearance = user.clearanceLevel; // Mutable
if (user.hasTemporaryBoost) {
effectiveClearance = effectiveClearance + 1; // Can reassign
}
return adminRole in user.roles AND effectiveClearance >= 5;
}
then ALLOW
}
Control Flow
Conditional Logic in Rules
Rules support complex conditional logic within when
blocks:
rule ComplexAccess {
when {
// Early return for admins
if ("admin" in user.roles) {
return true;
}
// Check ownership
if (user.id == resource.ownerId) {
return true;
}
// Check permissions based on classification
const canRead = resource.classification == "Public" ||
(resource.classification == "Internal" && user.isEmployee);
return canRead && action == "read";
}
then ALLOW
}
Ternary Operator
For concise conditional expressions:
const accessLevel = user.isAdmin ? "full" : "limited";
const timeout = user.isPremium ? 3600 : 1800;
Default Values
Default values are evaluated at object instantiation time, not at schema compilation time:
schema DefaultExample {
type User {
createdAt: DateTime = DateTime.Now() // Set when object is created
isActive: Boolean = true
tags: String[] = []
}
}