EPL Language Reference¶
Complete reference for EPL v9.8.0 syntax that is stable enough to teach in user-facing documentation.
Table Of Contents¶
- Comments
- Variables
- Data Types
- Operators
- Control Flow
- Functions
- Classes
- Collections
- Error Handling
- Modules And Bridges
- WebApp DSL
- Built-in Functions
- Methods
- Production Boundaries
Comments¶
Note: line comment using the colon form
Note "string-form comment, handy as a file header or docstring"
Comment "alias of the string form"
NoteBlock
A block comment spanning
multiple lines.
End
EPL accepts four comment forms: Note: text, Note "text", Comment "text", and the NoteBlock ... End block.
Variables¶
name = "Alice"
age = 25
active = True
score = 99.5
items = [1, 2, 3]
profile = Map with name = "Alice" and age = 25
English declaration forms:
Create name equal to "Alice"
Create age = 25
Create text title equal to "Invoice"
Remember city as "Delhi"
Assignment:
Constants:
Data Types¶
| Type | Example | Recommended Literal |
|---|---|---|
| Integer | 42 |
42 |
| Decimal | 3.14 |
3.14 |
| Text | "Hello" |
double-quoted text |
| Boolean | True, False |
capitalized |
| List | [1, 2, 3] |
square brackets |
| Map | Map with id = 1 and name = "A" |
Map with ... and ... |
| Nothing | Nothing |
capitalized |
Type helpers:
Say type_of(42)
Say is_integer(42)
Say is_text("hello")
Say is_list([1, 2])
Say is_number(3.14)
Say is_nothing(Nothing)
Conversions:
Operators¶
Arithmetic:
| Operator | Example |
|---|---|
+ |
total = a + b |
- |
remaining = total - used |
* |
area = width * height |
/ |
ratio = done / total |
% |
remainder = n % 2 |
power(a, b) |
value = power(2, 10) |
raised to |
value = 2 raised to 10 |
Comparison:
| Operator | English Form |
|---|---|
== |
is equal to, equals |
!= |
is not equal to, does not equal |
> |
is greater than |
< |
is less than |
>= |
is at least |
<= |
is at most |
Logical:
If enabled And count > 0 Then
Say "run"
End
If Not locked Or owner == "admin" Then
Say "allowed"
End
Ternary:
Control Flow¶
If / Otherwise:
Match:
While:
Repeat:
For range:
For each:
Break and continue:
Functions¶
Definition:
Call:
Parameters can be comma-separated or joined with and:
Lambdas:
square = lambda x -> x * x
add = lambda a, b -> a + b
numbers = [1, 2, 3, 4]
Say numbers.map(lambda x -> x * 2)
Input:
Classes¶
Basic class:
Class Animal
name = "Unknown"
sound = "..."
Function speak
Say name + " says " + sound
End
End
dog = new Animal
dog.name = "Rex"
dog.sound = "Woof"
dog.speak()
Constructor:
Class Counter
value = 0
Function init takes start
value = start
End
Function next
Increase value by 1
Return value
End
End
counter = new Counter(10)
Say counter.next()
Inheritance:
Use project tests before depending on advanced OOP features such as visibility, interfaces, generics, or static methods across all compilation targets.
Collections¶
Lists:
items = [3, 1, 4, 1, 5]
items.add(9)
items.remove(1)
Say items.contains(4)
Say items.index_of(4)
Say items.count(1)
items.sort()
items.reverse()
Say items.join(", ")
last = items.pop()
Functional list methods:
nums = [1, 2, 3, 4, 5]
Say nums.map(lambda x -> x * 2)
Say nums.filter(lambda x -> x > 3)
Say nums.reduce(lambda a, b -> a + b)
Say nums.find(lambda x -> x > 3)
Say nums.every(lambda x -> x > 0)
Say nums.some(lambda x -> x > 4)
Maps:
person = Map with name = "Alice" and age = 30
Say person.name
person.set("role", "admin")
Say person.get("role", "user")
Say person.has("name")
Say person.keys()
Say person.values()
person.remove("role")
Map literals on one line or across multiple lines:
Note: Single-line form.
settings = Map with host = "localhost" and port = 8080
Note: Multi-line form breaks around each `and`.
config = Map with host = "localhost"
and port = 8080
and debug = True
Note: For dynamic keys, build incrementally with .set().
headers = Map with content_type = "application/json"
headers.set("X-Request-ID", request_id)
Error Handling¶
Throw:
Assert:
Modules And Bridges¶
File and stdlib imports:
Bundled importable modules:
EPL ships six importable modules under epl/stdlib/: json, encoding, net, os, regex, and sql. A bare import brings their functions in as plain names; an aliased import namespaces them.
Note: Bare import — functions become plain names.
Import "encoding"
Say to_base64("hi")
Note: Aliased import — functions are namespaced.
Import "encoding" as ENC
Say ENC.to_base64("hi")
json is a reserved token, so json.parse(...) will not lex. Use the bare form or an alias:
These modules wrap the always-available built-ins (json_parse, regex_match, db_*, and others), which remain callable directly. See docs/stdlib-reference.md for the full per-module API.
Module block:
Module Utils
Constant VERSION = "1.0"
Function double takes x
Return x * 2
End
End
Say Utils::VERSION
Say Utils::double(5)
Python bridge:
Note: `json` is a reserved token, so alias the Python module to a non-reserved name.
Use python "json" as pyjson
payload = pyjson.loads("{\"ok\": true}")
Say payload.get("ok")
JavaScript bridge:
Bridge code is privileged. Sandbox mode blocks ecosystem bridges.
WebApp DSL¶
Create WebApp called app
Route "/" shows
Page "Home"
Heading "Home"
Text "Welcome"
Link "Health" to "/api/health"
End
End
Route "/api/health" responds with
Send json Map with status = "ok"
End
Start app on port 8000
Request context inside route bodies:
| Name | Purpose |
|---|---|
request_data |
Parsed JSON or form body |
request_params |
Path and query params |
request_headers |
Headers map |
request_method |
HTTP method |
request_path |
Request path |
request |
Combined request object |
session_id |
Session identifier |
Route "/users/:name" responds with
name = request_params.name
role = request_data.get("role", "guest")
Send json Map with name = name and role = role
End
Built-in Functions¶
Core:
| Function | Purpose |
|---|---|
length(x) |
Length of text, list, or map |
type_of(x) |
Runtime type name |
to_integer(x) |
Convert to integer |
to_decimal(x) |
Convert to decimal |
to_text(x) |
Convert to text |
to_boolean(x) |
Convert to boolean |
Math:
| Function | Purpose |
|---|---|
absolute(x) |
Absolute value |
round(x) |
Round number |
floor(x) |
Round down |
ceil(x) |
Round up |
sqrt(x) |
Square root |
power(x, y) |
Exponentiation |
log(x) |
Natural log |
sin(x), cos(x), tan(x) |
Trigonometry |
min(a, b), max(a, b) |
Minimum / maximum |
random(min, max) |
Random value in range |
Text:
| Function | Purpose |
|---|---|
uppercase(s) |
Uppercase |
lowercase(s) |
Lowercase |
trim(s) |
Trim whitespace |
split(s, sep) |
Split text |
join(list, sep) |
Join list |
replace(s, old, new) |
Replace text |
JSON:
| Function | Purpose |
|---|---|
json_parse(text) |
Parse JSON |
json_stringify(value) |
Serialize JSON |
json_valid(text) |
Validate JSON where available |
json_merge(a, b) |
Merge JSON-like maps where available |
json_query(value, path) |
Query JSON-like data where available |
Database:
| Function | Purpose |
|---|---|
db_open(path) |
Open SQLite |
db_execute(db, sql[, params]) |
Run SQL statement |
db_query(db, sql[, params]) |
Query all rows |
db_query_one(db, sql[, params]) |
Query one row |
db_insert(db, table, map) |
Insert map record |
db_close(db) |
Close connection |
Auth:
| Function | Purpose |
|---|---|
auth_hash_password(password) |
Hash password |
auth_verify_password(password, hash) |
Verify password |
auth_jwt_create(payload, secret[, expiry_seconds]) |
Create JWT |
auth_jwt_verify(token, secret) |
Verify JWT |
auth_generate_token(length) |
Generate random token |
Methods¶
String methods:
s = "Hello World"
Say s.uppercase()
Say s.lowercase()
Say s.trim()
Say s.contains("World")
Say s.starts_with("Hello")
Say s.ends_with("World")
Say s.replace("World", "EPL")
Say s.split(" ")
Say s.substring(0, 5)
Say s.index_of("World")
Say s.count("l")
Say s.repeat(2)
Say s.reverse()
Say s.char_at(0)
Say s.to_list()
Numeric conversions need a string whose contents are actually a number:
List methods:
items.add("x")
items.remove("x")
items.contains("x")
items.sort()
items.reverse()
items.join(", ")
items.pop()
items.clear()
items.copy()
Map methods:
m.keys()
m.values()
m.entries()
m.has("key")
m.get("key", "default")
m.set("key", "value")
m.remove("key")
m.merge(other)
m.clear()
m.copy()
Production Boundaries¶
- Use
Note:,Note "...", orNoteBlockcomments in production documentation. - Write
Map with ... and ...on one line or across multiple lines (breaking around eachand); build maps with dynamic keys incrementally with.set. - Use
db_executefor production migrations instead of complexdb_create_tabledefinitions. - Use parameterized SQL for every value that came from users, files, requests, or external services.
- Use
Send jsonin WebApp routes instead of returning bare maps. - Wrap Python/JS bridge calls in
Try/Catchand declare dependencies inepl.toml. - Run
epl test, parser smoke tests, and deployment smoke tests for the target you actually ship.