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 = 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 = 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
| Type | Kind | Description |
|---|---|---|
Annotation | record | One typed annotation application, retaining source order. |
AnnotationArgument | record | One checked member supplied to a reflected typed annotation. |
Entry | record | One named or positional edge in the indexed semantic type graph. |
ExtensionKey | interface | A typed identity for data derived lazily from a reflection descriptor, schema, or binding. |
Field | record | One stored field projected directly from the reflected root type. |
FieldCodec | record | A keyed runtime codec materialized from a reflected record. |
FieldCodecBlueprint | record | An opaque field-codec recipe returned inside comptime. |
Info | record | An immutable compile-time description of one resolved semantic type. |
Node | record | One node in an Info semantic type graph. |
SoAField | record | One top-level stored struct field available as a SoA column. |
SoAInfo | record | Target-independent semantic inputs to SoA storage derivation. |
Functions
| Function | Kind | Description |
|---|---|---|
extensionKey | function | Creates an identity for one lazily derived metadata value. |
fieldCodec | comptime function | Builds a keyed field-codec recipe from a reflected record. |
Types#
Annotationrecord#
record Annotation
readonly name: string
readonly arguments: {AnnotationArgument}
endOne typed annotation application, retaining source order.
Fields
arguments#
AnnotationArgumentrecord#
record AnnotationArgument
readonly name: string
readonly kind: "value" | "nil" | "type"
readonly value: any?
readonly type: integer?
endOne 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.
(targets = {"field"})
local record serialized
name: string?
codec: any
end
local record StringCodec
end
local record User
(name = "user_id", codec = StringCodec)
id: integer
end
const Serialization: string = 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")Fields
kind#
kind: "value" | "nil" | "type"type#
type: integer?Entryrecord#
record Entry
readonly name: string?
readonly type: integer?
readonly read: integer?
readonly write: integer?
readonly readable: boolean?
readonly writable: boolean?
readonly hasDefault: boolean?
readonly defaultValue: any
readonly mode: string?
readonly bound: integer?
readonly answer: integer?
readonly default: boolean?
readonly annotations: {Annotation}?
readonly [string]: any
endOne named or positional edge in the indexed semantic type graph.
Fields
type#
type: integer?readable#
readable: boolean?writable#
writable: boolean?hasDefault#
hasDefault: boolean?mode#
mode: string?bound#
bound: integer?answer#
answer: integer?default#
default: boolean?annotations#
annotations: {Annotation}?ExtensionKeyinterface#
A typed identity for data derived lazily from a reflection descriptor, schema, or binding.
It has the shape of nupp.store.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
| Name | Description |
|---|---|
T |
Fields
Fieldrecord#
record Field
readonly name: string
readonly kind: string
readonly typeName: string?
readonly type: integer?
readonly readable: boolean
readonly writable: boolean
readonly hasDefault: boolean
readonly defaultValue: any
readonly annotations: {Annotation}
endOne stored 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.
local record Options
format: string = "compact"
retries: integer
end
const DefaultFormat: string = 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")Fields
kind#
kind: stringtypeName#
typeName: string?type#
type: integer?readable#
readable: booleanwritable#
writable: booleanhasDefault#
hasDefault: booleanannotations#
annotations: {Annotation}FieldCodecrecord#
record FieldCodec<T>
encode: function(self, value: T): {[string]: any}
decode: function(self, value: {[string]: any}): (T?, string?)
fingerprint: string
endA keyed runtime codec materialized from a reflected record.
encode copies present declared fields into a plain keyed table. The stable fingerprint records the field names in declaration order.
local record Position
x: number
y: number
end
const PositionCodec: nupp.reflect.FieldCodec<Position> = 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
| Name | Description |
|---|---|
T |
Methods
Fields
fingerprint#
fingerprint: stringFieldCodecBlueprintrecord#
record FieldCodecBlueprint
endAn opaque field-codec recipe returned inside comptime.
Inforecord#
record Info
readonly schema: integer
readonly root: integer
readonly types: {Node}
readonly kind: string
readonly name: string
readonly qualifiedName: string
readonly fields: {Field}
readonly annotations: {Annotation}
readonly soa: SoAInfo
readonly fingerprint: string
endAn immutable compile-time description of one 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
local function describe(info: nupp.reflect.Info): string
return info.fingerprint .. ":" .. tostring(#info.fields)
end
const PairDescription: string = do
return describe(nupp.reflect(Pair))
end
assert(PairDescription:match(":2$") ~= nil)Fields
schema#
schema: integerroot#
root: integerkind#
kind: stringqualifiedName#
qualifiedName: stringannotations#
annotations: {Annotation}fingerprint#
fingerprint: stringNoderecord#
record Node
readonly kind: string
readonly name: string?
readonly nominal: boolean?
readonly annotations: {Annotation}?
readonly fields: {Entry}?
readonly staticFields: {Entry}?
readonly metamethods: {Entry}?
readonly nestedTypes: {Entry}?
readonly associatedTypes: {Entry}?
readonly members: {integer}?
readonly parameters: {Entry}?
readonly returns: {integer}?
readonly typeParameters: {integer}?
readonly typeBounds: {integer}?
readonly packParameters: {integer}?
readonly constParameters: {integer}?
readonly parameterKinds: {string}?
readonly typeArguments: {integer}?
readonly packArguments: {integer}?
readonly constArguments: {integer}?
readonly supertypes: {integer}?
readonly element: integer?
readonly body: integer?
readonly of: integer?
readonly origin: integer?
readonly noReturn: boolean?
readonly noYield: boolean?
readonly [string]: any
endOne 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 = 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")Fields
kind#
kind: stringnominal#
nominal: boolean?annotations#
annotations: {Annotation}?members#
members: {integer}?parameters#
parameters: {Entry}?returns#
returns: {integer}?typeParameters#
typeParameters: {integer}?typeBounds#
typeBounds: {integer}?packParameters#
packParameters: {integer}?constParameters#
constParameters: {integer}?parameterKinds#
parameterKinds: {string}?typeArguments#
typeArguments: {integer}?packArguments#
packArguments: {integer}?constArguments#
constArguments: {integer}?supertypes#
supertypes: {integer}?element#
element: integer?body#
body: integer?origin#
origin: integer?noReturn#
noReturn: boolean?noYield#
noYield: boolean?SoAFieldrecord#
record SoAField
readonly name: string
readonly identity: string
readonly ordinal: integer
readonly type: integer?
readonly ctype: string?
readonly eligible: boolean
endOne top-level stored struct field available as a SoA column.
Fields
identity#
identity: stringordinal#
ordinal: integertype#
type: integer?ctype#
ctype: string?eligible#
eligible: booleanSoAInforecord#
record SoAInfo
readonly schema: integer
readonly eligible: boolean
readonly reason: string?
readonly fields: {SoAField}
endTarget-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 = 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")Fields
schema#
schema: integereligible#
eligible: booleanFunctions#
extensionKeyfunction#
local extensionKey: function<T>(build: function(host: any): T): ExtensionKey<T>Creates an identity for one lazily derived metadata value.
A descriptor, schema, or binding builds a key's value once, then answers the same value from its private cache. Key identities and their slot numbers are process-local and must not be persisted.
Type parameters
| Name | Description |
|---|---|
T |
Arguments
| Name | Type | Description |
|---|---|---|
build | function(host: any): T |
Returns
| Type | Description |
|---|---|
ExtensionKey<T> |
fieldCodeccomptime function#
local fieldCodec: function(info: Info): FieldCodecBlueprintBuilds 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
local function keyed(
info: nupp.reflect.Info
): nupp.reflect.FieldCodecBlueprint
return nupp.reflect.fieldCodec(info)
end
const MessageCodec: nupp.reflect.FieldCodec<Message> = 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
| Name | Type | Description |
|---|---|---|
info | Info |
Returns
| Type | Description |
|---|---|
FieldCodecBlueprint |