Bounded native Lua language

A whole computer program is one literal descriptor:

return {
  api_version = 1,
  handlers = {
    start = function(event)
      computer.log("Ready")
      computer.every(60, "sample")
    end,
    sample = function(event)
      local n = computer.getState("samples") or 0
      computer.setState("samples", n + 1)
    end
  }
}

start is optional. Handler names are unique, bounded identifiers and all registrations refer to declared names, never function values. Only comments/empty statements may surround the sole literal descriptor return. No dynamic descriptor keys, extra descriptor keys, module-level effects or helper initialization are allowed. A fresh environment is constructed for each callback: locals and closures do not secretly survive; use explicit computer state.

Inside handlers: local declarations/assignment, literals/tables, if/elseif/else, do, return, break, numeric/generic for, while, repeat, local helpers and guest calls are supported. Recursion/loops consume enforced work/depth/allocation credits, not unlimited native time. Lua 5.2 primitive arithmetic, comparisons, short-circuiting, concatenation and multiple-return/nil-tuple adjustment apply. Nonfinite values cannot cross state/API boundaries. Use dot calls everywhere.

Approved globals and libraries

Globals: assert, error, ipairs, pairs, next, pcall, select, tonumber, tostring, type; read-only math, string, table, colors/colours, computer, peripheral. No print: use computer.log.

Library Complete members
math abs, ceil, floor, min, max, sqrt, fmod, modf, sin, cos, tan, asin, acos, atan, atan2, deg, rad, exp, log, pi
string byte, char, len, sub, lower, upper, reverse, rep, format, find
table concat, insert, remove, sort, pack, unpack
colors / colours 16 colors plus gray/grey and lightGray/lightGrey aliases; exact constants

These follow bounded Lua-style primitive operations, not arbitrary native-library fallback. Math validates finite operands/results. Numeric-string arithmetic and conversion is metered; invalid tonumber returns nil. tostring never exposes native addresses. string.find(s, needle, init, true) requires explicit true for plain search and returns first,last or one nil. No patterns. string.sub/byte operate on byte indexes, not Unicode; char operands are 0–255. Formatting validates width/precision/output amplification before work. Large repetition/concatenation can refuse before allocating output. Table mutation requires guest-owned plain tables; dense-sequence helpers reject unsuitable inputs. Sort stages before publication and comparator guest calls consume the same ledger. Pack/unpack and select preserve nil arity but remain within tuple limits. Iterator exhaustion returns one nil; absent remove returns one nil. Returned defensive API snapshots are usable guest tables, not references to service internals.

Standard helper signatures

... below is bounded by tuple_entries (128), including protected status prefixes. These helpers operate only inside a callback; they grant no persistent/host access.

Global signature Returns / behavior
type(value) Lua type-name string
tostring(value) Primitive string or stable descriptive table/function/handle name; no addresses
tonumber(value, base?) Number or one nil for invalid conversion; base 2–36 requires string
assert(value, ...) value,... if truthy; otherwise raise first message or default
error(value) Does not return; raises supplied guest value without a host stack-level API
pcall(fn, ...) true,results... or false,error for ordinary failure; fatal budget/stop escapes
select("#", ...) Argument count, including nils
select(index, ...) Suffix tuple; nonzero integer, negative counts from end
next(table, previous_key?) key,value or one nil at end; guest table only
pairs(table) Iterator, table, nil; no sorted-order guarantee
ipairs(table) Iterator, table, 0; stops at first absent 1-based value
Math signature Returns / domain
math.abs(x), ceil(x), floor(x), sqrt(x) One finite number
math.min(x, ...), max(x, ...) One number; at least one operand
math.fmod(x, y) Remainder
math.modf(x) Integer part, fractional part
math.sin(x), cos(x), tan(x) Trigonometric result, radians
math.asin(x), acos(x), atan(x), atan2(y, x) Angle in radians; finite-domain results required
math.deg(x), rad(x) Radians→degrees / degrees→radians
math.exp(x), log(x, base?) Exponential / logarithm; nonfinite result refused
math.pi Read-only numeric constant

The Math table abbreviates member prefixes: e.g. ceil means math.ceil. Numeric-string operands are converted under byte-work admission. Native math errors/nonfinite results do not become valid Data; no random/seed API exists.

String signature Returns / defaults
string.len(s) Byte length
string.sub(s, i?, j?) Byte slice; defaults 1,length; negative indexes from end, clipped
string.byte(s, i?, j?) Byte-number tuple; default i=1, j=i; empty range yields zero values
string.char(...) String from integer bytes 0–255
string.lower(s), upper(s), reverse(s) Byte-string transform
string.rep(s, n, separator?) Repetition with default empty separator; nonpositive n yields empty
string.format(format, ...) Bounded formatted string; conversions c,d,i,o,u,x,X,e,E,f,g,G,q,s and literal %%
string.find(s, needle, init?, true) first,last byte indexes or one nil; default init=1, plain=true required

Negative string indexes are relative to length; finite numeric indexes are clipped using the helper's Lua-style floor/ceiling rules. String inputs/results are at most 16,384 bytes. Formatting can refuse a conservative estimated output even if a particular formatted result would be shorter. No patterns or Unicode processing.

Table signature Returns / defaults
table.pack(...) Temporary table with slots and n counting nils; not necessarily persistable Data
table.unpack(t, i?, j?) Tuple including holes; default i=1, j=#t; bounded indexes/tuple width
table.concat(t, separator?, i?, j?) String from dense string/number sequence; defaults empty separator,1,length
table.insert(t, value) / table.insert(t, position, value) None; append / insert into dense sequence
table.remove(t, position?) One removed value or one nil; default final position
table.sort(t, less?) None; staged dense-sequence sort, default primitive <; optional guest comparator

Table helpers require guest-owned plain tables and bounded inventory (1,024 entries). Pack may contain nil holes plus n, so do not store it as Data without conversion. Sort failure does not publish a partially sorted target, but comparator effects on other guest/API state are not a callback-wide transaction. Never depend on hash iteration order for factory decisions: sort a bounded list when order matters.

Excluded features

No _ENV, _G, global assignment, generated/private names or host globals (game, script, remote, storage, settings, defines, rendering). No require, load, loadstring, loadfile, dofile, package/bytecode/debug, coroutines, IO, sockets, OS/wall clock, random/randomseed, math.huge, raw helpers or metatable access. No goto/labels, Lua 5.3+ syntax, colon calls or indexing a string to reach its host metatable. Use string.sub(s, ...), not s:sub(...). No string match/gmatch/gsub/dump, no non-plain find. Protected namespaces and facades cannot be mutated or persisted. These are intentional compatibility boundaries, not invitations to bypass the sandbox.

Failure and persistence

Source/token/node/nesting/generated-source and compile-work limits apply before activation. Runtime instrumentation charges loops, calls, table/index movement, operators and opaque helpers. Exceeding fatal work/depth/allocation limits faults the run even inside pcall; it does not yield or switch to an interpreter. Successful earlier state/KV/configuration/display effects stay committed while still-owned logic output is cleared. A later explicit Run starts a new generation.

No player source executes on load. Only explicit plain state and validated named registrations/events persist; host executable reconstruction happens during synchronized work with identical warm/cold admission. Work-unit limits do not prove real-time latency. See common rules, computer API and runnable examples.