This page describes the RustScript syntax accepted by project-d.
A program is a sequence of statements until end of file.
Program ::= Statement*RustScript uses use, not import.
For local .rss modules, the source loader accepts:
use math;
use self::math;
use super::stdlib::rss::strings::{trim, split as split_string};
use super::stdlib::rss::iter::*;
use super::stdlib::rss::iter::{*};
use super::stdlib::rss::strings as string;
Rules:
use path;imports all public symbols from the target module.use path::*;anduse path::{*};import all public symbols explicitly.use path::{name, other as alias};imports selected public symbols.use path as alias;imports a namespace alias.selfandsuperare supported path qualifiers.crate::paths are rejected.- If the path does not end with
.rss,.rssis appended by the loader.
Inside the parser, built-in and host namespaces also use use:
use json;
use http;
use runtime as rt;
use http::{request as req};
Built-in namespaces must be imported as namespaces and called through that namespace; built-in use-lists are rejected.
Struct declarations define named object schemas for type checking.
struct Point {
x: int,
y: int,
}
struct Box<T> {
value: T,
}
Struct fields are name: Type pairs separated by commas. A trailing comma is allowed.
Functions may be declared, defined with an expression body, or defined with a block body.
fn declared(x: int) -> int;
fn double(x: int) -> int = x + x;
pub fn id<T>(value: T) -> T {
value
}
Rules:
pub fnmarks a function as exported.- Generic parameters use
<T, U>after the function name. - Parameters may omit type annotations.
- Return type syntax is
-> Type. - A return type may be followed by
?to make it optional. - A block body must end in an expression; a final semicolon makes the function return invalid for lint/spec purposes.
- A trailing semicolon after a block function body is tolerated.
Implemented primitive and structural type schemas:
unknown
null
int
float
number
bool
string
bytes
array
array<T>
map
map<T>
Name
Name<T, U>
T
[T]
[A, B]
[A, B, T...]
fn(A, B) -> R
Type?
Type[]
Notes:
unknownis accepted but tracked by diagnostics.- Inline object type schemas are rejected; use
structand refer to the struct name. [T]is an array ofT.[A, B]is a fixed tuple-style array schema.[A, B, T...]is a tuple prefix followed by a variadic rest type.Type?wraps a type in an optional schema.Type[]is an array alias and may repeat.
let value = 1;
let typed: int = 1;
let mut total = 0;
total = total + 1;
total += 1;
total++;
++total;
mut is enforced when mutable binding checks are enabled by the compiler pipeline. += and ++ require RustScript dialect support and are available in the RustScript frontend.
if condition {
statement;
} else if other_condition {
statement;
} else {
statement;
}
while condition {
statement;
}
RustScript supports Rust-style integer ranges and borrowed map entry iteration:
for i in 0..10 {
statement;
}
for i in 0..=10 {
statement;
}
for (key, value) in &map_value {
statement;
}
for (key: string, value: int) in &typed_map {
statement;
}
.. is an exclusive integer range, and ..= is inclusive. Borrowed map iteration visits each entry once without creating a keys array or performing a second lookup. Its order is unspecified. The map local is immutably borrowed for the loop body and cannot be assigned to or mutated there. Loop bindings are immutable unless a future pattern form explicitly declares otherwise.
Because map<T> describes the value type while map keys remain dynamic, strict-typing code should annotate a key binding when its concrete type is required. Parenthesized C-style loop heads are rejected. Use while for custom steps or descending loops.
break;
continue;
Both are only valid inside loops.
Expression precedence, from low to high:
| Level | Operators/forms | Associativity |
|---|---|---|
| Logical OR | ` | |
| Logical AND | && |
left |
| Comparison | ==, !=, <, <=, >, >= |
left |
| Additive | +, - |
left |
| Multiplicative | *, /, % |
left |
| Unary | &, &mut, -, !, prefix ++ |
right |
| Primary/postfix | calls, indexing, slicing, member access, optional access, postfix ++ |
left |
null
true
false
123
1.25
"text"
b"bytes"
name
name(args...)
namespace::function(args...)
function::<T>(args...)
(namespace_expr)
[array, values]
{key: value, other = value}
Named functions, imported functions, built-ins, and host calls use call syntax:
add(1, 2)
json::decode::<Payload>(body)
http::request::get_header("x-id")
Explicit type arguments require a direct function call. Local function values do not accept explicit type arguments.
value.field
value[0]
value[start:end]
value[:end]
value[start:]
Special members:
value.copy()
value.unwrap_or(fallback)
value.length
value.has(key)
value.keys
value.unwrap() is rejected; use unwrap_or or explicit optional handling.
Optional access:
value?.field
value?.[key]
[]
[1, 2, 3]
{}
{"x": 1, y: 2, [dynamic_key]: 3}
{0: "zero", true: "yes", null: "nil"}
If a brace literal contains map entries, bare expression entries are also accepted and receive sequential integer keys starting at 0. Otherwise a brace literal with only expressions is lowered as an array-style literal.
If expressions use => and require an else branch:
let value = if condition => {
1
} else if other => {
2
} else => {
3
};
Each branch is a block that must end with an expression.
let out = match value {
0 => "zero",
"x" => "x",
null => "nil",
Some(inner) => inner,
Option::None => "none",
Some(int) => "integer optional",
_ => "default",
};
Supported patterns:
- integer literals
- string literals
- bytes literals
nullNoneOption::NoneSome(name)bindingSome(TypeName)type patterns forint,float,number,bool,string,bytes,array,mapand their capitalized names_wildcard
A wildcard arm is required. Non-wildcard arms cannot appear after the wildcard arm.
Pipe closures are available in RustScript:
|x| x + 1
|x, y| x + y
|| 42
Closures have expression bodies. Block bodies are not supported by the RustScript dialect.
The parser recognizes these language-level calls:
print(value);
println(value);
println("x = {}", x);
type(value);
assert(condition);
print and println support Rust-style format strings when the first argument is a string literal and more arguments follow.