Choose the MVP builtin environment

Archived MVP specification. For ASPL 0.7.0, see the current reference and native HTTP guide.

Type: grilling Status: resolved Blocked by: 05, 09 Parent: Find the ASPL MVP specification

Question

Does the MVP need any built-in functions, constants, or automatically available prelude names beyond its syntax, operators, entry function, and two foreign adapter profiles? If so, what exact names, types, semantics, Arabic and English spellings, namespace rules, and native and browser availability belong in the implementation-ready specification?

Answer

The MVP builtin environment contains one language-owned output callable and nothing else. Its canonical Arabic name is اطبع; print is its exact English alias. Both spellings resolve to one builtin with type (string) -> unit on native Linux and in the browser playground.

There are no builtin constants, overloads, numeric output functions, automatically imported modules, general prelude names, or user-extensible builtin registry.

Source names and checking

اطبع and print remain identifier tokens rather than lexer keywords. Before collecting source declarations, the checker inserts one builtin target into the callable namespace and associates both normalized spellings with it. Calls through either spelling have the same checked target identity and produce byte-identical bytecode.

The aliases are language-owned names:

An ordinary call has exactly one string argument and returns unit. It is valid only as a call statement. Existing argument-count-mismatch, type-mismatch, and unit-value-not-allowed diagnostics cover wrong arity, a non-string argument, and an attempt to use the result as a value.

The builtin is safe. Prefixing its call with غير_آمن or unsafe produces unsafe-on-safe-call and a machine-applicable edit that removes the marker. The same reason replaces unsafe-on-aspl-call for user-defined ASPL function calls.

The formatter preserves the written builtin alias. An explicit vocabulary-conversion action may rewrite اطبع and print only where name resolution identifies this builtin; it never rewrites an unrelated identifier, string, comment, path, or C symbol.

Output semantics

One successful call writes the string's exact UTF-8 bytes in execution order. It adds no newline, terminator, prefix, or formatting. The empty string succeeds without touching the host. Embedded NUL is an ordinary output byte. A program writes a newline only by including \n in its string.

The call is synchronous. It completes its write or produces a non-success execution outcome before the VM dispatches the next instruction. ASPL does not flush or coordinate buffering inside unsafe foreign functions, so foreign-library output remains subject to that library's own rules.

Output is a host effect, not an ASPL value. A write failure never becomes an ASPL trap, errno value, Boolean result, or integer result.

Bytecode and lowering

The unpublished bytecode version 1 gains this instruction:

Opcode Instruction Operands a, b, c
42 WRITE_STRING source string register, 0, 0

The checker gives the builtin its own fixed target kind. Lowering evaluates the argument normally, then emits WRITE_STRING with the resulting register. It emits no call frame, return destination, argument staging range, foreign import, library name, symbol name, or serialized builtin name.

The validator requires operand a to name an initialized string register in the current function and requires both unused operands to be zero. WRITE_STRING falls through after success and counts as one instruction under the existing pre-dispatch accounting rule. A source map associates it with the complete builtin call span.

The instruction is host-neutral. Native and browser hosts consume identical bytecode; their output destinations and limits do not change instruction selection or serialization. Since version 1 has not shipped, its draft table is amended in place rather than creating version 2. Any later change to the opcode number or meaning requires a new bytecode version under the existing version rule.

Host callback and outcomes

Each VmExecution receives a synchronous output callback. The callback borrows the immutable string pointer and byte length only for the duration of the call. It may not retain or mutate the bytes.

The callback reports exactly one of these results:

The VM stops execution on either non-success result and keeps the ordinary mapped or unmapped instruction location. Output accepted before the stop remains externally visible. The output limit is cumulative per execution and counts accepted UTF-8 bytes, including embedded NUL.

Native Linux behavior

Direct aspl run execution and generated native programs write builtin output unchanged to inherited stdout. aspl check and aspl build compile and validate the instruction but never execute it.

The native adapter retries interrupted writes and continues after short writes until it accepts the complete string or receives an unrecoverable result. A failure after a partial write reports the accepted prefix and cannot roll those bytes back. Native execution has no product output ceiling.

ASPL preserves the CLI's normal Unix signal policy. It installs no SIGPIPE handler. A closed stdout pipe may therefore terminate the process by SIGPIPE before the adapter receives an error. If the surrounding environment ignores or blocks SIGPIPE and the write returns EPIPE, the adapter reports host-failure/host-operation-failed and the process uses host-failure status 8.

Browser behavior

The playground supplies the same builtin through its worker host callback without adding a foreign import, filesystem bridge, network bridge, or server call. It retains a maximum of 256 KiB, or 262,144 accepted bytes, per execution. A call that would cross the ceiling contributes no bytes and returns limit-stop/output-limit; output from earlier calls remains visible and is marked partial.

The playground retains exact bytes for accounting and conformance, but its output region uses a safe presentation. Line feeds and tabs keep their layout. NUL, carriage return, bidi controls, and other non-printing controls appear as visible escapes with their Unicode code point and name under the pinned Unicode data. The output container isolates its direction from the surrounding Arabic or English interface.

Accepted output appears as the program emits it. Starting a new Run clears the preceding output. Stop, trap, limit stop, or host failure preserves accepted bytes and marks the output partial. Editing after a run keeps its output with the existing Previous source snapshot label until the next Run.

Diagnostics and confusables

The diagnostic catalog replaces unsafe-on-aspl-call with:

Reason Severity Arabic template English template
unsafe-on-safe-call error لا تُستخدم العلامة {marker} مع استدعاء آمن. A safe call must not be marked {marker}.

It replaces confusable-keyword with confusable-reserved-name. Confusable checking compares each declared identifier with both keyword sets and the two builtin aliases under the existing LTR and RTL skeleton rules. The record carries name, reserved-name, and reserved-kind, where the kind is keyword or builtin.

Reason Severity Arabic template English template
confusable-reserved-name warning قد يلتبس المعرّف {name} بالاسم المحجوز {reserved-name}. Identifier {name} may be visually confusable with reserved name {reserved-name}.

The renderer also shows reserved-kind as localized structured detail. Arabic renders the values as كلمة محجوزة and دالة مضمنة; English renders them as keyword and builtin. Exact builtin spellings remain hard name conflicts rather than warnings.

Documentation and conformance

The canonical first website program still sums the integers from 1 through 10 and returns status 0 only when the result is 55. On that successful path it calls اطبع("55\n"). The English-keyword and mixed-alias counterparts preserve the same string bytes and expected output.

Builtin conformance must cover: