0x0LearnReferenceLibrariesMigration0x0.jmp0x1b.com

0x0 Language Guide

This guide documents the language slice implemented by

compiler/main.0x0. It is descriptive, not aspirational: a construct

belongs here only when the current compiler parses and emits it.

Source Files

A 0x0 file is a sequence of parenthesized forms. The conventional first form is

the module declaration:


(⊙ main)

The compiler currently uses the module name when emitting OISA. If no module

form is present, the module name defaults to main.

File-based compiler entry points accept import forms:


(↥ "import-helper.0x0")
(↥ "pkg:core-map")

loads another .0x0 source file before compiling the importing file. The

path is a text literal. Relative paths are resolved from the importing source

file's directory; absolute paths are used as written. Imported functions

participate in semantic validation and can be called by the root file. The root

file's form still controls the emitted module name.

Paths beginning with pkg: resolve through the package lockfile. For example,

(↥ "pkg:core-map") reads the dep core-map ... entry from 0x0.lock and

loads that local dependency path.

Imports may also declare an alias:


(↥ "import-helper.0x0" helper)

With an alias, imported function definitions are exposed as alias.name symbols

inside the importing compile unit. Imported modules may declare exported

functions with :


(↦ public-add another-public-function)

If a module has no form, all of its functions are exported for namespaced

imports. If it has one or more forms, only those functions may be called

through the import alias. Non-exported functions remain available inside the

imported module for its own implementation.

This is the first multi-file slice, not the final package system. The repository

now has a checked 0x0.pkg manifest and generated 0x0.lock for local path

dependencies. Package imports resolve local lockfile dependencies, but imports

do not yet provide full path normalization.

Line comments start with ; and continue to the next newline:


;;; Module-level comment.
;; Function or section comment.
; Local implementation note.

Comments are ignored by the lexer. They must not change emitted OISA or runtime

behavior.

Functions

Functions use the ƒ form:


(ƒ add
  (∷ (→ I64 I64 I64))
  (a b)
  (+ a b))

The implemented function shape is:


(ƒ name
  optional-annotations...
  (param...)
  body...)

Annotations are accepted with the form. The emitter still skips annotation

nodes when generating OISA, C, and ELF, but the compiler now validates the

implemented contract slice before emission:

is concrete;

inferred by the current checker.

Annotations therefore describe checked source contracts for the current slice,

not runtime metadata:


(∷ (→ ArgType... ResultType))

Functions may also include a doc annotation before the parameter list:


(doc "Return the sum of two integers.")

doc annotations are parsed as source metadata and skipped by the OISA, C, and

ELF backends. This lets libraries and frameworks carry documentation inside the

language surface without changing runtime behavior.

Functions may also include a capability annotation:


(cap pure)

The current capability names are pure, io, file, network, and process.

Unannotated functions default to io. A pure function may call pure functions

and pure builtins, but it may not call read-stdin, argv, env, read-file,

write-file, print, panic, or another function whose capability is not

pure. file is

used by safe file wrappers in lib/core/file.0x0. network and process are

accepted source contracts for framework/runtime boundaries; the current runtime

does not yet expose socket or subprocess builtins. Capability annotations are

skipped by emitters after validation, like type and documentation annotations.

Multiple body expressions are evaluated in order. The final expression is the

function result. An empty body emits Unit.

Semantic Checks

Before any backend emits output, the compiler validates:

are rejected.

inferable. Any remains permissive.

inferred concrete types differ. Any remains permissive.

function whose capability is not pure.

This is not yet a complete type system. The checker deliberately treats

unresolved complex cases as Any instead of pretending to prove them.

Values

The current source language supports:

value/tag slice.

reverse.

The first source libraries in lib/core define conventional list-backed

Option, Result, map, byte-list, JSON-field, error, safe path, and safe file

helpers. See docs/core-library.html for their current source-level

representations.

Control Forms

if has exactly three operands:


(if condition then-expression else-expression)

The current truth rule treats nil and false as false in the C compatibility

runtime. The ELF slice uses the value register for branch tests in the supported

examples and compiler path.

introduces local bindings:


(≔ ((name value)
    (other value))
  body...)

Bindings are evaluated in order, and the body is evaluated with the new names in

scope.

do evaluates expressions in sequence and returns the last one:


(do
  (write-file "build/out.txt" "ok")
  42)

Builtins

The current compiler/runtime surface includes these builtins:

not.

int-to-text, text-to-int, is-space?, is-digit?, is-alpha?.

write-file, print, panic.

read-stdin reads standard input until EOF and returns it as Text.

argv returns the process arguments after the executable name as a list of

Text values. env reads one environment variable by name and returns its

value as Text, or "" when the variable is not present.

print writes shown values separated by spaces and then a newline. The final

main result printer writes integer and text results directly.

The OISA and C compatibility paths expose a dynamic Value runtime. The direct

ELF path implements the value/tag subset needed by the compiler and examples,

including bounded read-stdin, process argv/env, callable print for

integer/text values, and startup/runtime printing for the final main result.

The direct ELF runtime follows ABI 0.1 from docs/abi.html: function results

return as payload rax plus tag r15; up to six arguments travel as payload

and tag register pairs; Text is NUL-terminated UTF-8; lists are 24-byte cons

nodes; runtime panic exits with status 1; and direct ELF calls with more

than six arguments are rejected.

Example


(⊙ recursive-let)

(ƒ loop
  (∷ (→ I64 I64 I64))
  (n acc)
  (if (= n 0)
    acc
    (loop (- n 1) (+ acc 7))))

(ƒ main
  (∷ (→ Unit I64))
  (_)
  (≔ ((start 6))
    (loop start 0)))

This returns 42.

Compatibility Rules

Every accepted source construct must pass the same checks:

same output.