RedEX is a reference-driven programming-language design. Human-readable names make source approachable; permanent numeric references give declarations a stable identity that survives a rename.
Current implementation boundary: RedEXCompile provides the file type, tokenizer, snippets, formatting, outline/reference map, diagnostics, starter project, CLI, and a literal/
io.printpreview runner. Sections describing broader runtime behavior define the language direction and editor syntax; they do not claim the preview runner already compiles every example.
| File | Purpose |
|---|---|
*.RedEX |
RedEX source module |
*.RedEXP |
Declarative RedEXCompile plugin manifest |
*.rexdb |
RedEX database storage |
*.rexv |
Reference/version history |
REX.sig |
Project signature and identity |
.redexcompile/project.json |
IDE-only linked-tool configuration |
A small project can look like:
MyProject/
├─ REX.sig
├─ src/
│ └─ Main.RedEX
└─ data/
└─ Accounts.rexdb
@module $"Main"[100] {
let {displayName}[20]: string = "Ada";
public fn {greet}[50]() -> void {
io.print(f"Hello {displayName}");
}
}
Main,displayName, andgreetare readable names.[100],[20], and[50]are stable numeric references.- A rename changes the name, not the permanent identity.
- A reference must be unique within its declaration scope. The editor reports duplicate declaration references as
RX-REF-002.
Reference-shaped syntax recognized by the editor includes:
| Form | Meaning |
|---|---|
{Name}[20] |
Named declaration with permanent reference |
${764[46]} |
Stable data reference |
&{20[50]} |
Stable function/reference address |
{$"Store"}[764]{ |
Database-style referenced block |
{$$"Store"}[764]{ |
Project/global database-style referenced block |
@module $"Main"[100] {
use "redex/io";
use "redex/fs" as fs;
@entry
public async fn {Main}[99]() -> void {
io.print("Hello from RedEX");
}
}
- A normal
.RedEXsource file should declare one@module. - An executable module may contain one
@entryfunction. useimports a module;assupplies a local alias.- Visibility keywords are
public,project,private, and the design also reservesinternalfor project-scoped APIs.
The editor reports a missing module declaration as RX-MODULE-001, more than one main module as RX-MODULE-002, and duplicate entry annotations as RX-CALL-001.
RedEX uses visually distinctive comment fences:
<-> This is an inline/fenced comment <->
>-<
This is a multiline comment block.
>-<
The tokenizer ignores brackets inside recognized comments. An unclosed multiline comment is RX-SYNTAX-005.
let {count}[20]: int = 0;
let mut {status}[21]: string = "ready";
const {MAX_RETRIES}[22]: int = 3;
let {enabled}[23]: bool = true;
let {ratio}[24]: float = 0.75;
let {nothing}[25]: null = null;
RedEX literals are lowercase: true, false, and null. Forms such as True, False, NULL, Null, NUL, and nullptr are deliberately diagnosed as RX-SYNTAX-001.
Numeric forms include decimal, floating point, hexadecimal (0xFF), and binary (0b1010).
The editor recognizes these core type words:
string char bool byte int float number null void any
table map set option result task channel bytes
Examples:
let {name}[30]: string = "RedEX";
let {letter}[31]: char = 'R';
let {payload}[32]: bytes = bytes.from("data");
let {anything}[33]: any = 42;
let {scores}[40]: table<int> = [10, 20, 30];
let {uniqueIds}[41]: set<int> = set(1, 2, 3);
let {profile}[42]: map<string, string> = { "name": "Ada" };
let {pair}[43] = ("port", 4217);
let {exclusivePages}[44] = 1..10;
let {inclusivePages}[45] = 1..=10;
Generic type arguments use angle brackets. Collection behavior belongs to the production runtime; Monaco currently supplies syntax/bracket editing and the RedEX formatter preserves the structure.
let {plain}[46]: string = "Hello";
let {raw}[47]: string = r"C:\project\file";
let {message}[48]: string = f"Hello {name}";
- Normal strings use
"…". r"…"is highlighted as a raw string.f"…"is highlighted as an interpolated string.- The preview runner evaluates simple named interpolation in
io.print(f"…").
public fn {add}[50](left: int, right: int) -> int {
return left + right;
}
public fn {identity}[51]<T>(value: T) -> T {
return value;
}
private fn {logInternal}[52](message: string) -> void {
io.print(message);
}
Functions use fn, a referenced name, parameters, ->, and a return type. void means no returned value. Generic parameters follow the declaration name.
if score >= 90 {
io.print("A");
} else if score >= 80 {
io.print("B");
} else {
io.print("C");
}
let label = match status {
200 => "ok",
404 => "missing",
_ => "other",
};
The tokenizer recognizes equality, comparison, boolean, arithmetic, assignment, null-coalescing, range, and arrow operators.
for item in items {
io.print(f"{item}");
}
while connected {
network.poll();
}
loop {
if finished { break; }
if shouldSkip { continue; }
}
public record {User}[60] {
public {id}[61]: int,
public {name}[62]: string,
}
public enum {Role}[63] {
{Admin}[64],
{Member}[65],
}
public trait {Display}[66] {
fn {display}[67](self) -> string;
}
impl Display for User {
fn {display}[68](self) -> string {
return self.name;
}
}
Records, enums, and traits appear in the Reference Outline with their stable references.
fn {findUser}[70](id: int) -> option<User> {
return none;
}
fn {parsePort}[71](text: string) -> result<int, string> {
return int.parse(text);
}
let port = parsePort("4217")?;
option<T> represents a possibly absent value. some and none represent its states. result<T,E> represents success or recoverable failure; ok, fail, and ? are reserved for result flow.
try {
await service.connect();
} catch error {
io.print(f"Connection failed: {error}");
} finally {
service.close();
}
The design reserves try, catch, finally, and throw. Prefer typed result<T,E> for expected recoverable failures.
public async fn {loadUser}[72](id: int) -> task<User> {
return await api.users.get(id);
}
let worker = spawn processQueue();
let events: channel<string> = channel.create();
async, await, spawn, task, and channel are reserved and highlighted. The full scheduler/channel runtime is beyond the current preview runner.
let text = await fs.readText("README.md");
await fs.writeText("output.txt", text);
let response = await http.get("https://example.com/data.json");
let payload = await response.json();
These calls describe standard-library direction. They require the future production RedEX runtime; Help Write and the editor should not claim they executed in the preview.
mount db $"Accounts"[764]
from "data/Accounts.rexdb"
as accounts;
transaction [764] {
accounts.Users.insert(user);
}
watch ${764[46]} as oldValue, newValue {
io.print(f"Changed from {oldValue} to {newValue}");
}
mount,db,from, andasidentify database storage.transactiondefines an atomic data operation.watchobserves a stable data reference.${764[46]}addresses referenced data rather than a changeable name.
let activeUsers = select all from accounts.Users
where enabled == true
order name ascending
first 10;
let total = select count from accounts.Users;
The language reserves select, where, order, ascending, descending, first, count, all, and with for query work.
@test
fn {addsNumbers}[90]() -> void {
assert.equal(add(2, 3), 5);
}
@test is an annotation-style entry for the planned test runner. The current editor highlights annotations; production test execution remains a compiler/runtime milestone.
RedEXCompile’s formatter:
- normalizes line endings;
- uses four-space indentation;
- adjusts indentation around bracketed blocks;
- reduces runs of blank lines;
- preserves comment blocks; and
- leaves stable numeric references unchanged.
Current diagnostic codes:
| Code | Meaning |
|---|---|
RX-SYNTAX-001 |
Non-RedEX uppercase/null literal |
RX-REF-002 |
Duplicate declaration reference |
RX-MODULE-001 |
Suggested module declaration missing |
RX-MODULE-002 |
More than one main module |
RX-CALL-001 |
More than one entry point |
RX-SYNTAX-003 |
Unexpected closing bracket |
RX-SYNTAX-004 |
Unclosed opening bracket |
RX-SYNTAX-005 |
Unclosed multiline comment |
Errors display as red squiggles, Problems entries, and red glyphs beside line numbers.
redex new MyProject
redex check MyProject
redex format MyProject
redex run MyProject
redex build MyProjectThe preview runner evaluates simple let/const literal declarations, interpolated strings, and io.print. Unsupported expressions are labeled rather than falsely reported as executed.
.RedEXP is a separate declarative JSON format:
{
"redexp": 1,
"name": "My Plugin",
"version": "0.1.0",
"description": "Adds RedEX snippets.",
"contributes": {
"snippets": [
{
"language": "redex",
"prefix": "hello",
"description": "Insert a hello message",
"body": "io.print(\"Hello\");"
}
],
"theme": { "accent": "#ed2d43" }
}
}Executable code, main, and scripts fields are rejected. Plugin metadata must match the public registry entry before a remote install succeeds.
| Capability | Current |
|---|---|
| File recognition and red-X icon | Yes |
| Syntax highlighting | Yes |
| Snippets and name completion | Yes |
| Brackets/autoclosing | Yes |
| Formatter | Yes |
| Reference outline | Yes |
| Core structural diagnostics | Yes |
Literal/io.print preview |
Yes |
| Complete type checker | Not yet |
| Production compiler/runtime | Not yet |
| Full database engine | Not yet |
| Debug adapter and breakpoints | Not yet |
This distinction is intentional: RedEXCompile should expose what works today without presenting future language design as an already-complete compiler.