Write in Arabic. Run here.

Loading the editor…

This program sums the integers from 1 to 10. On success it prints 55 and returns status 0. Edit the source, then press Run.

Compilation and execution happen in your browser. Source is not sent to a server.

Continue to learning the language

Learn from one program

Values, conditions and loops

The storable numeric types are ص8/i8, ص16/i16, ص32/i32, ص64/i64, ط8/u8, ط16/u16, ط32/u32, ط64/u64, ع32/f32, ع64/f64, alongside bool, string, c_ptr. unit means no result. Use دع / let for immutable bindings and متغير / var for mutation. Conditions require booleans. Start with the simple sum, then use the numeric reference for exact types and explicit conversions.

Read and check the example Continue to the exact contract Normative release limitations

Native HTTP with ASPL 0.5.0

ASPL 0.5.0 includes native HTTP/1.1 and verified HTTPS, service state and stop, and upstream requests inside handlers. Read the guides: English / العربية, API English / المرجع العربي, Deployment English / النشر بالعربية. The checked source examples use both .aspl and .لبات.

Each file uses import core::http; or استورد أساسي::ويب. and qualifies members with its written prefix. Browser/private embedding reject this library before effects with unsupported-supplied-library-profile. Run the networking examples with the native tool.

Host applicability: native

aspl check docs/examples/http/en/service.aspl
aspl run docs/examples/http/en/service.aspl
aspl check docs/examples/http/ar/service.لبات
aspl run docs/examples/http/ar/service.لبات
Normative release limitations

Consult the contract

Program and process status

One .aspl file contains function definitions and foreign declarations. The required ابدأ_الرئيسية / start_main takes no parameters and returns i64. Valid statuses are 0..255; any other value traps instead of truncating.

Accepted: top-level functions. Rejected: global bindings, statements outside functions, a missing entry function, or calling it from source.

hello-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout ""
native: check 0; success / status 0; stdout ""
Download source Open in the editor
aspl check hello.aspl
aspl run hello.aspl
hello-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout ""
native: check 0; success / status 0; stdout ""
Download source Open in the editor
aspl check hello.aspl
aspl run hello.aspl

Reasons and outcomes: missing-entry-function, invalid-entry-signature, entry-call-not-allowed; trap / invalid-process-status

Host applicability: shared

Normative release limitations

Source notation

Source is strict UTF-8 under Unicode 17.0. Identifiers are case-sensitive NFC names, each using one Arabic or Latin script. English keywords and word operators are exact aliases and may mix. Executable digits and punctuation use ASCII; equality, conjunction, and disjunction use matches, and, and or or their Arabic aliases يطابق, تطابق, و, and أو. Numeric prefixes are 0x/0X and 0b/0B, or 0س and 0ث; Arabic hexadecimal uses ا ب ت ث ج ح for values 10 through 15. Statements end with . or ;. Each numeric token stays LTR in logical source order, and display order never changes source bytes.

Accepted: Arabic and English keywords and either radix alphabet in one program. Rejected: unconverted non-ASCII digits outside strings and comments, an identifier mixing scripts, or a hexadecimal spelling that mixes alphabets. The editor converts Arabic-Indic and Extended Arabic-Indic digits to ASCII outside strings and comments, and makes invisible controls visible.

Reasons and outcomes: non-ascii-digit, mixed-script-identifier

Host applicability: shared

Read and check the example Normative release limitations

Types and control flow

There are no implicit conversions. Every typed numeric value keeps its exact width and signedness. Operations need matching operand types, and boundaries and aggregates do not convert values. The only conversion applies a numeric type name explicitly, such as ط8(value) or u8(value), and it can trap when the value is not representable. ص64/i64 remains the type for the entry result, indexes, lengths, and Unicode bounds. Strings are immutable, c_ptr is opaque and nullable, and unit cannot be stored. Initialized bindings may infer their type, if, while require booleans, and return must match its declared result.

Accepted: assigning a mutable binding and using a comparison as a boolean condition. Rejected: uninitialized bindings, immutable assignment, or implicitly mixing numeric types.

sum-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    متغير المجموع: ص64 = 0.
    متغير العدد: ص64 = 1.
    طالما (العدد <= 10) {
        المجموع = المجموع + العدد.
        العدد = العدد + 1.
    }
    إذا (المجموع يطابق 55) {
        اطبع("55\n").
        أرجع 0.
    }
    أرجع 1.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "55\n"
native: check 0; success / status 0; stdout "55\n"
Download source Open in the editor
aspl check sum-ar.aspl
aspl run sum-ar.aspl
sum-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    var المجموع: i64 = 0;
    var العدد: i64 = 1;
    while (العدد <= 10) {
        المجموع = المجموع + العدد;
        العدد = العدد + 1;
    }
    if (المجموع matches 55) {
        print("55\n");
        return 0;
    }
    return 1;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "55\n"
native: check 0; success / status 0; stdout "55\n"
Download source Open in the editor
aspl check sum-en.aspl
aspl run sum-en.aspl
sum-mixed · ASPL 0.5.0

Browser and native

fn ابدأ_الرئيسية() -> ص64 {
    متغير المجموع: ص64 = 0;
    متغير العدد: ص64 = 1;
    طالما (العدد <= 10) {
        المجموع = المجموع + العدد;
        العدد = العدد + 1;
    }
    إذا (المجموع matches 55) {
        print("55\n");
        return 0;
    }
    أرجع 1;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "55\n"
native: check 0; success / status 0; stdout "55\n"
Download source Open in the editor
aspl check sum-mixed.aspl
aspl run sum-mixed.aspl

Reasons and outcomes: immutable-assignment, type-mismatch; trap / integer-overflow

Host applicability: shared

Normative release limitations

Exact numeric family

The reserved pairs are ص8/i8 from -128 through 127, ص16/i16 from -32768 through 32767, ص32/i32 from -2147483648 through 2147483647, ص64/i64 from -9223372036854775808 through 9223372036854775807, ط8/u8 from 0 through 255, ط16/u16 from 0 through 65535, ط32/u32 from 0 through 4294967295, ط64/u64 from 0 through 18446744073709551615, plus ع32/f32 and ع64/f64 for IEEE 754 binary32 and binary64. Each pair is one type identity. User declarations cannot reuse these names or numeric parse and format names.

Accepted: a literal in a known typed position, an explicit conversion, and a copied list<u8> that is then mutated. Rejected: typed operands of different numeric types, or an implicit conversion at a binding, call, return, list element, record field, or result payload.

A decimal integer with leading zeroes remains decimal. Latin hexadecimal 0x/0X accepts digits and a..f/A..F, while 0س accepts digits and ا ب ت ث ج ح. Binary is 0b/0B or 0ث. Each prefix needs at least one digit. _ may appear only between valid digits, never beside a prefix, decimal point, or exponent marker, and never first, last, or repeated. There are no type suffixes, octal, hexadecimal floats, NaN literals, or infinity literals. A period terminates a statement unless it starts a fraction: 1. is an integer then a terminator, while 1.0. is a float then a terminator.

Precedence runs from calls, indexing, fields, and grouping; through ! - ~, * / %, + -, shifts, &, ^, |, ordered comparisons, equality, Boolean AND, and Boolean OR. Binary operators associate left and unary operators associate right. Context comes from an annotation, assignment, parameter, return, field, list, result, or typed operand. A literal without context defaults to i64 or f64. Direct minus admits every signed minimum, and a contextual u64 literal reaches 18446744073709551615. The checker does not select the smallest fitting type or convert an already typed value.

Addition, subtraction, multiplication, and division need one matching type and return it. % is integer-only. Addition, subtraction, multiplication, and negation trap with integer-overflow rather than wrapping. Division truncates toward zero, the remainder takes the dividend's sign, and zero or signed-minimum divided or remaindered by -1 traps. ~ & ^ | << >> work at the operand's exact width. A shift count may be any integer type and is not converted to the left type. A negative count or one equal to or greater than the width traps with invalid-shift-count. Left shift discards high bits, unsigned right shift fills with zero, and signed right shift extends the sign.

Each f32 or f64 primitive rounds to nearest even at its own width before the next operation. Multiplication and addition do not fuse. Subnormals, signed zero, infinities, and IEEE results from division by zero remain values. Arithmetic NaNs become positive quiet NaNs and ordered NaN comparisons are false. An explicit conversion applies any numeric type name to a numeric expression only. Integer-to-integer conversion checks range. Integer-to-float conversion rounds the mathematical integer directly to the target width, nearest even, and every integer is finite; the largest u64 therefore becomes 2^64 in f64. Float-to-integer conversion truncates before range checking, and float-width conversion rounds without trapping. A value-dependent conversion failure happens only when execution reaches it. Its classifications are below-range, above-range, nan, positive-infinity, and negative-infinity. Nested conversions run inside out and retain every rounding point.

Every type has a parser and formatter: حلل_ص8/parse_i8 and نسق_ص8/format_i8; حلل_ص16/parse_i16 and نسق_ص16/format_i16; حلل_ص32/parse_i32 and نسق_ص32/format_i32; حلل_ص64/parse_i64 and نسق_ص64/format_i64; حلل_ط8/parse_u8 and نسق_ط8/format_u8; حلل_ط16/parse_u16 and نسق_ط16/format_u16; حلل_ط32/parse_u32 and نسق_ط32/format_u32; حلل_ط64/parse_u64 and نسق_ط64/format_u64; حلل_ع32/parse_f32 and نسق_ع32/format_f32; حلل_ع64/parse_f64 and نسق_ع64/format_f64. A parser takes string and returns result<T>; a formatter takes exactly T and returns string. Integer text is an optional ASCII sign followed by ASCII decimal digits. Float text has digits, an optional fraction with following digits, and an optional exponent with digits, or exactly nan, inf, +inf, -inf. These are runtime-text rules, not source-literal rules: whitespace, separators, prefixes, suffixes, NUL, trailing text, and non-ASCII digits fail, as do float forms .5 and 1.. Parsing checks the whole grammar before range. Exact messages are invalid number for T, number out of range for T (MIN through MAX), or finite number out of range for T. A failed result has no diagnostic, source location, or trace. Formatting is deterministic ASCII and round trips every finite float, with -0, nan, inf, and -inf written exactly.

Bindings, parameters, returns, record fields, lists, and result payloads preserve all ten types exactly. Each reserved numeric-list slot takes its scalar width: 1 byte for i8/u8, 2 for i16/u16, 4 for i32/u32/f32, and 8 for i64/u64/f64. Length, capacity, and charges are separate. An empty list has zero capacity, nonempty capacity is between length and max(4, 2 * length), and element charge is capacity * width. Copies share first and detach on mutation, then the last owner reclaims storage. There is no public byte view or promise about addresses, alignment, byte order, or C layout. Memory limits, cancellation, and allocation failure do not publish a partial mutation.

This is development documentation for ASPL 0.5.0, private bytecode version 5, and browser-result wire version 3. The contributor-only example creates valid version-5 bytecode, changes the byte at offset 36 without updating its CRC, saves it as corrupted-v5.asplbc, then passes it to validate-bytecode corrupted-v5.asplbc; it reports load-failure / invalid-bytecode before execution. This is not a public path. A checking error and diagnostic, an ASPL trap, a failed result, a load failure, and a resource, cancellation, or host outcome are different results. Diagnostics and traps keep full-width ASCII technical fields in Arabic and English. Direct execution identifies a source location. A generated native program identifies its function name and relative instruction index.

numeric-types-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    دع الحد: ط64 = 18446744073709551615.
    دع مباشر: ع32 = 1.0000000596046448.
    دع بتات: ط8 = 0سحح.
    دع محول: ط8 = ط8(255).
    إذا (نسق_ط64(الحد) لا يطابق "18446744073709551615") { أرجع 1. }
    إذا (نسق_ع32(مباشر) لا يطابق "1.00000012") { أرجع 2. }
    إذا ((بتات & 0س0ح) لا يطابق 15 أو (بتات >> 4) لا يطابق 15 أو محول لا يطابق 255) { أرجع 3. }
    متغير بايتات: قائمة<ط8> = [0, 255].
    متغير نسخة: قائمة<ط8> = بايتات.
    نسخة[0] = بتات << 0.
    إذا (بايتات[0] لا يطابق 0 أو نسخة[0] لا يطابق 255) { أرجع 4. }
    اطبع("numeric types\n").
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "numeric types\n"
native: check 0; success / status 0; stdout "numeric types\n"
Download source Open in the editor
aspl check numeric-types-ar.aspl
aspl run numeric-types-ar.aspl
numeric-types-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    let الحد: ط64 = 18446744073709551615;
    let مباشر: f32 = 1.0000000596046448;
    let بتات: ط8 = 0سحح;
    let محول: ط8 = ط8(255);
    if (format_u64(الحد) not match "18446744073709551615") { return 1; }
    if (format_f32(مباشر) not match "1.00000012") { return 2; }
    if ((بتات & 0س0ح) not match 15 or (بتات >> 4) not match 15 or محول not match 255) { return 3; }
    var بايتات: list<ط8> = [0, 255];
    var نسخة: list<ط8> = بايتات;
    نسخة[0] = بتات << 0;
    if (بايتات[0] not match 0 or نسخة[0] not match 255) { return 4; }
    print("numeric types\n");
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "numeric types\n"
native: check 0; success / status 0; stdout "numeric types\n"
Download source Open in the editor
aspl check numeric-types-en.aspl
aspl run numeric-types-en.aspl
numeric-types-mixed · ASPL 0.5.0

Browser and native

fn ابدأ_الرئيسية() -> i64 {
    دع maximum: u64 = 18446744073709551615.
    let direct: ع32 = 1.0000000596046448;
    let latin: ط8 = 0xff;
    دع عربي: u8 = 0سحح.
    let binary_latin: u8 = 0b0011;
    دع binary_arabic: ط8 = 0ث0011.
    let converted: u8 = ط8(255);
    if (نسق_ط64(maximum) not match "18446744073709551615") { return 1. }
    إذا (format_f32(direct) not match "1.00000012") { أرجع 2; }
    if ((latin & 0x0f) not match 15 or (عربي >> 4) not match 15) { return 3. }
    إذا ((binary_latin | binary_arabic) not match 3 أو converted not match 255) { أرجع 4; }
    var bytes: قائمة<u8> = [0, latin];
    متغير copy: list<ط8> = bytes.
    copy[0] = عربي.
    if (bytes[0] not match 0 or copy[0] not match 255) { return 5. }
    print("numeric types\n");
    return 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "numeric types\n"
native: check 0; success / status 0; stdout "numeric types\n"
Download source Open in the editor
aspl check numeric-types-mixed.aspl
aspl run numeric-types-mixed.aspl
numeric-range-check-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    دع بايت: ط8 = 256.
    أرجع 0.
}

Expected outcomes and literal output

browser: check source-error; source-error / numeric-literal-out-of-range; stdout ""
native: check 1; source-error / status 1 / numeric-literal-out-of-range; stdout ""
Download source Open in the editor
aspl check numeric-range-check-ar.aspl
numeric-range-check-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    let بايت: ط8 = 256;
    return 0;
}

Expected outcomes and literal output

browser: check source-error; source-error / numeric-literal-out-of-range; stdout ""
native: check 1; source-error / status 1 / numeric-literal-out-of-range; stdout ""
Download source Open in the editor
aspl check numeric-range-check-en.aspl
numeric-conversion-trap-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    دع بايت: ط8 = ط8(256).
    اطبع(نسق_ط8(بايت)).
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; trap / invalid-numeric-conversion; stdout ""
native: check 0; success / status 5 / invalid-numeric-conversion; stdout ""
Download source Open in the editor
aspl check numeric-conversion-trap-ar.aspl
aspl run numeric-conversion-trap-ar.aspl
numeric-conversion-trap-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    let بايت: ط8 = ط8(256);
    print(format_u8(بايت));
    return 0;
}

Expected outcomes and literal output

browser: check success; trap / invalid-numeric-conversion; stdout ""
native: check 0; success / status 5 / invalid-numeric-conversion; stdout ""
Download source Open in the editor
aspl check numeric-conversion-trap-en.aspl
aspl run numeric-conversion-trap-en.aspl

Reasons and outcomes: source-error / numeric-literal-out-of-range; trap / integer-overflow, integer-zero-divisor, invalid-shift-count, invalid-numeric-conversion; result / invalid-number, number-out-of-range; load-failure / invalid-bytecode; limit-stop, cancelled, host-failure

Host applicability: shared

Normative release limitations

Strings and Unicode

A string is an immutable UTF-8 value. طول / length: (string) -> i64 counts Unicode scalar values from zero. محرف_عند / char_at: (string, i64) -> string returns one scalar as a string and رمز_عند / codepoint_at: (string, i64) -> i64 returns its numeric value. من_رمز / from_codepoint: (i64) -> string builds a character from a valid scalar including zero and rejects surrogates and values outside U+10FFFF. اقتطع / slice: (string, i64, i64) -> string includes its start and excludes its end. + concatenates exactly two strings at the existing addition precedence and never formats numbers implicitly. اجمع_نصوص / join: (list<string>, string) -> string joins a list of strings with the separator between elements only, sizing once and allocating the result once; an empty list yields the empty string. حلل_ص64 / parse_i64: (string) -> result<i64> accepts an optional ASCII sign followed by ASCII decimal digits with leading zeroes across the full i64 range including the minimum value, and rejects whitespace, separators, suffixes, NUL, trailing text, and non-ASCII digits, returning invalid-number or number-out-of-range as a recoverable result. نسق_ص64 / format_i64: (i64) -> string returns the canonical decimal text with no positive sign, grouping, or redundant leading zeroes. حلل_ع64 / parse_f64: (string) -> result<f64> accepts ASCII decimal text with an optional sign, decimal point, and exponent, including integer-only text and the exact nan, inf, +inf, and -inf spellings, and rejects whitespace, trailing text, and non-ASCII digits, returning invalid-number or number-out-of-range as a recoverable result. نسق_ع64 / format_f64: (f64) -> string returns locale-independent ASCII text that parses back to the same binary64 value, using nan, inf, and -inf for nonfinite values. Embedded NUL, bidi controls, whitespace, and normalization are preserved, and equality compares exact bytes.

Accepted: empty strings, empty slices, concatenating two strings, joining a string list with a separator, and parsing/formatting integers and floating-point values round trip. Rejected: negative or out-of-range indexes, reversed slices, invalid Unicode values, mixing a string with a number, non-string join elements, or numeric text with whitespace or trailing text.

strings-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    دع المتن = "aمرحبا😀".
    إذا (طول(المتن) لا يطابق 7) { أرجع 1. }
    إذا (محرف_عند(المتن, 1) لا يطابق "م") { أرجع 2. }
    إذا (رمز_عند(المتن, 1) لا يطابق 1605) { أرجع 3. }
    إذا (من_رمز(65) لا يطابق "A") { أرجع 4. }
    إذا (اقتطع(المتن, 1, 3) لا يطابق "مر") { أرجع 5. }
    دع الرسالة = المتن + "!".
    اطبع(الرسالة).
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "aمرحبا😀!"
native: check 0; success / status 0; stdout "aمرحبا😀!"
Download source Open in the editor
aspl check strings-ar.aspl
aspl run strings-ar.aspl
strings-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    let المتن = "aمرحبا😀";
    if (length(المتن) not match 7) { return 1; }
    if (char_at(المتن, 1) not match "م") { return 2; }
    if (codepoint_at(المتن, 1) not match 1605) { return 3; }
    if (from_codepoint(65) not match "A") { return 4; }
    if (slice(المتن, 1, 3) not match "مر") { return 5; }
    let الرسالة = المتن + "!";
    print(الرسالة);
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "aمرحبا😀!"
native: check 0; success / status 0; stdout "aمرحبا😀!"
Download source Open in the editor
aspl check strings-en.aspl
aspl run strings-en.aspl
strings-mixed · ASPL 0.5.0

Browser and native

fn ابدأ_الرئيسية() -> ص64 {
    دع المتن = "aمرحبا😀";
    if (طول(المتن) not match 7) { return 1; }
    إذا (char_at(المتن, 1) not match "م") { أرجع 2. }
    let رمز = رمز_عند(المتن, 1);
    if (رمز not match 1605) { return 3; }
    دع حرف = from_codepoint(65).
    إذا (حرف not match "A") { أرجع 4. }
    let مقطع = اقتطع(المتن, 1, 3);
    if (مقطع not match "مر") { return 5; }
    دع الرسالة = المتن + "!";
    اطبع(الرسالة).
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "aمرحبا😀!"
native: check 0; success / status 0; stdout "aمرحبا😀!"
Download source Open in the editor
aspl check strings-mixed.aspl
aspl run strings-mixed.aspl
join-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    دع فارغة: قائمة<نص> = [].
    إذا (اجمع_نصوص(فارغة, ",") لا يطابق "") { أرجع 1. }
    دع واحدة: قائمة<نص> = ["مرحبا"].
    إذا (اجمع_نصوص(واحدة, ",") لا يطابق "مرحبا") { أرجع 2. }
    دع أجزاء: قائمة<نص> = ["a", "b", "c"].
    إذا (اجمع_نصوص(أجزاء, ",") لا يطابق "a,b,c") { أرجع 3. }
    إذا (اجمع_نصوص(أجزاء, "") لا يطابق "abc") { أرجع 4. }
    اطبع(اجمع_نصوص(أجزاء, ",")).
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "a,b,c"
native: check 0; success / status 0; stdout "a,b,c"
Download source Open in the editor
aspl check join-ar.aspl
aspl run join-ar.aspl
join-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    let فارغة: list<string> = [];
    if (join(فارغة, ",") not match "") { return 1; }
    let واحدة: list<string> = ["مرحبا"];
    if (join(واحدة, ",") not match "مرحبا") { return 2; }
    let أجزاء: list<string> = ["a", "b", "c"];
    if (join(أجزاء, ",") not match "a,b,c") { return 3; }
    if (join(أجزاء, "") not match "abc") { return 4; }
    print(join(أجزاء, ","));
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "a,b,c"
native: check 0; success / status 0; stdout "a,b,c"
Download source Open in the editor
aspl check join-en.aspl
aspl run join-en.aspl
join-mixed · ASPL 0.5.0

Browser and native

fn ابدأ_الرئيسية() -> ص64 {
    دع فارغة: قائمة<string> = [].
    if (اجمع_نصوص(فارغة, ",") not match "") { return 1; }
    دع واحدة: list<نص> = ["مرحبا"];
    إذا (join(واحدة, ",") not match "مرحبا") { أرجع 2. }
    let أجزاء: قائمة<string> = ["a", "b", "c"];
    if (طول(أجزاء) not match 3) { return 3; }
    إذا (اجمع_نصوص(أجزاء, ",") not match "a,b,c") { أرجع 4. }
    if (join(أجزاء, "") not match "abc") { return 5; }
    اطبع(join(أجزاء, ",")).
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "a,b,c"
native: check 0; success / status 0; stdout "a,b,c"
Download source Open in the editor
aspl check join-mixed.aspl
aspl run join-mixed.aspl
parse-int-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    اطبع("first: ").
    دع سيئ: نتيجة<ط8> = حلل_ط8(اقرأ_سطر()).
    إذا (سيئ::نجاح) {
        أرجع 1.
    }
    اطبع(سيئ::الخطأ::الرمز).
    اطبع("\nsecond: ").
    دع جيد: نتيجة<ص64> = حلل_ص64(اقرأ_سطر()).
    إذا (جيد::نجاح) {
        إذا (نسق_ص64(-9223372036854775808) لا يطابق "-9223372036854775808") { أرجع 2. }
        اطبع(نسق_ص64(جيد::قيمة + 1)).
        اطبع("\n").
        أرجع 0.
    }
    أرجع 3.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "first: number-out-of-range\nsecond: 42\n"
native: check 0; success / status 0; stdout "first: number-out-of-range\nsecond: 42\n"
scripted stdin lines: ["256","41"]
Download source Open in the editor
aspl check parse-int-ar.aspl
aspl run parse-int-ar.aspl
parse-int-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    print("first: ");
    let سيئ: result<ط8> = parse_u8(read_line());
    if (سيئ::ok) {
        return 1;
    }
    print(سيئ::error::code);
    print("\nsecond: ");
    let جيد: result<i64> = parse_i64(read_line());
    if (جيد::ok) {
        if (format_i64(-9223372036854775808) not match "-9223372036854775808") { return 2; }
        print(format_i64(جيد::value + 1));
        print("\n");
        return 0;
    }
    return 3;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "first: number-out-of-range\nsecond: 42\n"
native: check 0; success / status 0; stdout "first: number-out-of-range\nsecond: 42\n"
scripted stdin lines: ["256","41"]
Download source Open in the editor
aspl check parse-int-en.aspl
aspl run parse-int-en.aspl
parse-int-mixed · ASPL 0.5.0

Browser and native

fn ابدأ_الرئيسية() -> ص64 {
    اطبع("first: ").
    let سيئ: نتيجة<u8> = parse_u8(اقرأ_سطر()).
    إذا (سيئ::ok) { أرجع 1. }
    print(سيئ::الخطأ::code).
    print("\nsecond: ").
    دع جيد: result<ص64> = حلل_ص64(read_line()).
    if (جيد::نجاح) {
        إذا (format_i64(-9223372036854775808) not match "-9223372036854775808") { return 2. }
        اطبع(نسق_ص64(جيد::value + 1)).
        print("\n").
        أرجع 0.
    }
    return 3.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "first: number-out-of-range\nsecond: 42\n"
native: check 0; success / status 0; stdout "first: number-out-of-range\nsecond: 42\n"
scripted stdin lines: ["256","41"]
Download source Open in the editor
aspl check parse-int-mixed.aspl
aspl run parse-int-mixed.aspl
parse-float-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    اطبع("first: ").
    دع سيئ: نتيجة<ع32> = حلل_ع32(اقرأ_سطر()).
    إذا (سيئ::نجاح) {
        أرجع 1.
    }
    اطبع(سيئ::الخطأ::الرمز).
    اطبع("\nsecond: ").
    دع جيد: نتيجة<ع64> = حلل_ع64(اقرأ_سطر()).
    إذا (جيد::نجاح) {
        إذا (نسق_ع64(0.5) لا يطابق "0.5") { أرجع 2. }
        إذا (نسق_ع32(1.0000000596046448) لا يطابق "1.00000012") { أرجع 3. }
        اطبع(نسق_ع64(جيد::قيمة + 1.0)).
        اطبع("\n").
        أرجع 0.
    }
    أرجع 4.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "first: invalid-number\nsecond: 42\n"
native: check 0; success / status 0; stdout "first: invalid-number\nsecond: 42\n"
scripted stdin lines: ["12x","41"]
Download source Open in the editor
aspl check parse-float-ar.aspl
aspl run parse-float-ar.aspl
parse-float-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    print("first: ");
    let سيئ: result<f32> = parse_f32(read_line());
    if (سيئ::ok) {
        return 1;
    }
    print(سيئ::error::code);
    print("\nsecond: ");
    let جيد: result<f64> = parse_f64(read_line());
    if (جيد::ok) {
        if (format_f64(0.5) not match "0.5") { return 2; }
        if (format_f32(1.0000000596046448) not match "1.00000012") { return 3; }
        print(format_f64(جيد::value + 1.0));
        print("\n");
        return 0;
    }
    return 4;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "first: invalid-number\nsecond: 42\n"
native: check 0; success / status 0; stdout "first: invalid-number\nsecond: 42\n"
scripted stdin lines: ["12x","41"]
Download source Open in the editor
aspl check parse-float-en.aspl
aspl run parse-float-en.aspl
parse-float-mixed · ASPL 0.5.0

Browser and native

fn ابدأ_الرئيسية() -> ص64 {
    اطبع("first: ").
    let سيئ: نتيجة<f32> = parse_f32(اقرأ_سطر()).
    إذا (سيئ::ok) { أرجع 1. }
    print(سيئ::الخطأ::code).
    print("\nsecond: ").
    دع جيد: result<ع64> = حلل_ع64(read_line()).
    if (جيد::نجاح) {
        إذا (format_f64(0.5) not match "0.5") { return 2. }
        if (نسق_ع32(1.0000000596046448) not match "1.00000012") { أرجع 3. }
        اطبع(نسق_ع64(جيد::value + 1.0)).
        print("\n").
        أرجع 0.
    }
    return 4.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "first: invalid-number\nsecond: 42\n"
native: check 0; success / status 0; stdout "first: invalid-number\nsecond: 42\n"
scripted stdin lines: ["12x","41"]
Download source Open in the editor
aspl check parse-float-mixed.aspl
aspl run parse-float-mixed.aspl

Reasons and outcomes: type-mismatch, argument-count-mismatch; trap / string-index-out-of-bounds, string-slice-out-of-bounds, invalid-unicode-scalar

Host applicability: shared

Normative release limitations

Recoverable results

The type نتيجة<T> / result<T> holds either a successful value of type T or error information. نجاح / success builds success with one argument that infers the payload, or with no arguments for result<unit>, while إخفاق / failure builds failure from a string code and message and needs the expected result type from its declaration, assignment, argument, or return site. Postfix :: reads the نجاح / ok, قيمة / value, and الخطأ / error fields on a result and الرمز / code plus الرسالة / message on معلومات_خطأ / error_info, binds tighter than arithmetic, and never translates user names. Reading the wrong branch traps, reading a result<unit> payload is a compile-time error, and error codes stay stable strings separate from messages.

Accepted: returning success or failure from a function, passing and returning results, and checking the flag before reading the matching branch. Rejected: failure without an expected type, unknown fields, reading the value of a failed result or the error of a success, or comparing two results.

results-ar · ASPL 0.5.0

Browser and native

دالة حي(الاسم: نص) -> نتيجة<نص> {
    إذا (الاسم يطابق "") {
        أرجع إخفاق("empty-name", "name was empty").
    }
    أرجع نجاح("hello " + الاسم).
}
دالة ابدأ_الرئيسية() -> ص64 {
    دع جيد: نتيجة<نص> = حي("aspl").
    إذا (جيد::نجاح) {
        اطبع(جيد::قيمة).
        اطبع(" ").
    } وإلا {
        أرجع 1.
    }
    دع سيئ: نتيجة<نص> = حي("").
    إذا (سيئ::نجاح) {
        أرجع 2.
    }
    اطبع(سيئ::الخطأ::الرمز).
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "hello aspl empty-name"
native: check 0; success / status 0; stdout "hello aspl empty-name"
Download source Open in the editor
aspl check results-ar.aspl
aspl run results-ar.aspl
results-en · ASPL 0.5.0

Browser and native

fn حي(الاسم: string) -> result<string> {
    if (الاسم matches "") {
        return failure("empty-name", "name was empty");
    }
    return success("hello " + الاسم);
}
fn start_main() -> i64 {
    let جيد: result<string> = حي("aspl");
    if (جيد::ok) {
        print(جيد::value);
        print(" ");
    } else {
        return 1;
    }
    let سيئ: result<string> = حي("");
    if (سيئ::ok) {
        return 2;
    }
    print(سيئ::error::code);
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "hello aspl empty-name"
native: check 0; success / status 0; stdout "hello aspl empty-name"
Download source Open in the editor
aspl check results-en.aspl
aspl run results-en.aspl
results-mixed · ASPL 0.5.0

Browser and native

fn greet(name: string) -> نتيجة<string> {
    إذا (name matches "") {
        return إخفاق("empty-name", "name was empty");
    }
    return نجاح("hello " + name);
}
fn ابدأ_الرئيسية() -> i64 {
    دع good: result<string> = greet("aspl").
    if (good::نجاح) {
        اطبع(good::value);
        print(" ");
    } وإلا {
        return 1;
    }
    let bad: نتيجة<string> = greet("");
    إذا (bad::ok) {
        أرجع 2.
    }
    print(bad::الخطأ::code);
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "hello aspl empty-name"
native: check 0; success / status 0; stdout "hello aspl empty-name"
Download source Open in the editor
aspl check results-mixed.aspl
aspl run results-mixed.aspl

Reasons and outcomes: result-type-required, invalid-field, unit-value-not-allowed, type-mismatch; trap / wrong-result-branch

Host applicability: shared

Normative release limitations

Typed lists

Type arguments use < and >; the former square-bracket type syntax is rejected. The type قائمة<T> / list<T> stores a variable number of values of the same type T. Square-bracket literals build their values in written order and allow a trailing comma; a nonempty literal infers its exact element type with no numeric coercion, while an empty literal needs the expected element type from its declaration, assignment, argument, or return site. Elements accept nested lists and the currently storable value types, and reject unit elements and whole-list equality. Indexing [i] reads an element by value starting at zero, and طول / length returns the element count as i64 in constant time. A negative or out-of-range index traps. أضف / append adds one value of the exact element type and returns unit, and indexed assignment xs[i] = v replaces a single element. Both operations require a var root binding, resolve indexes left to right exactly once before the assigned value, and keep copies independent: changing one copy, including inside nested lists, never changes the original. Numeric lists store each reserved i8/u8 slot in one byte, i16/u16 in two, i32/u32/f32 in four, and i64/u64/f64 in eight, with no conversion and no public byte-view promise.

Accepted: empty literals with an expected type, trailing commas, nested lists, passing and returning lists, reading elements and lengths, appending and replacing elements through a var root, and independent copies. Rejected: empty literals without an expected type, mixed element types, unit elements, comparing two lists, negative and out-of-range indexes, or mutation through a let binding, a parameter, or a temporary value.

lists-ar · ASPL 0.5.0

Browser and native

دالة المجموع(القيم: قائمة<ص64>) -> ص64 {
    أرجع القيم[0] + القيم[1] + القيم[2].
}
دالة ابدأ_الرئيسية() -> ص64 {
    دع القيم: قائمة<ص64> = [3, 4, 5].
    إذا (طول(القيم) لا يطابق 3) { أرجع 1. }
    إذا (المجموع(القيم) لا يطابق 12) { أرجع 2. }
    دع بايتات: قائمة<ط8> = [0, 255].
    إذا (طول(بايتات) لا يطابق 2 أو بايتات[0] لا يطابق 0 أو بايتات[1] لا يطابق 255) { أرجع 3. }
    دع كسور: قائمة<ع64> = [0.5].
    إذا (كسور[0] لا يطابق 0.5) { أرجع 4. }
    اطبع("12").
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "12"
native: check 0; success / status 0; stdout "12"
Download source Open in the editor
aspl check lists-ar.aspl
aspl run lists-ar.aspl
lists-en · ASPL 0.5.0

Browser and native

fn المجموع(القيم: list<i64>) -> i64 {
    return القيم[0] + القيم[1] + القيم[2];
}
fn start_main() -> i64 {
    let القيم: list<i64> = [3, 4, 5];
    if (length(القيم) not match 3) { return 1; }
    if (المجموع(القيم) not match 12) { return 2; }
    let بايتات: list<ط8> = [0, 255];
    if (length(بايتات) not match 2 or بايتات[0] not match 0 or بايتات[1] not match 255) { return 3; }
    let كسور: list<f64> = [0.5];
    if (كسور[0] not match 0.5) { return 4; }
    print("12");
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "12"
native: check 0; success / status 0; stdout "12"
Download source Open in the editor
aspl check lists-en.aspl
aspl run lists-en.aspl
lists-mixed · ASPL 0.5.0

Browser and native

fn total(القيم: list<ص64>) -> i64 {
    return القيم[0] + القيم[1] + القيم[2];
}
fn ابدأ_الرئيسية() -> ص64 {
    دع xs: قائمة<i64> = [3, 4, 5].
    if (طول(xs) not match 3) { return 1; }
    إذا (total(xs) not match 12) { أرجع 2. }
    let bytes: قائمة<u8> = [0, 255];
    إذا (length(bytes) not match 2 أو bytes[0] not match 0 أو bytes[1] not match 255) { return 3. }
    let fractions: list<ع64> = [0.5];
    if (fractions[0] not match 0.5) { أرجع 4. }
    print("12");
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "12"
native: check 0; success / status 0; stdout "12"
Download source Open in the editor
aspl check lists-mixed.aspl
aspl run lists-mixed.aspl
list-mutation-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    متغير xs: قائمة<ص64> = [1, 2].
    أضف(xs, 3).
    إذا (طول(xs) لا يطابق 3) { أرجع 1. }
    متغير نسخة: قائمة<ص64> = xs.
    نسخة[0] = 9.
    إذا (xs[0] لا يطابق 1) { أرجع 2. }
    إذا (نسخة[0] لا يطابق 9) { أرجع 3. }
    أضف(xs, xs[0]).
    إذا (طول(xs) لا يطابق 4) { أرجع 4. }
    إذا (xs[3] لا يطابق 1) { أرجع 5. }
    متغير nested: قائمة<قائمة<ص64>> = [[1], [2]].
    دع nested_copy: قائمة<قائمة<ص64>> = nested.
    nested[0][0] = 7.
    إذا (nested_copy[0][0] لا يطابق 1) { أرجع 6. }
    إذا (nested[0][0] لا يطابق 7) { أرجع 7. }
    متغير grown: قائمة<ص64> = [].
    متغير k = 0.
    طالما (k < 32) { أضف(grown, k * 2). k = k + 1. }
    إذا (طول(grown) لا يطابق 32) { أرجع 8. }
    إذا (grown[31] لا يطابق 62) { أرجع 9. }
    grown[0] = grown[31].
    إذا (grown[0] لا يطابق 62) { أرجع 10. }
    متغير بايتات: قائمة<ط8> = [0, 255].
    متغير نسخة_بايتات: قائمة<ط8> = بايتات.
    نسخة_بايتات[0] = 255.
    إذا (بايتات[0] لا يطابق 0 أو نسخة_بايتات[0] لا يطابق 255) { أرجع 11. }
    متغير كسور: قائمة<ع64> = [0.5].
    كسور[0] = 1.5.
    إذا (كسور[0] لا يطابق 1.5) { أرجع 12. }
    اطبع("32").
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "32"
native: check 0; success / status 0; stdout "32"
Download source Open in the editor
aspl check list-mutation-ar.aspl
aspl run list-mutation-ar.aspl
list-mutation-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    var xs: list<i64> = [1, 2];
    append(xs, 3);
    if (length(xs) not match 3) { return 1; }
    var نسخة: list<i64> = xs;
    نسخة[0] = 9;
    if (xs[0] not match 1) { return 2; }
    if (نسخة[0] not match 9) { return 3; }
    append(xs, xs[0]);
    if (length(xs) not match 4) { return 4; }
    if (xs[3] not match 1) { return 5; }
    var nested: list<list<i64>> = [[1], [2]];
    let nested_copy: list<list<i64>> = nested;
    nested[0][0] = 7;
    if (nested_copy[0][0] not match 1) { return 6; }
    if (nested[0][0] not match 7) { return 7; }
    var grown: list<i64> = [];
    var k = 0;
    while (k < 32) { append(grown, k * 2); k = k + 1; }
    if (length(grown) not match 32) { return 8; }
    if (grown[31] not match 62) { return 9; }
    grown[0] = grown[31];
    if (grown[0] not match 62) { return 10; }
    var بايتات: list<ط8> = [0, 255];
    var نسخة_بايتات: list<ط8> = بايتات;
    نسخة_بايتات[0] = 255;
    if (بايتات[0] not match 0 or نسخة_بايتات[0] not match 255) { return 11; }
    var كسور: list<f64> = [0.5];
    كسور[0] = 1.5;
    if (كسور[0] not match 1.5) { return 12; }
    print("32");
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "32"
native: check 0; success / status 0; stdout "32"
Download source Open in the editor
aspl check list-mutation-en.aspl
aspl run list-mutation-en.aspl
list-mutation-mixed · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    متغير xs: list<ص64> = [1, 2];
    append(xs, 3);
    إذا (طول(xs) not match 3) { أرجع 1. }
    var نسخة: قائمة<i64> = xs;
    نسخة[0] = 9;
    if (xs[0] not match 1) { return 2; }
    إذا (نسخة[0] not match 9) { أرجع 3. }
    append(xs, xs[0]);
    if (طول(xs) not match 4) { return 4; }
    إذا (xs[3] not match 1) { أرجع 5. }
    متغير nested: list<قائمة<ص64>> = [[1], [2]];
    let nested_copy: قائمة<list<ص64>> = nested;
    nested[0][0] = 7;
    if (nested_copy[0][0] not match 1) { return 6; }
    إذا (nested[0][0] not match 7) { أرجع 7. }
    var grown: list<i64> = [];
    متغير k = 0;
    while (k < 32) { أضف(grown, k * 2); k = k + 1. }
    if (length(grown) not match 32) { return 8; }
    if (grown[31] not match 62) { return 9; }
    grown[0] = grown[31];
    إذا (grown[0] not match 62) { أرجع 10. }
    var bytes: قائمة<u8> = [0, 255];
    متغير byte_copy: list<ط8> = bytes.
    byte_copy[0] = 255;
    if (bytes[0] not match 0 or byte_copy[0] not match 255) { return 11. }
    var fractions: قائمة<f64> = [0.5];
    fractions[0] = 1.5;
    إذا (fractions[0] not match 1.5) { أرجع 12. }
    print("32");
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "32"
native: check 0; success / status 0; stdout "32"
Download source Open in the editor
aspl check list-mutation-mixed.aspl
aspl run list-mutation-mixed.aspl

Reasons and outcomes: immutable-assignment, invalid-assignment-target, result-type-required, type-mismatch; trap / list-index-out-of-bounds

Host applicability: shared

Normative release limitations

Named records and value semantics

A سجل / record declaration names a nominal type at file scope with a comma-separated field list, a colon between each name and type, and an allowed trailing comma. Names are collected before field types resolve, so definition order does not matter. Records are nominal: two different declarations stay different types even when their fields match. Construction names the record with every field supplied exactly once in written order, and rejects unknown, missing, duplicate, and unit fields. Postfix :: reads fields and chains with list indexes at higher precedence than arithmetic, and never translates user field names. A constructor directly in an if or while condition must be parenthesized so the block-opening brace stays unambiguous.

Accepted: nested records, lists, and results inside fields; passing, returning, and carrying records in successful results; contextual typing of empty lists and failed results inside fields; and updating nested fields and indexes through a var root. Rejected: direct and indirect recursive types through lists or results, whole-record equality, mutation through a let binding, a parameter, a temporary value, or a result projection, and reading a result<unit> payload.

Lists and records copy with value semantics: changing one copy, including a nested field, a list inside a copied record, or a record inside a copied list, never changes the original. Copy-on-write detaches the affected path through shared aggregates before mutating, and unique storage grows geometrically for appends. Assignment targets resolve their indexes left to right exactly once before the assigned value, and an element taken from the same list stays valid during growth.

Runtime ownership generalizes across strings, lists, records, results, and Unicode indexes: literal bytes stay borrowed from the checked program, while owned values are released on register replacement, argument passing, returns, aggregate updates, and frame cleanup. Repeated assignments and loop iterations reclaim replaced values so temporary strings do not accumulate, and live values survive a read_line wait, foreign calls, and returns. The memory budget counts live allocations, backing capacities, payloads, Unicode index caches, and temporaries, and cleanup stays bounded without unbounded C recursion.

records-ar · ASPL 0.5.0

Browser and native

سجل رمز { نوع: ص64, متن: نص, سطر: ص64, عمود: ص64 }
سجل حالة_محلل { رموز: قائمة<رمز>, مؤشر: ص64 }
دالة رمز_الحالة(حالة: حالة_محلل) -> رمز {
    أرجع حالة::رموز[حالة::مؤشر].
}
دالة ابدأ_الرئيسية() -> ص64 {
    دع زائد: رمز = رمز { نوع: 1, متن: "+" , سطر: 2, عمود: 7 }.
    إذا (زائد::نوع لا يطابق 1) { أرجع 1. }
    إذا (زائد::متن لا يطابق "+") { أرجع 2. }
    إذا (زائد::سطر لا يطابق 2) { أرجع 3. }
    إذا (زائد::عمود لا يطابق 7) { أرجع 4. }
    متغير حالة: حالة_محلل = حالة_محلل { رموز: [زائد], مؤشر: 0 }.
    إذا (رمز_الحالة(حالة)::متن لا يطابق "+") { أرجع 5. }
    متغير منقولة: حالة_محلل = حالة.
    منقولة::مؤشر = 1.
    إذا (حالة::مؤشر لا يطابق 0) { أرجع 6. }
    إذا (منقولة::مؤشر لا يطابق 1) { أرجع 7. }
    منقولة::رموز[0]::عمود = 9.
    إذا (حالة::رموز[0]::عمود لا يطابق 7) { أرجع 8. }
    إذا (منقولة::رموز[0]::عمود لا يطابق 9) { أرجع 9. }
    دع موجود: نتيجة<رمز> = نجاح(زائد).
    إذا (موجود::نجاح) {
        إذا (موجود::قيمة::سطر لا يطابق 2) { أرجع 10. }
    } وإلا {
        أرجع 11.
    }
    اطبع("3 tokens").
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "3 tokens"
native: check 0; success / status 0; stdout "3 tokens"
Download source Open in the editor
aspl check records-ar.aspl
aspl run records-ar.aspl
records-en · ASPL 0.5.0

Browser and native

record رمز { نوع: i64, متن: string, سطر: i64, عمود: i64 }
record حالة_محلل { رموز: list<رمز>, مؤشر: i64 }
fn رمز_الحالة(حالة: حالة_محلل) -> رمز {
    return حالة::رموز[حالة::مؤشر];
}
fn start_main() -> i64 {
    let زائد: رمز = رمز { نوع: 1, متن: "+" , سطر: 2, عمود: 7 };
    if (زائد::نوع not match 1) { return 1; }
    if (زائد::متن not match "+") { return 2; }
    if (زائد::سطر not match 2) { return 3; }
    if (زائد::عمود not match 7) { return 4; }
    var حالة: حالة_محلل = حالة_محلل { رموز: [زائد], مؤشر: 0 };
    if (رمز_الحالة(حالة)::متن not match "+") { return 5; }
    var منقولة: حالة_محلل = حالة;
    منقولة::مؤشر = 1;
    if (حالة::مؤشر not match 0) { return 6; }
    if (منقولة::مؤشر not match 1) { return 7; }
    منقولة::رموز[0]::عمود = 9;
    if (حالة::رموز[0]::عمود not match 7) { return 8; }
    if (منقولة::رموز[0]::عمود not match 9) { return 9; }
    let موجود: result<رمز> = success(زائد);
    if (موجود::ok) {
        if (موجود::value::سطر not match 2) { return 10; }
    } else {
        return 11;
    }
    print("3 tokens");
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "3 tokens"
native: check 0; success / status 0; stdout "3 tokens"
Download source Open in the editor
aspl check records-en.aspl
aspl run records-en.aspl
records-mixed · ASPL 0.5.0

Browser and native

record Token { kind: ص64, text: نص, line: ص64, column: i64 }
سجل ParserState { tokens: قائمة<Token>, cursor: ص64 }
fn token_at(state: ParserState) -> Token {
    return state::tokens[state::cursor];
}
fn ابدأ_الرئيسية() -> ص64 {
    دع plus: Token = Token { kind: 1, text: "+", line: 2, column: 7 }.
    if (plus::kind not match 1) { return 1; }
    إذا (plus::text not match "+") { أرجع 2. }
    if (plus::line not match 2) { return 3; }
    إذا (plus::column not match 7) { أرجع 4. }
    var state: ParserState = ParserState { tokens: [plus], cursor: 0 };
    إذا (token_at(state)::text not match "+") { أرجع 5. }
    var moved: ParserState = state.
    moved::cursor = 1.
    if (state::cursor not match 0) { return 6; }
    إذا (moved::cursor not match 1) { أرجع 7. }
    moved::tokens[0]::column = 9.
    if (state::tokens[0]::column not match 7) { return 8; }
    إذا (moved::tokens[0]::column not match 9) { أرجع 9. }
    let found: نتيجة<Token> = success(plus).
    if (found::نجاح) {
        إذا (found::value::line not match 2) { أرجع 10. }
    } وإلا {
        return 11;
    }
    print("3 tokens");
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "3 tokens"
native: check 0; success / status 0; stdout "3 tokens"
Download source Open in the editor
aspl check records-mixed.aspl
aspl run records-mixed.aspl

Reasons and outcomes: immutable-assignment, invalid-assignment-target, invalid-field, result-type-required, type-mismatch, recursive-type; trap / list-index-out-of-bounds, wrong-result-branch

Host applicability: shared

Normative release limitations

Functions

Functions have unique top-level names, typed parameters and a typed result. Calls pass values by value. Definition order does not matter and recursion is allowed. Every path in a non-unit function must return a value. The factorial example returns status 120 without output.

Accepted: calling a later definition or recursing. Rejected: overloading, nested functions, wrong call arity, or a missing return path.

functions-ar · ASPL 0.5.0

Browser and native

دالة مضروب(القيمة: ص64) -> ص64 {
    إذا القيمة <= 1 {
        أرجع 1.
    }
    أرجع القيمة * مضروب(القيمة - 1).
}

دالة ابدأ_الرئيسية() -> ص64 {
    أرجع مضروب(5).
}

Expected outcomes and literal output

browser: check success; success / start_main 120; stdout ""
native: check 0; success / status 120; stdout ""
Download source Open in the editor
aspl check functions-ar.aspl
aspl run functions-ar.aspl
functions-en · ASPL 0.5.0

Browser and native

fn مضروب(القيمة: i64) -> i64 {
    if القيمة <= 1 {
        return 1;
    }
    return القيمة * مضروب(القيمة - 1);
}

fn start_main() -> i64 {
    return مضروب(5);
}

Expected outcomes and literal output

browser: check success; success / start_main 120; stdout ""
native: check 0; success / status 120; stdout ""
Download source Open in the editor
aspl check functions-en.aspl
aspl run functions-en.aspl

Reasons and outcomes: argument-count-mismatch, type-mismatch, missing-return

Host applicability: shared

Normative release limitations

Diagnostics and correction

A diagnostic carries a stable reason key, severity, typed arguments, a primary span, ordered secondary spans, and an optional edit. Language changes wording only. Technical type names, operators, bounds, and values stay full-width ASCII. Warnings do not block execution. Direct execution maps a diagnostic to source. Built programs contain no source map, but report the trapping function name and relative instruction index. The first example assigns an immutable binding. The correction replaces دع / let with متغير / var and normally returns status 1.

Accepted: correct the binding and check again, or branch on a failed parse result. Rejected: treating every nonzero status as a source error or exception. Distinguish a diagnostic, an ASPL trap, a recoverable result, a load failure, and a resource, cancellation, or host outcome.

The example let byte: u8 = 256 is a checking error because the contextual literal is out of range. In contrast, u8(256) has a valid default i64 operand and traps with invalid-numeric-conversion only if reached. parse_u8("256") returns a failed result with code number-out-of-range. None of these outcomes becomes another.

The integer numeric-literal-out-of-range checking diagnostic fields are spelling, type, minimum, maximum. Its floating form has spelling, type, classification, where the classification is finite-overflow. numeric-operator-not-supported has operator, type.

Numeric trap fields are ordered: integer-overflow has type, operation, operand-count, operands; integer-zero-divisor has type, operation, dividend; invalid-shift-count has left-type, count-type, count, width; and invalid-numeric-conversion has source-type, target-type, classification, then source-value or source-bits. Unsigned values through full u64 travel without JavaScript-number rounding.

diagnostic-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    دع قيمة = 0.
    قيمة = 1.
    أرجع قيمة.
}

Expected outcomes and literal output

browser: check source-error; source-error / immutable-assignment; stdout ""
native: check 1; source-error / status 1 / immutable-assignment; stdout ""
Download source Open in the editor
aspl check diagnostic-ar.aspl
diagnostic-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    let قيمة = 0;
    قيمة = 1;
    return قيمة;
}

Expected outcomes and literal output

browser: check source-error; source-error / immutable-assignment; stdout ""
native: check 1; source-error / status 1 / immutable-assignment; stdout ""
Download source Open in the editor
aspl check diagnostic-en.aspl
corrected-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    متغير قيمة = 0.
    قيمة = 1.
    أرجع قيمة.
}

Expected outcomes and literal output

browser: check success; success / start_main 1; stdout ""
native: check 0; success / status 1; stdout ""
Download source Open in the editor
aspl check corrected-ar.aspl
aspl run corrected-ar.aspl
corrected-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    var قيمة = 0;
    قيمة = 1;
    return قيمة;
}

Expected outcomes and literal output

browser: check success; success / start_main 1; stdout ""
native: check 0; success / status 1; stdout ""
Download source Open in the editor
aspl check corrected-en.aspl
aspl run corrected-en.aspl

Reasons and outcomes: source-error / immutable-assignment, numeric-literal-out-of-range; trap / integer-overflow, integer-zero-divisor, invalid-shift-count, invalid-numeric-conversion; result / invalid-number, number-out-of-range; load-failure / invalid-bytecode; limit-stop, cancelled, host-failure

Host applicability: shared

Normative release limitations

Safe output

The output builtin is اطبع / print: (string) -> unit. It writes string bytes in order, including NUL, without an automatic newline or flush. Add \n explicitly. Neither alias can be redefined. The browser safely displays output bytes without interpreting them as page markup.

Accepted: one string, including an empty string. Rejected: a number, multiple arguments, or storing the result.

Writing is synchronous; an empty string does not touch the host. Native output retries interrupted writes and continues short writes. Output accepted before failure remains visible. There is no special SIGPIPE handler; a closed pipe may terminate the process through that signal. If the environment ignores or blocks it and writing returns EPIPE, the result is a host failure with status 8.

output-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    اطبع("مرحبا\n").
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "مرحبا\n"
native: check 0; success / status 0; stdout "مرحبا\n"
Download source Open in the editor
aspl check output-ar.aspl
aspl run output-ar.aspl
output-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    print("مرحبا\n");
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "مرحبا\n"
native: check 0; success / status 0; stdout "مرحبا\n"
Download source Open in the editor
aspl check output-en.aspl
aspl run output-en.aspl

Reasons and outcomes: type-mismatch, argument-count-mismatch; host-failure / host-operation-failed / write-program-output; limit-stop / output-limit

Host applicability: shared

Normative release limitations

Line input

The builtin اقرأ_سطر / read_line: () -> string reads one line. It takes neither arguments nor an غير_آمن / unsafe marker, and neither name may be defined. Print a prompt before the call because the builtin writes no prompt, echo, or terminator. A line ends in LF or CRLF, which are removed. An empty line produces an empty string. A final unterminated line is returned once at EOF, then the next call traps with input-exhausted.

Accepted: pass, return, compare, print, measure, index, slice, concatenate, or explicitly parse the read string with a numeric parser. Rejected: treating source notation or Arabic-Indic digits as accepted numeric input, or implicitly converting a string to a number.

The runtime validates the complete line as strict UTF-8. Whitespace, NUL, Arabic marks, direction controls, Arabic-Indic digits, and normalization form stay exactly as the host supplied them. Program input does not pass through the source editor, lexer, or digit conversion. Invalid input traps with invalid-input-utf8 and the first invalid byte offset.

Both hosts allow 65536 payload bytes per line, excluding LF or CRLF. Exactly that size is accepted. A larger line ends the run with input-line-limit, never a truncated string. Cancelling while waiting is cancellation, not EOF.

The execution owns each successful nonempty input string under shared runtime ownership: literal bytes stay borrowed from the compiled program without copying, while registers, parameters, and returns carry the same immutable bytes across calls and returns. Replacing a binding or cleaning up a frame reclaims the discarded string, so the VM memory limit counts only live strings.

input-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    اطبع("ما اسمك؟ ").
    دع الاسم = اقرأ_سطر().
    اطبع("مرحبا ").
    اطبع(الاسم).
    اطبع("\n").
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "ما اسمك؟ مرحبا ليلى\n"
native: check 0; success / status 0; stdout "ما اسمك؟ مرحبا ليلى\n"
scripted stdin lines: ["ليلى"]
Download source Open in the editor
aspl check input-ar.aspl
aspl run input-ar.aspl
input-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    print("ما اسمك؟ ");
    let الاسم = read_line();
    print("مرحبا ");
    print(الاسم);
    print("\n");
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "ما اسمك؟ مرحبا Mina\n"
native: check 0; success / status 0; stdout "ما اسمك؟ مرحبا Mina\n"
scripted stdin lines: ["Mina"]
Download source Open in the editor
aspl check input-en.aspl
aspl run input-en.aspl
input-mixed · ASPL 0.5.0

Browser and native

fn مرر(value: string) -> string {
    return value;
}

fn start_main() -> i64 {
    print("first: ");
    var first = اقرأ_سطر();
    let kept = first.
    let returned = مرر(first).
    اطبع("second: ").
    let second = read_line().
    first = second.
    إذا returned matches kept {
        print("equal: ");
        print(returned).
        اطبع(" / ").
        print(kept).
        اطبع("\n").
        return 0.
    }
    أرجع 1.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "first: second: equal: ١٢٣ / ١٢٣\n"
native: check 0; success / status 0; stdout "first: second: equal: ١٢٣ / ١٢٣\n"
scripted stdin lines: ["١٢٣","١٢٣"]
Download source Open in the editor
aspl check input-mixed.aspl
aspl run input-mixed.aspl

Reasons and outcomes: argument-count-mismatch, unsafe-on-safe-call; trap / input-exhausted, invalid-input-utf8; limit-stop / input-line-limit; cancelled

Host applicability: shared

Normative release limitations

Linux commands and phases

The tool accepts one source file. check validates source, run executes in-process, and build atomically publishes a validated ELF program. --diagnostic-language=ar|en selects diagnostic wording only. Program output stays on stdout, while diagnostics and traps use stderr. Check and build do not open program libraries. Building invokes no C compiler or linker. Built programs run independently of the tool installation.

Accepted: diagnostic options before the command and one source path after it. Rejected: multiple sources, public bytecode output, or program arguments. Use -- before a path starting with a dash.

Reasons and outcomes: 0 success; 1 source-error; 2 usage-error; 3 policy-rejection; 4 load-failure; 5 trap; 6 limit-stop; 7 cancelled; 8 host-failure; 9 internal-failure

Host applicability: native

aspl --diagnostic-language=en check hello.aspl
aspl run hello.aspl
aspl build -o hello hello.aspl
./hello
Read and check the example Normative release limitations

Linux input and built programs

The aspl run command reads inherited stdin from a terminal, pipe, or redirected file. A program built by aspl build uses the same reader and is an ELF. It contains private bytecode version 4 and its VM, so it runs after the compiler and runtime are removed from PATH.

A prompt printed by ASPL is visible before the wait, even without a newline. The reader removes only that line's terminator and does not read into the next line, leaving later bytes for a foreign function that reads stdin. A signal or stop request while waiting never turns into input-exhausted.

Host applicability: native

printf 'Mina\n' | aspl run input.en.aspl
aspl build -o input input.en.aspl
printf 'Mina\n' | ./input
Normative release limitations

Text file reading and writing

The builtin اقرأ_ملف_نصي / read_text_file: (string) -> result<string> reads a whole file as strict UTF-8, and the builtin اكتب_ملف_نصي / write_text_file: (string, string) -> result<unit> writes the supplied UTF-8 bytes exactly, without appending a newline. Neither takes an غير_آمن / unsafe marker, and none of their names may be defined. Relative paths resolve against the process working directory, with no shell expansion and no implicit directory creation. Empty files succeed with an empty string, and content bytes are preserved exactly including BOM, line endings, NUL, and normalization.

Accepted: reading a filename from line input, then checking the flag and reading the matching branch; and writing a relative output after reading its path from input. Rejected: empty paths, shell expansion, reading a directory, device, or pipe as a whole file, or implicitly creating directories when writing.

The native host reads regular files only, including a symbolic link resolving to a regular file, with a default 16 MiB per-file limit. Oversized reads fail with file-too-large while collecting, never after unbounded allocation. Empty or NUL-containing paths return invalid-path, nonregular inputs return not-regular-file, and malformed UTF-8 bytes return invalid-utf8.

The browser uses one virtual-file collection for imported and generated files. Names are exact, case-sensitive UTF-8 names up to 255 bytes, with no slashes, backslashes, or control characters, and not dot or double-dot. A successful write atomically replaces the map entry and a later read in the same run sees the new bytes. The default limits are 1 MiB per file, 64 files, and 8 MiB of contents. Each run also has an 8 MiB update-transfer budget that charges filename bytes, content bytes, and 128 bytes for every message, including an empty write. A quota failure returns virtual-file-limit and keeps the prior bytes. A missing read returns not-found, malformed UTF-8 returns invalid-utf8, and an oversized file returns file-too-large. Files stay in page memory across runs and interface-language changes, clear on refresh, and are never uploaded or persistently stored.

Native writing succeeds on empty content and enforces the 16 MiB per-file limit before publication without creating any file. Output is staged in a temporary file inside the destination directory, then published with an atomic rename that replaces the final directory entry, including a final symlink, without following it. Failure before publication preserves the previous destination and removes the temporary file; no cross-file transactions or crash durability are promised. Cancellation before publication keeps the old contents, and cancellation after a successful publication does not roll the write back.

Failure codes are stable: invalid-path for an invalid virtual path, not-found for a missing file, permission-denied for permission failures, virtual-file-limit for browser quotas, and io-error for other I/O failures. unsupported-host applies only to a contributor host with no file adapter. Memory exhaustion, allocation failure, and cancellation remain execution outcomes rather than recoverable results. Check and build validate the call without reading a source file or writing output.

The miniature arithmetic language at docs/examples/mini-arith/mini-arith.aspl is the integrated walkthrough: it asks for two input lines, the source filename and the operation (interpret or generate), and for generation a third line with the output filename. Interpreting demo.txt, which declares i, مجموع, and limit and sums 1 through 10 in a while loop with an if branch, prints File: Operation: 55. Generation writes valid ASPL source through write_text_file only after successful parsing, and the generated file then checks, runs, and builds through the ordinary toolchain with output matching the interpreter. Malformed source fails before any output is published, and a failed output preserves the previous destination. In the browser, import demo.txt through the file list, answer the same prompts, and the generated text appears as a virtual file ready to download; the browser does not compile that generated text within the same run. The desktop console runs the same example from the selected source file's working directory with the usual line input.

read-file-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    اطبع("File: ").
    دع الاسم = اقرأ_سطر().
    دع المحتوى: نتيجة<نص> = اقرأ_ملف_نصي(الاسم).
    إذا (المحتوى::نجاح) {
        اطبع(المحتوى::قيمة).
    } وإلا {
        اطبع("error: ").
        اطبع(المحتوى::الخطأ::الرمز).
        اطبع("\n").
    }
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "File: error: not-found\n"
native: check 0; success / status 0; stdout "File: error: not-found\n"
scripted stdin lines: ["missing.txt"]
Download source Open in the editor
aspl check read-file-ar.aspl
aspl run read-file-ar.aspl
read-file-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    print("File: ");
    let الاسم = read_line();
    let المحتوى: result<string> = read_text_file(الاسم);
    if (المحتوى::ok) {
        print(المحتوى::value);
    } else {
        print("error: ");
        print(المحتوى::error::code);
        print("\n");
    }
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "File: error: not-found\n"
native: check 0; success / status 0; stdout "File: error: not-found\n"
scripted stdin lines: ["missing.txt"]
Download source Open in the editor
aspl check read-file-en.aspl
aspl run read-file-en.aspl
write-file-ar · ASPL 0.5.0

Browser and native

دالة ابدأ_الرئيسية() -> ص64 {
    اطبع("Output: ").
    دع المحفوظ: نتيجة<وحدة> = اكتب_ملف_نصي("generated.txt", "generated\n").
    إذا (المحفوظ::نجاح) {
        اطبع("saved\n").
    } وإلا {
        اطبع("error: ").
        اطبع(المحفوظ::الخطأ::الرمز).
        اطبع("\n").
    }
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "Output: saved\n"
native: check 0; success / status 0; stdout "Output: saved\n"
Download source Open in the editor
aspl check write-file-ar.aspl
aspl run write-file-ar.aspl
write-file-en · ASPL 0.5.0

Browser and native

fn start_main() -> i64 {
    print("Output: ");
    let المحفوظ: result<unit> = write_text_file("generated.txt", "generated\n");
    if (المحفوظ::ok) {
        print("saved\n");
    } else {
        print("error: ");
        print(المحفوظ::error::code);
        print("\n");
    }
    return 0;
}

Expected outcomes and literal output

browser: check success; success / start_main 0; stdout "Output: saved\n"
native: check 0; success / status 0; stdout "Output: saved\n"
Download source Open in the editor
aspl check write-file-en.aspl
aspl run write-file-en.aspl

Reasons and outcomes: argument-count-mismatch, unsafe-on-safe-call, type-mismatch; result / invalid-path, not-found, permission-denied, not-regular-file, invalid-utf8, file-too-large, io-error, virtual-file-limit, unsupported-host

Host applicability: native

printf 'hello\n' > hello.txt
printf 'hello.txt\n' | aspl run read-file.en.aspl
aspl build -o read-file read-file.en.aspl
printf 'hello.txt\n' | ./read-file
printf '\n' | aspl run write-file.en.aspl
printf 'docs/examples/mini-arith/demo.txt\ninterpret\n' | aspl run docs/examples/mini-arith/mini-arith.aspl
printf 'docs/examples/mini-arith/demo.txt\ngenerate\n/tmp/demo-generated.aspl\n' | aspl run docs/examples/mini-arith/mini-arith.aspl
aspl check /tmp/demo-generated.aspl
aspl run /tmp/demo-generated.aspl
aspl build -o /tmp/demo-generated /tmp/demo-generated.aspl
/tmp/demo-generated
Normative release limitations

Playground input in the browser

When a program reaches read_line, the playground shows a waiting state, a one-line field, and Send, Close input, and Stop. Send sends the current draft only for the displayed request and clears it after the worker acknowledges it. Close input sends EOF without sending the draft, which remains visibly unsent. Stop cancels the run and is not EOF.

The field rejects multiline paste and CR or LF, and shows the byte limit. Draft bytes and digits stay as entered and do not pass through the source editor. Input echoes are separate interface records, not program output or part of its output limit.

The file list shows filenames and byte sizes with import, download, remove, and clear actions. Import reads local files without uploading them to a server, while a program can replace a generated file without a confirmation dialog. The page accepts file updates only from the active job, and updates accepted before a trap or Stop remain downloadable. Download starts from an explicit user action and the temporary object URL is revoked afterward. Import confirms replacing an existing name and clearing the collection, and disables user changes while a run is active with a per-run snapshot. Files persist across reruns and interface-language changes in page memory only.

The execution limit measures accumulated active time only. Time spent waiting for input does not consume it. Auto, LTR, and RTL keep output bytes, the draft, source snapshot, and request identity, changing display direction and alignment only.

Host applicability: browser

Normative release limitations

Host and execution limits

The browser runs bytecode locally and applies a ceiling of 10000000 instructions per run. The following loop ends with limit-stop at that ceiling. The table lists both host limits. Units are MiB = 1048576 bytes and KiB = 1024 bytes. Here none means no product ceiling and n/a means not applicable.

Accepted: running the common language in the browser. Rejected: a foreign import even if unused. Do not send the infinite-loop example to native execution.

Fixed resource ceilings
Resource Native Browser
Source bytes16 MiB1 MiB
Lexical items1048576131072
Syntax nodes1048576131072
Syntactic nesting256128
Compiler working memory512 MiB128 MiB
Bytecode bytes64 MiB8 MiB
Functions655364096
Foreign imports40960
Integer constants1048576131072
Float constants1048576131072
String references1048576131072
String bytes16 MiB2 MiB
Input-line payload65536 bytes65536 bytes
Bytecode instructions4194304524288
Registers per function655368192
Executed instructionsnone10000000
Runtime frames4096512
Runtime value slots1048576131072
VM-owned execution memory256 MiB64 MiB
Captured outputnone256 KiB
Check wall timenone2 s
Run wall timenone3 s
WebAssembly linear memoryn/a256 MiB
Concurrent worker jobsn/a1

Source includes every byte read, including a leading byte-order mark. Compiler memory includes all live compilation allocations. Execution memory includes frames, slots, C-string loans, and live execution-owned strings, excluding immutable program storage, libraries, and foreign allocations. A structural ceiling wins over a memory ceiling at the same operation. Allocation failure below the ceiling is host-failure / allocation-failed.

The check clock starts when the loaded worker accepts the job; the run clock starts when it accepts execution after a successful check. Loading counts against neither clock, and waiting for user input does not count against the run clock. The first observed ceiling determines the outcome; a deadline terminates the worker with time-limit. The output ceiling rejects the entire crossing write and retains prior output as partial. Native execution has no product instruction, time, or output ceiling, subject to the instruction counter's representational maximum.

Development ASPL 0.5.0 uses private bytecode format 5 and browser-result wire version 3. Current builds reject every other bytecode version. The format is not a public compatibility interface.

limit-ar · ASPL 0.5.0

Browser only

دالة ابدأ_الرئيسية() -> ص64 {
    طالما صواب {}
    أرجع 0.
}

Expected outcomes and literal output

browser: check success; limit-stop / execution-instruction-limit / ceiling 10000000; stdout ""
Download source Open in the editor
limit-en · ASPL 0.5.0

Browser only

fn start_main() -> i64 {
    while true {}
    return 0;
}

Expected outcomes and literal output

browser: check success; limit-stop / execution-instruction-limit / ceiling 10000000; stdout ""
Download source Open in the editor

Reasons and outcomes: policy-rejection / foreign-imports-not-supported; limit-stop / execution-instruction-limit

Host applicability: browser

Normative release limitations

Normative limitations

These are limitations from the archived 0.1.1 conformance manifest. Each identifier links to its owning reference text; they do not describe ASPL 0.5.0 input features.

ASPL-SEMANTIC-0403
The ASPL MVP has five storable types; strings are immutable and originate only from literals.
ASPL-SEMANTIC-0404
The ASPL MVP has five storable types; strings are immutable and originate only from literals.
ASPL-SEMANTIC-0405
The ASPL MVP has five storable types; strings are immutable and originate only from literals.
ASPL-SEMANTIC-0406
The ASPL MVP has five storable types; strings are immutable and originate only from literals.
ASPL-SEMANTIC-0407
The ASPL MVP has five storable types; strings are immutable and originate only from literals.
ASPL-SEMANTIC-0189
The ASPL MVP accepts one source file and has no modules, package system, or program arguments.
ASPL-BYTECODE-0531
ASPL bytecode is private and version-matched, not a stable public VM ABI.
ASPL-BYTECODE-0532
ASPL bytecode is private and version-matched, not a stable public VM ABI.
ASPL-BYTECODE-0533
ASPL bytecode is private and version-matched, not a stable public VM ABI.
ASPL-BYTECODE-0534
ASPL bytecode is private and version-matched, not a stable public VM ABI.
ASPL-BYTECODE-0535
ASPL bytecode is private and version-matched, not a stable public VM ABI.
ASPL-CLI-0605
Native execution does not sandbox unsafe foreign code.
ASPL-CLI-0606
Native execution does not sandbox unsafe foreign code.
ASPL-CLI-0607
Native execution does not sandbox unsafe foreign code.
ASPL-CLI-0608
Native execution does not sandbox unsafe foreign code.
ASPL-BROWSER-0347
The browser output builtin creates no foreign import.
ASPL-BROWSER-0348
The browser output builtin adds no filesystem bridge.
ASPL-BROWSER-0349
The browser output builtin adds no network bridge.
ASPL-BROWSER-0350
The browser output builtin adds no server bridge.
ASPL-DIST-0109
The first native target is x86-64 Linux with glibc 2.34 or later.
ASPL-DIST-0144
SHA-256 provides integrity only, without publisher authentication or release signing.
ASPL-PERF-0161
The build and browser performance claims apply only to the specified host, protocol, and pinned browsers.
ASPL-CONFORMANCE-0672
The ASPL MVP makes no production-readiness claim.
ASPL-CONFORMANCE-0673
The ASPL MVP makes no full-C-replacement claim.
ASPL-CONFORMANCE-0674
The ASPL MVP promises no security-support duration.
ASPL-CONFORMANCE-0675
The ASPL MVP makes no stable-public-bytecode claim.

Understand the limits of C

C signatures, Buffer and C-string loans

Development 0.5.0 adds exact fixed signatures through c / سي, fixed-width scalars and copied Buffer / مخزن, while retaining the original adapters. Read the separate C guide: English / العربية for checked examples, shared ownership and reviewed managed callbacks. Ordinary C declarations/calls remain unsafe, synchronous and excluded from HTTP handler paths. The callback demonstration is contributor-only and refused by the production tool.

Accepted: nonempty literal library and symbol names without NUL, with both unsafe markers. Rejected: duplicate library/symbol pairs, mismatched signatures, or a missing marker.

Adapter سي_صحيح__مؤشر_محرف_ثابت / c_int__const_char_ptr maps (string) -> i64 to int (*)(const char *). Before entering C, it rejects a string containing NUL, copies the bytes and appends the terminator. The loan ends when the function returns. C may read only during the call and may neither modify nor retain the pointer. The int result converts by value; negative values remain ordinary data.

Adapter سي_مزدوج__مزدوج / c_double__double maps (f64) -> f64 to double (*)(double). It passes binary64 values, canonicalizes returned NaN and restores the floating-point environment. Neither adapter inspects errno, exception flags or library error conventions.

The commands check and build validate declarations without opening libraries. Execution prepares every import before the entry function, ordered by library bytes, symbol bytes, then adapter ID. Each name opens once with RTLD_NOW | RTLD_LOCAL, followed by lookup using dlsym and dlerror. Names pass unchanged under the glibc loader rules. The first failure prevents entry and closes opened handles in reverse order.

For puts, download the source, check it, then run on the native host. The library function adds the newline. Check a negative result yourself and do not use its unspecified positive value as the process status. Loan allocation failure is a host failure; foreign crashes or retention of the pointer are outside the trap guarantees.

puts-ar · ASPL 0.5.0

Native only

Native only. The browser rejects this import with policy-rejection / foreign-imports-not-supported before execution, even if unused.

غير_آمن خارجي اطبع_سطر(رسالة: نص) -> ص64
    = سي_صحيح__مؤشر_محرف_ثابت("libc.so.6", "puts").

دالة ابدأ_الرئيسية() -> ص64 {
    دع النتيجة = غير_آمن اطبع_سطر("مرحبا").
    إذا النتيجة < 0 { أرجع 1. }
    أرجع 0.
}

Expected outcomes and literal output

browser: check policy-rejection; policy-rejection / foreign-imports-not-supported; stdout ""
native: check 0; success / status 0; stdout "مرحبا\n"
Download source Check browser rejection
aspl check puts-ar.aspl
aspl run puts-ar.aspl
puts-en · ASPL 0.5.0

Native only

Native only. The browser rejects this import with policy-rejection / foreign-imports-not-supported before execution, even if unused.

unsafe foreign اطبع_سطر(رسالة: string) -> i64
    = c_int__const_char_ptr("libc.so.6", "puts");

fn start_main() -> i64 {
    let النتيجة = unsafe اطبع_سطر("مرحبا");
    if النتيجة < 0 { return 1; }
    return 0;
}

Expected outcomes and literal output

browser: check policy-rejection; policy-rejection / foreign-imports-not-supported; stdout ""
native: check 0; success / status 0; stdout "مرحبا\n"
Download source Check browser rejection
aspl check puts-en.aspl
aspl run puts-en.aspl
double-ar · ASPL 0.5.0

Native only

Native only. The browser rejects this import with policy-rejection / foreign-imports-not-supported before execution, even if unused.

غير_آمن خارجي جذر(قيمة: ع64) -> ع64
    = سي_مزدوج__مزدوج("libm.so.6", "sqrt").

دالة ابدأ_الرئيسية() -> ص64 {
    دع النتيجة = غير_آمن جذر(4.0).
    إذا النتيجة تطابق 2.0 { أرجع 0. }
    أرجع 1.
}

Expected outcomes and literal output

browser: check policy-rejection; policy-rejection / foreign-imports-not-supported; stdout ""
native: check 0; success / status 0; stdout ""
Download source Check browser rejection
aspl check double-ar.aspl
aspl run double-ar.aspl
double-en · ASPL 0.5.0

Native only

Native only. The browser rejects this import with policy-rejection / foreign-imports-not-supported before execution, even if unused.

unsafe foreign جذر(قيمة: f64) -> f64
    = c_double__double("libm.so.6", "sqrt");

fn start_main() -> i64 {
    let النتيجة = unsafe جذر(4.0);
    if النتيجة matches 2.0 { return 0; }
    return 1;
}

Expected outcomes and literal output

browser: check policy-rejection; policy-rejection / foreign-imports-not-supported; stdout ""
native: check 0; success / status 0; stdout ""
Download source Check browser rejection
aspl check double-en.aspl
aspl run double-en.aspl

Reasons and outcomes: unknown-foreign-adapter, foreign-signature-mismatch, invalid-foreign-library-name, invalid-foreign-symbol-name, duplicate-foreign-target, unsafe-required-on-foreign-declaration, unsafe-required-on-foreign-call; load-failure / foreign-library-open-failed, foreign-symbol-lookup-failed; trap / foreign-string-contains-nul; host-failure / allocation-failed; policy-rejection / foreign-imports-not-supported

Host applicability: native

Normative release limitations

Move to Linux

Check the host first

The target is baseline Linux x86-64 with glibc 2.34 or later. Results must be Linux, x86_64 and glibc 2.34 or later. Failure to identify GNU libc does not establish compatibility. See the normative host limitations.

uname -s
uname -m
getconf GNU_LIBC_VERSION
Normative release limitations

Archive and verification

The current ASPL release is 0.5.0. Download the Linux x86-64 archive and its checksum record, then verify them before extraction. This is a published project release and does not claim complete official ASPL MVP conformance.

The archive contains aspl, DEPENDENCIES.json, LICENSE-MIT, LICENSE-APACHE and THIRD-PARTY-NOTICES. The same dependency manifest is available alongside the download. Licensing is a choice of MIT OR Apache-2.0.

Download the 0.5.0 archive and checksum into the same directory. The checksum file has one line with 64 lowercase hex digits, two spaces, the filename and a newline. Verification must report aspl-0.5.0-x86_64-linux-gnu.tar.xz: OK before extraction. The checksum checks integrity and does not prove publisher identity.

This archive includes notices for Unicode, libffi and the private HTTP dependencies. Read the complete texts: MIT, Apache-2.0, and third-party notices.

Use a fresh download directory for each version. Inspect the listing before extraction; it must match the directory, files and modes described here. Stop if any command fails or the listing or version differs, and do not continue to the install commands.

ASPL 0.5.0 includes native HTTP and uses private bytecode format 5. Rebuild older bytecode from source. The bytecode format is internal, not a public compatibility interface.

sha256sum --check SHA256SUMS &&
tar -tvJf aspl-0.5.0-x86_64-linux-gnu.tar.xz

tar -xJf aspl-0.5.0-x86_64-linux-gnu.tar.xz &&
./aspl-0.5.0-x86_64-linux-gnu/aspl --version
Normative release limitations

Install the tool and verify PATH

After verification, put the extracted ASPL 0.5.0 tool on your path. It must print aspl 0.5.0. The optional desktop Console is a separate download.

The command command -v aspl must resolve to $HOME/.local/bin/aspl. Otherwise use export PATH="$HOME/.local/bin:$PATH" in the current shell. To persist it, manually add that line to ~/.bashrc for Bash or ~/.zshrc for Zsh. For Fish, use fish_add_path "$HOME/.local/bin". Open a new shell and check the path and version again.

For an administrator-managed installation, after the same check use sudo install -m 0755 ./build/aspl /usr/local/bin/aspl. Check the resolved path so an older copy does not mask the selected tool.

Download ASPL Console 0.5.0 and its separate checksum. It uses system Qt 6.11 or later, desktop platform plugins and an Arabic-capable font. On current Arch/Omarchy install qt6-base qt6-wayland noto-fonts. Read the runtime and installation instructions. The --aspl option selects the tool. Choose Run to start the selected source file.

test "$(./aspl-0.5.0-x86_64-linux-gnu/aspl --version)" = "aspl 0.5.0" &&
install -d "$HOME/.local/bin" &&
install -m 0755 ./aspl-0.5.0-x86_64-linux-gnu/aspl "$HOME/.local/bin/aspl"
command -v aspl
aspl --version
sha256sum --check SHA256SUMS &&
tar -xJf aspl-console-0.5.0-linux-x86_64.tar.xz &&
./aspl-console-0.5.0-linux-x86_64/bin/aspl-console --aspl "$HOME/.local/bin/aspl" hello.aspl
Normative release limitations

Upgrade, rollback and uninstall

To upgrade, repeat the host check, download, verification, extraction and extracted-version check for the new release, then replace the tool with the same install command. To roll back, follow those steps with a chosen archived version and its checksum. Published versions are immutable. There is no automatic backup; retain archives for offline rollback. Only the newest release receives fixes before 1.0.

Uninstall removes only the selected executable, leaving shell configuration, source, built programs and archives. Remove only the path you selected.

After removal, run command -v aspl to detect another installed copy on your path.

rm -- "$HOME/.local/bin/aspl"

For the administrator-managed location only: sudo rm -- /usr/local/bin/aspl

Normative release limitations
Return to the editor