Exact numeric family
ASPL 0.7.0 · Current release
Widths, ranges, literals, operations, checked conversions, and numeric text.
On this page
Types and ranges
| Arabic alias | English alias | Minimum | Maximum |
|---|---|---|---|
ص8 |
i8 |
-128 |
127 |
ص16 |
i16 |
-32768 |
32767 |
ص32 |
i32 |
-2147483648 |
2147483647 |
ص64 |
i64 |
-9223372036854775808 |
9223372036854775807 |
ط8 |
u8 |
0 |
255 |
ط16 |
u16 |
0 |
65535 |
ط32 |
u32 |
0 |
4294967295 |
ط64 |
u64 |
0 |
18446744073709551615 |
ع32 / f32 is IEEE 754 binary32; ع64 / f64 is binary64. Each alias pair names one exact type. These names and numeric parse/format names cannot be redefined.
Source literals
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.
A decimal float has a fraction with digits on both sides of . or an e/E exponent with an optional sign and at least one digit. 1e2 and 1.0e-2 are valid; .5 is not. A source sign is a unary operator, not part of the literal token. Radix alphabets cannot mix inside one token. All numeric digits are ASCII even with Arabic prefixes.
Literal context and precedence
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.
Integer operations
Addition, subtraction, multiplication, and division need one matching type and return it. % is integer-only. Addition, subtraction, multiplication, and signed-integer negation trap with integer-overflow rather than wrapping. Unary minus on an already typed unsigned integer is rejected during checking with numeric-operator-not-supported. 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.
Floating operations and explicit conversion
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.
Parsing and formatting
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 an optional ASCII sign, digits, an optional fraction with following digits, and an optional e/E exponent with an optional ASCII sign and 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.
Numeric storage
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.
Release scope and related reading
The archived 0.4.0 numeric extension added ten widths, hexadecimal and binary literals, bitwise operations, and per-type text conversion. Its numeric rules remain in 0.7.0, but current private bytecode is version 7, not 4. The browser-result wire is 3. Bytecode is not a public compatibility interface. This page does not rewrite the MVP record that specified only i64 and f64.
Success and intentional failures
Execution: Browser and native · ASPL 0.7.0
- No prior knowledge is required to open and check it.
Input: No input lines are required.
fn start_main() -> i64 {
let maximum: u64 = 18446744073709551615;
let direct: f32 = 1.0000000596046448;
let bits: u8 = 0xff;
let converted: u8 = u8(255);
if (format_u64(maximum) not match "18446744073709551615") { return 1; }
if (format_f32(direct) not match "1.00000012") { return 2; }
if ((bits & 0x0f) not match 15 or (bits >> 4) not match 15 or converted not match 255) { return 3; }
var bytes: list<u8> = [0, 255];
var copy: list<u8> = bytes;
copy[0] = bits << 0;
if (bytes[0] not match 0 or copy[0] not match 255) { return 4; }
print("numeric types\n");
return 0;
}
Expected outcomes
{
"browser": {
"check": "success",
"class": "success",
"output": "numeric types\n",
"processStatus": 0
},
"native": {
"check": 0,
"status": 0,
"output": "numeric types\n"
}
}Execution: Browser and native · ASPL 0.7.0
- No prior knowledge is required to open and check it.
Input: No input lines are required.
fn start_main() -> i64 {
let byte: u8 = 256;
return 0;
}
Expected outcomes
{
"browser": {
"check": "source-error",
"class": "source-error",
"output": "",
"reason": "numeric-literal-out-of-range"
},
"native": {
"check": 1,
"status": 1,
"output": "",
"reason": "numeric-literal-out-of-range"
}
}Execution: Browser and native · ASPL 0.7.0
- No prior knowledge is required to open and check it.
Input: No input lines are required.
fn start_main() -> i64 {
let byte: u8 = u8(256);
print(format_u8(byte));
return 0;
}
Expected outcomes
{
"browser": {
"check": "success",
"class": "trap",
"reason": "invalid-numeric-conversion",
"output": ""
},
"native": {
"check": 0,
"status": 5,
"reason": "invalid-numeric-conversion",
"output": ""
}
}Diagnostic fields explain literal rejection versus conversion traps.
Read the complete families: