nupp.reflect

Semantic type reflection and reflection-driven field codecs.

Call the namespace with a concrete type inside comptime to obtain an immutable, target-independent descriptor. fieldCodec materializes the stored fields of a reflected record into a keyed runtime codec.

The root's common facts are projected onto Info, so the usual inspection does not need to walk the graph:

local record User
    id: integer
    name: string = "anonymous"
end

const UserSummary: string = comptime do
    local info = nupp.reflect(User)
    assert(info.kind == "record")
    assert(info.fields[2].hasDefault)
    return info.fields[1].name .. ":" .. info.fields[1].kind
end

assert(UserSummary == "id:integer")

Use root, types, and the integer edges between them when a generator needs the complete semantic type rather than the root projection. The graph remains finite even when the declaration is recursive:

local record Node
    value: string
    next: Node?
end

const NextKind: string = comptime do
    local info = nupp.reflect(Node)
    local edge = info.fields[2].type as integer
    return info.types[edge].kind
end

assert(NextKind == "union")

Module contents

Types

TypeKindDescription
AnnotationrecordA typed annotation application, retaining source order.
AnnotationArgumentrecordA checked member supplied to a reflected typed annotation.
EntryrecordA named or positional edge in the indexed semantic type graph.
ExtensionKeyinterfaceA typed identity for data derived lazily from a reflection descriptor, schema, or binding.
FieldrecordA visible field projected directly from the reflected root type.
FieldCodecrecordA keyed runtime codec materialized from a reflected record.
FieldCodecBlueprintrecordAn opaque field-codec recipe returned inside comptime.
InforecordAn immutable compile-time description of a resolved semantic type.
NoderecordA node in an Info semantic type graph.
SoAFieldrecordA top-level stored struct field available as a SoA column.
SoAInforecordTarget-independent semantic inputs to SoA storage derivation.

Functions

FunctionKindDescription
extensionKeyfunctionCreates an identity for a lazily derived metadata value.
fieldCodeccomptime functionBuilds a keyed field-codec recipe from a reflected record.
runtimefunctionReads the semantic description carried by a first-class type witness.
runtimeTypefunctionReads an available nominal witness reachable through stored fields or constructor parameters.

Types#

Annotationrecord#

record Annotation ...

A typed annotation application, retaining source order.

Members

NameKindDescription
namefield
argumentsfield

namefield#

name: string
@readonly

argumentsfield#

@readonly

AnnotationArgumentrecord#

record AnnotationArgument ...

A checked member supplied to a reflected typed annotation.

value is present for kind = "value"; type is an index into the owning Info.types graph for kind = "type". kind = "nil" preserves an explicitly supplied nil without pretending an absent table field contains it.

@annotation(targets = {"field"})
local record serialized
    name: string?
    @ref
    codec: any
end

local record StringCodec
end

local record User
    @serialized(name = "user_id", codec = StringCodec)
    id: integer
end

const Serialization: string = comptime do
    local info = nupp.reflect(User)
    local arguments = info.fields[1].annotations[1].arguments
    assert(arguments[1].kind == "value")
    assert(arguments[2].kind == "type")
    local codec = info.types[arguments[2].type as integer]
    return (arguments[1].value as string) .. ":" .. (codec.name as string)
end

assert(Serialization == "user_id:StringCodec")

Members

NameKindDescription
namefield
kindfield
valuefield
typefield

namefield#

name: string
@readonly

kindfield#

kind: "value" | "nil" | "type"
@readonly

valuefield#

value: any?
@readonly

typefield#

type: integer?
@readonly

Entryrecord#

record Entry ...

A named or positional edge in the indexed semantic type graph.

Members

NameKindDescription
namefield
typefield
readfield
writefield
storedfield
readablefield
writablefield
hasDefaultfield
defaultValuefield
modefield
boundfield
answerfield
defaultfield
annotationsfield

namefield#

name: string?
@readonly

typefield#

type: integer?
@readonly

readfield#

read: integer?
@readonly

writefield#

write: integer?
@readonly

storedfield#

stored: boolean?
@readonly

readablefield#

readable: boolean?
@readonly

writablefield#

writable: boolean?
@readonly

hasDefaultfield#

hasDefault: boolean?
@readonly

defaultValuefield#

defaultValue: any
@readonly

modefield#

mode: string?
@readonly

boundfield#

bound: integer?
@readonly

answerfield#

answer: integer?
@readonly

defaultfield#

default: boolean?
@readonly

annotationsfield#

annotations: {Annotation}?
@readonly

ExtensionKeyinterface#

interface ExtensionKey<T> ...

A typed identity for data derived lazily from a reflection descriptor, schema, or binding.

It has the shape of nupp.util.Key<T>, declared here because the prelude is read before any module is. _valueType is never present; it mentions T in both positions so that keys are invariant.

Type parameters

NameDescription
T

Members

NameKindDescription
idfield
namefield

idfield#

id: integer
@readonly

namefield#

name: string?
@readonly

Fieldrecord#

record Field ...

A visible field projected directly from the reflected root type.

The projection preserves declaration order, access capabilities, defaults, and annotations without requiring a lookup in Info.types. stored distinguishes stored fields, including callbacks, from methods.

local record Options
    format: string = "compact"
    retries: integer
end

const DefaultFormat: string = comptime do
    local field = nupp.reflect(Options).fields[1]
    assert(field.name == "format" and field.hasDefault)
    assert(field.readable and field.writable)
    return field.defaultValue as string
end

assert(DefaultFormat == "compact")

Members

NameKindDescription
namefield
kindfield
typeNamefield
typefield
storedfield
readablefield
writablefield
hasDefaultfield
defaultValuefield
annotationsfield

namefield#

name: string
@readonly

kindfield#

kind: string
@readonly

typeNamefield#

typeName: string?
@readonly

typefield#

type: integer?
@readonly

storedfield#

stored: boolean
@readonly

readablefield#

readable: boolean
@readonly

writablefield#

writable: boolean
@readonly

hasDefaultfield#

hasDefault: boolean
@readonly

defaultValuefield#

defaultValue: any
@readonly

annotationsfield#

annotations: {Annotation}
@readonly

FieldCodecrecord#

record FieldCodec<T> ...

A keyed runtime codec materialized from a reflected record.

encode copies present declared fields into a plain keyed table. decode selects the same fields from a keyed table and restores the record's runtime identity. Both operations are shallow. The stable fingerprint records the field names in declaration order.

local record Position
    x: number
    y: number
end

const PositionCodec: nupp.reflect.FieldCodec<Position> = comptime do
    return nupp.reflect.fieldCodec(nupp.reflect(Position))
end

local encoded = PositionCodec:encode(new Position(x = 3, y = 4))
assert(encoded.x == 3 and encoded.y == 4)
assert(PositionCodec.fingerprint == "t:x,y")

Type parameters

NameDescription
T

Members

NameKindDescription
encodemethod
decodemethod
fingerprintfield

encodemethod#

encode: function(self, value: T): {[string]: any}
Arguments
NameTypeDescription
?self
valueT
Returns
TypeDescription
{[string]: any}

decodemethod#

decode: function(self, value: {[string]: any}): (T?, string?)
Arguments
NameTypeDescription
?self
value{[string]: any}
Returns
TypeDescription
T?
string?

fingerprintfield#

fingerprint: string

FieldCodecBlueprintrecord#

record FieldCodecBlueprint

An opaque field-codec recipe returned inside comptime.

Inforecord#

record Info ...

An immutable compile-time description of a resolved semantic type.

Info can cross typed comptime helper boundaries. Its fingerprint is suitable for cache keys because it changes with the canonical type graph, defaults, and checked annotations rather than with compiler-local identities.

local record Pair
    left: string
    right: integer
end

@comptime local function describe(info: nupp.reflect.Info): string
    return info.fingerprint .. ":" .. tostring(#info.fields)
end

const PairDescription: string = comptime do
    return describe(nupp.reflect(Pair))
end

assert(PairDescription:match(":2$") ~= nil)

Members

NameKindDescription
schemafield
rootfield
typesfield
kindfield
namefield
qualifiedNamefield
fieldsfield
annotationsfield
soafield
fingerprintfield

schemafield#

schema: integer
@readonly

rootfield#

root: integer
@readonly

typesfield#

types: const{Node}
@readonly

kindfield#

kind: string
@readonly

namefield#

name: string
@readonly

qualifiedNamefield#

qualifiedName: string
@readonly

fieldsfield#

fields: const{Field}
@readonly

annotationsfield#

annotations: const{Annotation}
@readonly

soafield#

soa: const SoAInfo
@readonly

fingerprintfield#

fingerprint: string
@readonly

Noderecord#

record Node ...

A node in an Info semantic type graph.

Fields, parameters, results, union members, generic arguments, and wrappers point to other nodes by their integer index. Resolve only the edges relevant to the node's kind.

local type Handler = function(message: string, attempts: integer): boolean

const HandlerShape: string = comptime do
    local info = nupp.reflect(Handler)
    local handler = info.types[info.root]
    assert(handler.kind == "func")
    local first = (handler.parameters as {nupp.reflect.Entry})[1]
    local input = info.types[first.type as integer]
    local output = info.types[(handler.returns as {integer})[1]]
    return (first.name as string) .. ":" .. input.kind .. "->" .. output.kind
end

assert(HandlerShape == "message:string->boolean")

Members

NameKindDescription
copyablefieldWhether a nominal value has no ownership obligation or scoped borrow.
kindfield
namefield
nominalfield
annotationsfield
fieldsfield
staticFieldsfield
metamethodsfield
nestedTypesfield
associatedTypesfield
membersfield
parametersfield
returnsfield
typeParametersfield
typeBoundsfield
packParametersfield
constParametersfield
parameterKindsfield
typeArgumentsfield
packArgumentsfield
constArgumentsfield
supertypesfield
elementfield
bodyfield
offield
originfield
noReturnfield
noYieldfield

copyablefield#

copyable: boolean?
@readonly

Whether a nominal value has no ownership obligation or scoped borrow.

kindfield#

kind: string
@readonly

namefield#

name: string?
@readonly

nominalfield#

nominal: boolean?
@readonly

annotationsfield#

annotations: {Annotation}?
@readonly

fieldsfield#

@readonly

staticFieldsfield#

staticFields: {Entry}?
@readonly

metamethodsfield#

metamethods: {Entry}?
@readonly

nestedTypesfield#

nestedTypes: {Entry}?
@readonly

associatedTypesfield#

associatedTypes: {Entry}?
@readonly

membersfield#

members: {integer}?
@readonly

parametersfield#

@readonly

returnsfield#

returns: {integer}?
@readonly

typeParametersfield#

typeParameters: {integer}?
@readonly

typeBoundsfield#

typeBounds: {integer}?
@readonly

packParametersfield#

packParameters: {integer}?
@readonly

constParametersfield#

constParameters: {integer}?
@readonly

parameterKindsfield#

parameterKinds: {string}?
@readonly

typeArgumentsfield#

typeArguments: {integer}?
@readonly

packArgumentsfield#

packArguments: {integer}?
@readonly

constArgumentsfield#

constArguments: {integer}?
@readonly

supertypesfield#

supertypes: {integer}?
@readonly

elementfield#

element: integer?
@readonly

bodyfield#

body: integer?
@readonly

offield#

of: integer?
@readonly

originfield#

origin: integer?
@readonly

noReturnfield#

noReturn: boolean?
@readonly

noYieldfield#

noYield: boolean?
@readonly

SoAFieldrecord#

record SoAField ...

A top-level stored struct field available as a SoA column.

Members

NameKindDescription
namefield
identityfield
ordinalfield
typefield
ctypefield
eligiblefield

namefield#

name: string
@readonly

identityfield#

identity: string
@readonly

ordinalfield#

ordinal: integer
@readonly

typefield#

type: integer?
@readonly

ctypefield#

ctype: string?
@readonly

eligiblefield#

eligible: boolean
@readonly

SoAInforecord#

record SoAInfo ...

Target-independent semantic inputs to SoA storage derivation.

This says whether the declaration can be split into columns and identifies those columns. It deliberately does not contain target sizes or offsets; use nupp.mem.soa.layoutof for those.

local struct Particle
    x: float
    y: float
end

const ParticleColumns: string = comptime do
    local soa = nupp.reflect(Particle).soa
    assert(soa.eligible and #soa.fields == 2)
    assert(soa.fields[1].ordinal == 1)
    return soa.fields[1].name .. "," .. soa.fields[2].name
end

assert(ParticleColumns == "x,y")

Members

NameKindDescription
schemafield
eligiblefield
reasonfield
fieldsfield

schemafield#

schema: integer
@readonly

eligiblefield#

eligible: boolean
@readonly

reasonfield#

reason: string?
@readonly

fieldsfield#

@readonly

Functions#

extensionKeyfunction#

local extensionKey: function<T>(build: function(host: any): T): ExtensionKey<T>

Creates an identity for a lazily derived metadata value.

A descriptor, schema, or binding builds a key's value once, then returns the same value from its private cache. Key identities and their slot numbers are process-local and must not be persisted.

Type parameters

NameDescription
T

Arguments

NameTypeDescription
buildfunction(host: any): T

Returns

TypeDescription
ExtensionKey<T>

fieldCodeccomptime function#

local fieldCodec: @comptime function(info: Info): FieldCodecBlueprint

Builds a keyed field-codec recipe from a reflected record.

The opaque recipe must directly initialize a matching FieldCodec<Record> declaration. It may pass through typed comptime helpers on the way to that materialization boundary.

local record Message
    id: integer
    text: string
end

@comptime local function keyed(
    info: nupp.reflect.Info
): nupp.reflect.FieldCodecBlueprint
    return nupp.reflect.fieldCodec(info)
end

const MessageCodec: nupp.reflect.FieldCodec<Message> = comptime do
    return keyed(nupp.reflect(Message))
end

local encoded = MessageCodec:encode(new Message(id = 1, text = "hello"))
assert(encoded.id == 1 and encoded.text == "hello")

Arguments

NameTypeDescription
infoInfo

Returns

TypeDescription
FieldCodecBlueprint

runtimefunction#

local runtime: function<T>(typeObject: Type<T>): Info

Reads the semantic description carried by a first-class type witness. Generic consumers use the same descriptor as concrete callers.

Type parameters

NameDescription
T

Arguments

NameTypeDescription
typeObjectType<T>

Returns

TypeDescription
Info

runtimeTypefunction#

local runtimeType: function(info: Info, index: integer): Type<unknown>?

Reads an available nominal witness reachable through stored fields or constructor parameters. An unresolved forward declaration returns nil.

Arguments

NameTypeDescription
infoInfo
indexinteger

Returns

TypeDescription
Type<unknown>?