This document defines the HopHop language contract for independent compiler implementations. It is written to be implementation-oriented and evolution-friendly.
Primary goals:
See also:
MUST, MUST NOT, SHOULD, and MAY are normative.Stable, Provisional, or Draft.Stable rules are required for Core conformance.Provisional rules are expected for Reference-hop compatibility and may evolve.Draft rules are non-implemented proposals and are non-normative.Core profile = all Stable rules in this document.Reference-hop profile = Core + Provisional + section 14 behavior.Provisional rules, it is implementation-defined for Core conformance.Stable and Provisional text differ, Stable text is authoritative for Core.Reference-hop, section 14 entries are compatibility notes: unless a rule explicitly says behavior is required, reproducing a listed divergence is optional.space, tab, \r, \n, \f, \v.// to end-of-line./* and */.*/.[A-Za-z_][A-Za-z0-9_]*.__hop_ are reserved._ is a hole name, not a normal binding name._ is allowed only in positions that explicitly permit holes:var _ = expr, const _ = exprimport "path" as _import pub struct union enum fn var const type if else for switch case default break continue return defer assert sizeof true false in as null new del.mut is reserved legacy syntax and MUST be rejected in type positions.0x / 0X)."...") or raw (`...`).true, false.null.'...') and denote Unicode scalar values.\a, \b, \f, \n, \r, \t, \v, \\, \", \', octal \NNN, hex \xNN, Unicode \uNNNN, \UNNNNNNNN.\n in decoded string bytes.\ immediately followed by a line break elides that line break. In raw strings, only \` is treated specially (it encodes a literal backtick).";" as terminators in a number of productions. HopHop programs may omit most of these semicolons using the following two rules:IDENT, INT, FLOAT, STRING, RUNE, TRUE, FALSE, NULLBREAK, CONTINUE, RETURNRPAREN, RBRACK, RBRACENOT (postfix unwrap ! at line end)@ introduces a directive token sequence at top-level declaration scope.@name or @name(...).SourceFile consists of zero or more imports followed by zero or more top-level declarations.SourceFile = { ImportDecl ";" } { DirectiveRun TopDecl ";" } .
StringLit = /* lexical string literal; see [LEX-LIT-006] through [LEX-LIT-009] */ .
RuneLit = /* lexical rune literal; see [LEX-LIT-010] through [LEX-LIT-012] */ .
Literal = IntLit | FloatLit | StringLit | RuneLit | BoolLit | "null" .
DirectiveRun = { Directive ";" } .
Directive = "@" Ident [ "(" [ Literal { "," Literal } [ "," ] ] ")" ] .
ImportDecl = "import" StringLit [ ImportAlias ] [ ImportSymbols ] .
ImportAlias = "as" ( Ident | "_" ) .
ImportSymbols = "{" [ ImportSymbolList ] "}" .
ImportSymbolList = ImportSymbol { ImportSep ImportSymbol } [ ImportSep ] .
ImportSymbol = Ident [ "as" Ident ] .
ImportSep = "," | ";" .
TopDecl = [ "pub" ] ( StructDecl | UnionDecl | EnumDecl | TypeAliasDecl | FnDeclOrDef | TopConstDecl ) .
DeclName = Ident | "_" .
DeclNameList = DeclName { "," DeclName } .
TopDeclNameList = Ident { "," Ident } .
TypeParamList = "[" Ident { "," Ident } "]" .
StructDecl = "struct" Ident [ TypeParamList ] "{" [ StructFieldDeclList ] "}" .
UnionDecl = "union" Ident [ TypeParamList ] "{" [ FieldDeclList ] "}" .
EnumDecl = "enum" Ident [ TypeParamList ] Type "{" [ EnumItemList ] "}" .
TypeAliasDecl = "type" Ident [ TypeParamList ] Type .
FieldSep = "," | ";" .
AnonFieldSep = ";" .
StructFieldDeclList = StructFieldDecl { FieldSep StructFieldDecl } [ FieldSep ] .
FieldDeclList = FieldDecl { FieldSep FieldDecl } [ FieldSep ] .
AnonFieldDeclList = FieldDecl { AnonFieldSep FieldDecl } [ AnonFieldSep ] .
EnumItemList = EnumItem { FieldSep EnumItem } [ FieldSep ] .
StructFieldDecl = ( FieldDecl | EmbeddedFieldDecl ) [ FieldDefault ] .
FieldDecl = Ident { "," Ident } Type .
EmbeddedFieldDecl = TypeName .
FieldDefault = "=" Expr .
EnumItem = Ident [ EnumPayload ] [ "=" Expr ] .
EnumPayload = "{" [ FieldDeclList ] "}" .
FnDeclOrDef = "fn" FnName [ TypeParamList ] "(" [ ParamList ] ")" [ FnResultClause ]
[ Block ] .
FnName = Ident | "sizeof" .
ParamList = ParamGroup { "," ParamGroup } .
ParamGroup = "const" ( ( Ident | "_" ) Type | ( Ident | "_" ) "..." Type )
| ( Ident | "_" ) { "," ( Ident | "_" ) } Type
| ( Ident | "_" ) "..." Type .
FnResultClause = Type | "(" FnResultGroup { "," FnResultGroup } ")" .
FnResultGroup = Type | ( Ident { "," Ident } Type ) .
TopConstDecl = "const" TopDeclNameList ( [ Type ] "=" ExprList ) .
LocalConstDecl = "const" DeclNameList ( [ Type ] "=" ExprList ) .
Type = OptionalType | PtrType | RefType | SliceType | ArrayType | VarArrayType
| FnType | TupleType | AnonStructType | AnonUnionType | TypeName .
OptionalType = "?" Type .
PtrType = "*" Type .
RefType = "&" Type .
SliceType = "[" Type "]" .
ArrayType = "[" Type Expr "]" .
VarArrayType = "[" Type "." Ident "]" .
FnType = "fn" "(" [ FnTypeParamList ] ")" [ Type ] .
TupleType = "(" Type "," Type { "," Type } ")" .
FnTypeParamList = FnTypeParam { "," FnTypeParam } .
FnTypeParam = "const" ( Type | Ident Type | "..." Type )
| Type | ( Ident { "," Ident } Type ) | "..." Type .
AnonStructType = [ "struct" ] "{" [ AnonFieldDeclList ] "}" .
AnonUnionType = "union" "{" [ AnonFieldDeclList ] "}" .
TypeArgList = "[" Type { "," Type } "]" .
TypeName = Ident { "." Ident } [ TypeArgList ] .
Block = "{" [ StmtList ] "}" .
StmtList = Stmt { ";" Stmt } [ ";" ] .
Stmt = Block | VarDeclStmt | LocalConstDecl | IfStmt | ForStmt | SwitchStmt
| ReturnStmt | BreakStmt | ContinueStmt | DeferStmt | AssertStmt
| ConstBlockStmt | DelStmt | ShortAssignStmt | MultiAssignStmt | ExprStmt .
VarDeclStmt = "var" DeclNameList ( Type [ "=" ExprList ] | "=" ExprList ) .
ShortAssignStmt = DeclNameList ":=" ExprList .
MultiAssignStmt = ExprList "=" ExprList .
IfStmt = "if" Expr Block [ "else" ( IfStmt | Block ) ] .
ForStmt = "for" ( Block | Expr Block | ForClause Block | ForInClause Block ) .
ForClause = [ ForInit ] ";" [ Expr ] ";" [ Expr ] .
ForInit = VarDeclStmt | ShortAssignStmt | Expr .
ForInClause = ForInValueBinding "in" Expr
| ForInKeyBinding "," ForInValueBinding "in" Expr .
ForInKeyBinding = [ "&" ] Ident .
ForInValueBinding = "_" | [ "&" ] Ident .
SwitchStmt = "switch" [ Expr ] "{" { CaseClause } [ DefaultClause ] "}" .
CaseClause = "case" CasePattern { "," CasePattern } Block .
CasePattern = Expr [ "as" Ident ] .
DefaultClause = "default" Block .
ReturnStmt = "return" [ ExprList ] .
BreakStmt = "break" .
ContinueStmt = "continue" .
DeferStmt = "defer" ( Block | Stmt ) .
AssertStmt = "assert" Expr [ "," Expr { "," Expr } ] .
ConstBlockStmt = "const" Block .
DelStmt = "del" Expr { "," Expr } [ "in" Expr ] .
ExprStmt = Expr .
Expr = AssignExpr .
AssignExpr = LogicalOrExpr [ AssignOp AssignExpr ] .
AssignOp = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" .
LogicalOrExpr = LogicalAndExpr { "||" LogicalAndExpr } .
LogicalAndExpr = BitOrExpr { "&&" BitOrExpr } .
BitOrExpr = BitXorExpr { "|" BitXorExpr } .
BitXorExpr = BitAndExpr { "^" BitAndExpr } .
BitAndExpr = EqualityExpr { "&" EqualityExpr } .
EqualityExpr = RelExpr { ( "==" | "!=" ) RelExpr } .
RelExpr = ShiftExpr { ( "<" | ">" | "<=" | ">=" ) ShiftExpr } .
ShiftExpr = AddExpr { ( "<<" | ">>" ) AddExpr } .
AddExpr = MulExpr { ( "+" | "-" ) MulExpr } .
MulExpr = UnaryExpr { ( "*" | "/" | "%" ) UnaryExpr } .
UnaryExpr = ( ( "+" | "-" | "!" | "*" | "&" ) UnaryExpr ) | PostfixExpr .
PostfixExpr = PrimaryExpr { PostfixSuffix } .
PostfixSuffix = CallSuffix | IndexSuffix | SelectorSuffix | CastSuffix | UnwrapSuffix .
CallSuffix = "(" [ CallArgList ] ")" .
CallArgList = CallArg { "," CallArg } .
CallArg = [ Ident ":" ] Expr [ "..." ] .
ExprList = Expr { "," Expr } .
IndexSuffix = "[" Expr "]" | "[" [ Expr ] ":" [ Expr ] "]" .
SelectorSuffix = "." Ident .
CastSuffix = "as" Type .
UnwrapSuffix = "!" .
PrimaryExpr = Ident | IntLit | FloatLit | StringLit | RuneLit | BoolLit | "null"
| TypeValueExpr
| CompoundLit | NewExpr | "sizeof" "(" ( Type | Expr ) ")" | "(" Expr ")"
| TupleExpr .
TypeValueExpr = "type" Type .
TupleExpr = "(" Expr "," Expr { "," Expr } ")" .
NewExpr = "new" ( "[" Type Expr "]" | Type [ "{" [ FieldInitList ] "}" ] ) [ "in" Expr ] .
CompoundLit = [ TypeName ] "{" [ FieldInitList ] "}" .
FieldInitList = FieldInit { "," FieldInit } [ "," ] .
FieldInit = Ident { "." Ident } ":" Expr .
Ident {"," Ident} Type as a named-parameter groupTypecontext lexes and parses as an identifier expression; semantically it resolves to the ambient context binding in function bodies and is not a bindable declaration name.struct, union, enum, type, or fn, a following [ starts a type-parameter list only when the bracket contents parse as identifiers separated by commas. Otherwise the declaration continues without type parameters.Stmt), leading { is parsed unconditionally as Block.ExprStmt in statement context MUST NOT consume unparenthesized brace-leading compound-literal forms ({ ... }). If a compound-literal expression statement is intended, it MUST be parenthesized (({ ... })).Canonical examples:
fn f() {
{ x = 1 } // block with one statement: assignment to x
}
fn f() {
({ x: 1 }) // expression statement: compound literal value discarded
}
fn f() {
defer { x = 1 } // deferred block
}
fn declarations/definitions, struct, union, enum, type, const.var is invalid.const MUST have an initializer.const initializers MUST be const-evaluable in all scopes (top-level and local).@c_import("symbol") on top-level fn, const, or var declarations@wasm_import("module", "name") on top-level fn, const, or var declarations@export("name") on pub fn definitions@c_import and @wasm_import declare externally provided symbols and therefore require declarations, not definitions.@export publishes the annotated function under the requested external name.@c_import and @wasm_import declarations.pub applies to a single following top-level declaration._ MUST NOT name top-level symbols, struct/union fields, enum items, or type aliases.var _ = expr and const _ = expr are valid statement forms._ discards the corresponding RHS value and does not create or update a binding.context clauses MUST match exactly.context is not an overload dimension.sizeof is accepted as a declaration name for builtin-signature compatibility, but sizeof(...) expression syntax is always the builtin form and is not shadowable by user functions.(x, y T)) provide names for readability only; result names are not local bindings.name ...T and are constrained as follows:a, b ...T is invalid)fn f(...T)-style declarations where T != anytype, the variadic parameter binding inside the body has slice type [T].const (const name T or const name ...T).const a, b T is invalid); write separate const parameters.const parameter, the argument expression MUST be const-evaluable at the call site. For const variadic parameters, this applies to each variadic argument and to spread arguments.anytype is valid only in function parameter positions (function declarations and function-type parameter lists).anytype parameter slots bind independently to the static type of the corresponding call argument....anytype binds a heterogeneous compile-time pack, not a homogeneous slice.const_int or const_float MUST be declared with the const parameter modifier.struct may embed one base field (type-name-only) as first field.Enum.Item or pkg.Enum.Item.enum Name BaseType { ... } MUST be an integer type.as casts are required.{ ... } on the variant.Variant = n and Variant{ ... } = n.Enum.Variant{ ... }.as aliases and named imports) MUST NOT collide with any top-level declaration name in the importing package.builtin package names. Function declarations collide with public builtin functions by the same function identity rules as ordinary overloaded functions.bool, str, rawptr, and type.u8, u16, u32, u64, uinti8, i16, i32, i64, intf32, f64const_int, const_floatint and uint are pointer-sized signed/unsigned integers for the target.MemAllocator is a source-level type provided by builtin library declarations (for example builtin.MemAllocator and unqualified builtin lookup), not a language builtin type.rune is a source-level alias type provided by builtin declarations and modeled as type rune u32.*T, references &T, arrays [T N], slices [T], dependent arrays [T .n], optionals ?T, function types, tuple types (T1, T2, ...), anonymous aggregates.[T] is unsized and MUST NOT be used by value.const name is valid when that constant const-evaluates to a type value.const B = A (with A a type value) is a non-distinct type alias; B resolves to the same type as A. Use type B A for a distinct named type....T (e.g. fn(...i32) i32).const markers in type identity; for example, fn(i32) and fn(const i32) are distinct.anytype participates in function type identity (for example, fn(anytype) is distinct from fn(i32))....anytype are distinct from variadic function types ending in concrete ...T.const_int and const_float type names are valid only in function return types, const parameter types, const declaration explicit types, and as cast targets.struct, union, enum, type, and fn declarations MAY declare type parameters with [...] after the declaration name.type within the generic declaration body.TypeName[TypeArgs...].Vector{ ... } is invalid when Vector is generic.f[T](x) is not a generic call form.str and rune)str denotes textual byte sequences constrained to valid UTF-8.str data ([LEX-LIT-003], [LEX-LIT-009]).str operations are byte-oriented by default: len(s) reports byte length, not Unicode scalar-value count ([BI-LEN-001], [BI-LEN-002]).str is for textual data; arbitrary binary payloads SHOULD use [u8] families ([u8 N], *[u8], &[u8]) instead of str.rune denotes one Unicode scalar value and is modeled as builtin alias type rune u32 ([TYPE-BUILTIN-005], [LEX-LIT-010], [LEX-LIT-012]).const_int; values typed as rune can still implicitly convert to integer destinations only in the in-range const-evaluated case ([TYPE-INFER-004], [TYPE-ASSIGN-008]).cstr(s), which exposes str storage as &u8 with the lifetime/termination guarantees in [BI-CSTR-001] through [BI-CSTR-005].*T is writable reference-like access to T.&T is read-only reference-like access to T.*[T] / *[T N] are writable slice views&[T] / &[T N] are read-only slice viewsmut references or slices.?T accepts any well-formed T.null is assignable only to optional types and rawptr.T -> ?T is allowed.?T -> T is not implicit; unwrap or narrowing is required.if x { ... } narrows x to T in then, null in elsex == null, x != null, null == x, null != xif x == null { ... } else { ... } narrows x to null in then, T in elseif x != null { ... } else { ... } narrows x to T in then, null in elseif without else applies only when the then branch terminates (return, break, or continue)hophop/feature/optional and feature/optional are recognized but not required to enable ? in Reference-hop.const_int, const_float) convert to compatible concrete numeric types subject to range/precision checks.*T -> &T is allowed; read-only to writable is not.[S N] -> &[S][S N] -> *[S] when source is mutable lvalue&[S N] -> &[S]*[S N] -> *[S]*[S] -> &[S]Alias -> Target implicit, Target -> Alias not implicit.rune) can implicitly convert to integer destinations only when const evaluation produces an in-range value._._ first applies implicit defaulting (const_int -> int, const_float -> f64, untyped_bool -> bool).var x = expr infers from expr after concretization; const x = expr preserves const-numeric inference.var inference, const_int defaults to int and const_float defaults to f64.null or no-value expressions is invalid.const_int.var x T zero-initializes x, except direct pointer/reference locals (*T and &T) are uninitialized until assigned and cannot be read, dereferenced, returned, passed, or otherwise used before definite assignment. Direct read-only fat-reference locals &str and &[T] have valid all-zero representations and are zero-initialized to empty views.var x EnumType is valid only when one variant has effective tag value 0.if and switch; a value assigned only on some continuing control-flow paths is considered may-be-uninitialized. Assignments inside loop bodies do not definitely initialize the local after the loop. Parameters and for ... in bindings are initialized on entry.*T or &T require an explicit initializer, except direct read-only fat references &str and &[T]. rawptr keeps normal zero initialization and is not tracked by pointer/reference definite assignment.var a, b = 1, 2; var a, b T = x, y). Initializer arity must match declaration arity, except a single tuple-typed RHS may be decomposed positionally.+/- require numeric operands; unary ! requires bool.* dereferences pointer/reference; unary & forms read-only references.lhs1, lhs2, ... = rhs1, rhs2, ...) requires equal arity, except a single tuple-typed RHS may be decomposed positionally. RHS expressions are evaluated before stores; then stores apply left-to-right.const binding is invalid.name1, name2 := rhs1, rhs2) is local statement syntax. Each non-blank name assigns to a visible local if one exists, otherwise it declares a new mutable local inferred like var name = rhs. _ discards its RHS and never declares or resolves a local. Arity follows multi-assignment, including single tuple RHS decomposition, and RHS expressions are evaluated before assignments/declarations are applied left-to-right. Duplicate non-blank names in one short assignment are invalid.null equality special-cases.as is explicit cast syntax.rawptr may be created only from null, another rawptr, or an explicit cast from a pointer/reference type; casts from rawptr are permitted only to rawptr or pointer/reference types.null are permitted only to optional types and rawptr; typed null pointers/references require an explicit raw pointer bridge such as (null as rawptr) as *T.x! requires x : ?T and yields T.null is a runtime trap (panic), never undefined behavior.+ currently supports compile-time concatenation only for non-parenthesized literal chains (e.g. "a" + "b" + "c"). Other string + forms are invalid in Reference-hop.leftType == rightType, use that typeleft is assignable to right, use rightright is assignable to left, use leftconst_int, const_float) or reversed, use const_floatbool and numeric typestype valuesrawptrstr, *str, &str)rawptrstr, *str, &str)rawptr: identity equality; ordering by pointer-address ordernull): identity equality; ordering by pointer-address orderlen * sizeof(element)struct/union equality: bytewise object-representation equality__equal(lhs, rhs) or __order(lhs, rhs) is a best overload match, hook result semantics override [EXPR-CMPSEM-001] for that operation.__equal(a, b T) bool-shape: exactly 2 parameters, no context clause, return type bool__order(a, b T) int-shape: exactly 2 parameters, no context clause, return type int== uses __equal(lhs, rhs)!= uses logical negation of __equal(lhs, rhs)<, <=, >, >= use __order(lhs, rhs) compared against 0 with corresponding relation.contextnew)var/const symbolsrecv.f(args...) may resolve as f(recv, args...).recv.f alone does not produce callable lowering sugar.0: exact type match1: direct non-exact implicit conversion (for example alias peel step, mutability relaxation)2+: embedded upcast conversions (2 + ancestry_distance - 1)3: const-numeric concretization conversion4: optional lift T -> ?Tcost(dst <- alias(src)) = cost(dst <- srcBase) + 1)cost(?A <- ?B) = cost(A <- B))1 unless matched by a more specific cost rule above.f(p1, ..., pn, v ...T), call shapes are:f(a1, ..., an) (empty variadic tail)f(a1, ..., an, e1, ..., ek) where each ei is assignable to Tf(a1, ..., an, s...) where s is assignable to [T]_. After the first later parameter whose name does not start with _, remaining fixed arguments MUST be named. Variadic-tail arguments are governed by the variadic rules below.... is valid only on the final call argument.f(...anytype), explicit-tail arguments form a heterogeneous pack with per-element static type preservation....anytype pack bindings, len(args) is valid.args[i] with const-evaluable in-bounds integer index yields the indexed element type.args[i] with non-const index is allowed in expected-type contexts (e.g. cast/coercion, typed call arguments, typed assignment) and in typeof(args[i]); these lower to runtime per-element dispatch over the instantiated pack....anytype requires an anytype pack value; slice/array spread into ...anytype is invalid.x[i] over const-evaluable string/slice-like values produces a const byte value when i is const-evaluable and in bounds.*[T][a:b] -> *[T], &[T][a:b] -> &[T], (*str)[a:b] -> *str, (&str)[a:b] -> &strtype T forms a type-value expression of metatype type.type prefix is required when an expression-context type value would otherwise collide with ordinary postfix expression grammar, including instantiated generic named types (type Vector[i32]) and constructed types (type &[i32]).i64, remain valid without the type prefix.a.b.c: ...).{ ... } without explicit type requires expected aggregate type context or anonymous-struct inference.{ field: expr, ... } uses field names and concretized field value types.Enum.Variant{ ... }.Enum.Variant{ ... } type-checks against payload fields of that exact variant only.[expr, ...] forms an array literal expression. Elements may be separated by commas, semicolons, or inserted semicolons, and a trailing separator is allowed.[T N] from the common element type and element count. [] requires an expected type.[T N], each supplied element is checked against T; fewer than N elements default-initialize the trailing elements, and more than N elements is invalid.&[T N] or &[T], all elements must be const-evaluable and the compiler materializes immutable static storage. Bare array literals do not bind to mutable pointer or reference storage.new [expr, ...] allocates initialized array storage. Without an expected type it produces *[T N]; with expected *[T] it allocates dynamic-size storage using the literal length; with expected *[T N] it allocates fixed-size storage with default-filled trailing elements.if condition MUST be bool or optional.for forms: infinite block, condition form, C-style init; cond; post, and for ... in forms.for condition (if present) MUST be bool.for initializer are scoped to the entire loop (condition, post, and body) and are not visible after the loop.for ... in source expression MUST be iterable by either:len(x) and indexing x[i] (HEP-29), or__iterator(x) and matching next_* overloads for the loop form (HEP-30).for ... in source expression is evaluated once before loop iteration.for key, value in x, the key for sequence sources is synthetic int index; &key is invalid for synthetic keys.for ... in:value: by-value capture&value: by-reference capture with &x[i] semantics (mutable source -> *T, immutable source -> &T)_: discard capture (no value binding introduced)for ... in key/value bindings are body-scope locals.for value in x prefers next_value(it *Iter) ?(&T|*T); if unavailable, uses next_key_and_value(it *Iter) ?*Pair and binds from pair element 1 by value.for &value in x prefers next_value(it *Iter) ?(&T|*T); if unavailable, uses next_key_and_value(it *Iter) ?*Pair and binds from pair element 1 by reference.for key, value in x requires next_key_and_value(it *Iter) ?*Pair and binds key from pair element 0 and value from pair element 1.for key, _ in x prefers next_key(it *Iter) ?(&K|*K); if unavailable, uses next_key_and_value(it *Iter) ?*Pair and binds key from pair element 0.for _ in x), iterator protocol uses the value-binding path and discards produced values.__iterator overload resolution follows regular type-function first-argument matching:typeof(x)switch supports expression-switch and condition-switch.default clause.const { ... } executes its block in compile-time evaluation context at call sites.const { ... } failure to evaluate at compile time is a compile-time error.bool, enum), switches MUST be exhaustive unless a default clause is present.Enum.Variant as name introduces name in case-body scope and narrows it to that variant.as alias).break valid inside for/switch; continue only inside for.return must not provide values.return must provide exactly one value assignable to that type.return must provide exactly one value per tuple element, each assignable by position.defer supports statement or block, executes LIFO on scope exit.return, break, continue), but not guaranteed after runtime traps/aborts (panic, failed assert, process termination).str-assignable.context is an ambient builtin expression available in function bodies.Context.Context provides at least fields allocator, temp_allocator, and logger.context is a reserved contextual identifier expression:context.allocator, context.temp_allocator, and context.logger are mutable fields of the current ambient context.context Type clauses and call context ... suffixes are not part of the current grammar.len(x)str, arrays, slices, pointers/references to arrays/slices.int.x.len() is equivalent when no field len shadows it.cstr(s)str-assignable.&u8.x.cstr() is supported.copy(dst, src)copy(dst, src) copies min(len(dst), len(src)) elements from src into dst.memmove over copied bytes.int, and equals the number of elements copied.dst MUST be writable sequence-like and src MUST be readable sequence-like.copy(*str, &str) is valid.copy(*[u8], &str) is valid.copy(*str, &[u8]) is invalid unless src is explicitly cast to &str.newnew Tnew T{...}new [T n]in allocExprallocator compatible with MemAllocator.allocator, MUST be non-null and have a valid allocator implementation.n in new [T n] MUST be integer-typed; constant negative values are invalid.new T -> *Tnew [T n] -> *[T N] when n is constant positive N, else *[T]new [T 0] has type *[T] (runtime-length slice pointer form).Reference-hop, codegen may insert implicit null-trap unwrap when coercing new into non-optional pointer destinations.concat(a, b) and delconcat(a, b) requires both args str-assignable and context allocator; returns *str.del value uses context.allocator; del value in allocExpr uses an explicit allocator.del a, b, c in allocExpr frees each listed pointer through the same allocator.panic(msg)str-assignable.sizeofsizeof(Type) and sizeof(expr) forms are supported.int.sizeof(Type).print(msg)str-assignable.logger.logger beyond field presence.print output MUST end with a line break.Reference-hop currently validates logger field presence at typecheck time and may rely on backend coercion at codegen time for concrete logger compatibility.format(format, args...) and format_str(format, args...)format and format_str are available without an explicit import.format and format_str are builtin package functions.format and format_str(format, args...) require effective context field allocator compatible with MemAllocator.format and format_str(format, args...) return *str.{}, {i}, {f}, and {s}.and represent literal braces.format placeholder count and argument compatibility are checked at typecheck time.format_str(format &str, args...) accepts non-const format strings and performs format validation at runtime.typeof(x)typeof(x) requires exactly one argument.typeof(x) returns a value of builtin metatype type.x.typeof(T) is type (because type names are value expressions whose type is type).kind(...) and base(...)kind(t) and t.kind() require one type operand and return reflect.Kind (fallback u8 when reflect.Kind is unavailable).base(t) and t.base() require one type operand and return type.base(...) is valid only for alias type values; non-alias operands are a type error.is_alias(t) and t.is_alias() require one type operand and return bool.type_name(t) and t.type_name() require one type operand and return &str.ptr(t) requires one type operand and returns type representing *t.slice(t) requires one type operand and returns type representing [t].array(t, n) requires type + integer operands and returns type representing [t n]; n must be const-evaluable and in 0..UINT32_MAX when materialized.is_const(x) and reflect.is_const(x) return a const-evaluable bool indicating whether the call-site operand is const-evaluable. They are intended for const { ... } validation and specialization.source_location_of(x) and builtin.source_location_of(x) return builtin.SourceLocation for operand x.compiler.error* / compiler.warn*compiler.error(message) and compiler.warn(message) require one str-assignable argument.compiler.error_at(location, message) and compiler.warn_at(location, message) require builtin.SourceLocation + str-assignable arguments.&str; _at forms also require a valid const-evaluable builtin.SourceLocation.field [ElemType .lenField].struct.lenField MUST refer to a previously declared non-dependent integer field.*ElemType).sizeof(VSSType) is invalid; pointer/reference value forms are valid.package declaration keyword.import "path"import "path" as aliasimport "path" as _import "path" { Name, Other as Local }. segments, resolves .. by popping one segment, and rejects traversal above loader root.//) are invalid.import "path" as _ { ... } is invalid.* is invalid.import "platform" is built-in package import.platform currently exports exit(status i32).hophop/feature/<name> / feature/<name> are pseudo-imports; unknown names warn in Reference-hop..hop filebuiltin, reflect, compiler, mem, platform, testing, std/*, platform/*), resolver order is:<loader_root>/<importPath> first<ancestor>/lib/<importPath> from importing package directory upward to filesystem root and select the nearest match<ancestor>/lib/<importPath> from dirname(executable_path) upward to filesystem root and select the nearest matchpub exports top-level declarations.fn main() (no params, no return type, no explicit context clause).main, contextual operations use an implicit root context value.Reference-hop executable entry enforces fn main() at compile/run boundary.ParseErrorNameResolutionErrorTypeErrorContextErrorImportResolutionErrorEntrypointErrorThis section is non-core and documents current reference behavior.
switch lowers to if/else chains.new lowering uses allocator helpers and may inject implicit unwrap depending on destination optionality.builtin__Contextbuiltin*__ContextContextallocator, temp_allocator, and loggerassert(cond, fmt, args...) currently ignores formatting arguments in panic payload construction.const initializers are eagerly const-evaluated and rejected when non-const-evaluable (top-level and local).if, for, switch, assert, defer, break, continuesizeof(Type) and sizeof(expr) (including identifiers resolved from const-eval local/param bindings)string -> bool, and null -> rawptr / null -> ?TReference-hop.Draft -> Provisional -> Stable.Stable rules require a migration note and conformance update.platform/<target>.Context) and capability expansion.typeof metatype APIs.