Executable language tags
Executable language tags
The V3 Lua pilot evaluates a tag as a pure function call. Lua is built into
runtimes packaged with the Lua engine; no USE line is required. The public
language name is lua. The embedded implementation is Luau, using Grid's
existing Luau interpreter. Scalar tags use the narrower
grid-luau-source-scalar-v1 profile; typed list tags select the separate
grid-luau-source-batch-v1 Pilot; installed
grid-luau-script-v1 packages retain their existing behavior.
input Quantity = 2
input UnitPrice = 50
Total = <lua type="number" template>
return {{Quantity}} * {{UnitPrice}}
</lua>
Answer = <lua type="number">
return 42
</lua>type declares the result at the language boundary. The pilot accepts number, string, and boolean, plus homogeneous
nonnullable lists spelled number[], string[], and boolean[]. The body is a function body. Its first returned value must have that
type; additional Lua return values are ignored. Lua syntax is checked when the runtime admits the model;
an invalid replacement leaves the previous admitted model intact. A runtime
without the Lua engine refuses admission.
Reactive operands
Add template to insert Grid expression operands. Each hole is evaluated
once, eagerly, in source order in its existing Grid lexical scope. Changing
inputs recalculates the call without compiling Lua source again. Runtime values
are passed as typed arguments; their contents never become Lua source text.
Holes must have statically established, nonnullable scalar or homogeneous
scalar-list types. Objects, blank, nested or heterogeneous lists, unconstrained
generic values, units, and refined values are outside this pilot. A tag can appear in a Grid expression or callable body;
local operands keep their DO, function, and lambda scopes. Callable results
need proven unrefined result provenance. The pilot currently refuses all dynamic
and named callable results, including identity results and model aliases of
those results. Existing native schemes establish representation compatibility
without proving that a returned value is unchanged. Tags inside DEFINE bodies
remain supported. Until native result provenance proves otherwise,
refined or unknown descendants also remain refused through arithmetic,
selection, and conversion expressions.
Holes occupy executable expression positions. Holes inside Lua strings, backtick strings, or comments are refused, as are holes splitting an identifier or number token. Generated argument names avoid authored identifiers. The foreign parser checks the resulting Lua program at admission.
Without template, the body remains verbatim and braces have no Grid meaning.
The default delimiters are {{ and }}. Explicit start and end attributes
follow the existing template rules, including doubled opening
delimiters. Tagged ordinary and triple-quoted strings also support the same
type and template parameters; angle blocks are preferred for multiline code.
The first matching closing tag ends an angle block, including one inside
foreign text.
Typed batches
Pass a row or column list through a template hole and process all its values in one Lua invocation. Inputs are immutable, one-based Luau tables; use numeric loops. Results must be consecutive nonnullable scalar lists. Empty results are accepted. Matrices and nested lists are refused; they need a packaged dense or Frame contract. A list result uses BatchMap; a scalar result with list operands uses Reduce. These inline contracts use whole-call incrementality.
input Readings = [10, 20, 30]
Doubled = <lua type="number[]" template>
local readings = {{Readings}}
local result = {}
for index = 1, #readings do
result[index] = readings[index] * 2
end
return result
</lua>
Total = <lua type="number" template>
local readings = {{Readings}}
local total = 0
for index = 1, #readings do
total += readings[index]
end
return total
</lua>The declared input type must be proven in the Grid lexical scope. A generic function parameter alone is insufficient; a captured typed list or an expression with an established list type is accepted. Scalar and list Lua tags can appear inside DEFINE bodies. Result types describe the returned list; they do not promise that its length equals an input length.
Automatic scalar-call batching
An ordinary MAP can automatically batch a pure inline scalar body:
DEFINE Twice(value) = <lua type="number" template>
return {{value + 0}} * 2
</lua>
Doubled = MAP(SEQUENCE(10000), Twice)The compiler selects a separate extension MAP opcode with the authored MAP as its exact fallback. It accepts a direct inline scalar tail, including transparent named callable adapters, with pure scalar Grid operands. The admitted Luau bytecode must prove a bounded body with no guest calls, globals, captured state, allocation, or loops. The first automatic subset has number/boolean inputs and results, default scalar budgets, and no ambient shared invocation meter.
Maps with fewer than 64 scalar leaves and bodies without template arguments retain ordinary scalar execution before any eligibility probe. Inputs requiring coercion also retain ordinary execution and its diagnostic/memo behavior. Larger maps transfer at most 256 distinct guest argument tuples per chunk. Two bounded invocation-local indexes retain at most 2,048 raw input tuples and 2,048 converted guest tuples, preserving reuse without retaining guest state or capture results. A chunk reduced to one distinct guest tuple uses ordinary scalar execution. A no-guest eligibility probe declines unsupported bodies before capture.
Successful chunks use the existing bounded result-cache limits. Chunk keys bind the verified manifest and the exact ordered argument rows, independently of scalar keys. Disabled result caching performs no chunk serialization or hashing. Owned result slots count against the cache byte limit; partial successes, errors, and expired results are not cached. A qualifying uncached chunk initializes one VM and reuses its proven stateless function. Each logical call retains its scalar result/error validation and allowance. Guest failures remain individual error values; unavailable optimization support takes the scalar fallback before guest execution. MAP ordering, array shape, and scalar broadcasting remain unchanged. Ordinary arrays and dense numeric arrays participate; native collection families retain ordinary MAP behavior.
Batch telemetry counts logical extension requests, outcomes, and cache activity;
a guest start is one actual chunk VM rather than one logical row. Duration sums
record chunk wall time with logical request counts, so their mean is amortized.
grid_extension_scalar_batch_chunks_total distinguishes executed chunks from
cache hits. Admission probes do not count as calls. Updates occur once per chunk. Batch
series are emitted only after batch work; inactive scrapes add no new output.
String kernels, callbacks such as math.abs, stateful bodies, different budgets, loops, guest branches, dynamic callable selection, and unproven signatures keep fresh-state scalar calls. Calls in separate cells are not grouped across dependency boundaries. Explicit list bodies remain available for those computations. Neither batching interface adds persistent guest sessions or a worker to ordinary models.
Typed lists and automatically batched MAP require compiled model format minor 27. Existing scalar source inventories remain minor 26. Older readers reject the new contract.
Names and lifecycle
Bare lua is case insensitive in the tag namespace. Ordinary Grid functions
and variables named lua remain legal. An imported tag handler cannot replace
the builtin bare name; a qualified imported tag such as <custom.lua> keeps
its ordinary explicit import and handler contract.
The compiler retains exact source, scalar signature, budget, and manifest identity in the portable compiled model. Source inventory conveys no installation or execution authority. Admission revalidates that inventory against every referenced binding and prepares private bytecode once per artifact for that model revision. Saving and cold loading retain source, never producer-supplied bytecode. Retained revisions keep their admitted service until their final owner releases it. Replacing the ambient extension service does not rewrite existing revisions.
The initial source profile refuses generic for ... in ... loops, including
pairs, ipairs, and direct table iteration. Luau can otherwise expose
memory-dependent ordering through identity keys. Admission checks the private
compiler output, including nested functions, rather than matching source text.
Use numeric for or while loops in this pilot. Ambient randomness, clocks,
heap observations, weak-table/metatable construction, and identity-string
conversion are unavailable. This is a
restricted pure source interface, not cross-platform certification of every
Luau mathematical library function.
Explicit list and ordinary scalar invocations start with fresh sandboxed guest state. Proven stateless batches share one fresh VM for that chunk. The pure profile has no filesystem, network, process, or persistent state capabilities. Existing extension fuel, deadline, memory, and output budgets apply. Aggregate portable source is bounded to 16 MiB and retained prepared code to 32 MiB, with at most 256 artifacts and 256 operands per call. Luau's native source compiler has no allocator or interrupt hook: source/output ceilings and checks before and after compilation do not establish a hard native compiler peak-memory or CPU limit.
Later languages and DSLs
This milestone provides Lua execution through the existing extension runtime. Grid-authored grammar/TREE producers and a general extension-contribution result contract are later work. They can eventually target a supported foreign language while keeping native type admission and exact artifact identity. Wasm-compatible language support will use the same invocation and revision custody contracts, with explicit compiler packaging and target profiles. This pilot does not bundle a Wasm language compiler or imply full V3 completion.