1use crate::{
7 Type,
8 ast::Item,
9 catalog::{BuiltinDefinition, ExampleSpec, MemberDoc},
10 parse,
11};
12use std::{collections::BTreeMap, sync::OnceLock};
13
14#[derive(Clone, Copy, Debug)]
17pub struct FunctionDescriptor {
18 pub name: &'static str,
20 pub category: &'static str,
22 pub declaration: &'static str,
24 pub docs: &'static str,
26 pub status: &'static str,
28 pub members: &'static [MemberDoc],
30 pub examples: &'static [ExampleSpec],
32 pub rust_path: &'static str,
34 pub representation: &'static str,
36 pub monomorphic: bool,
39}
40
41impl FunctionDescriptor {
42 fn definition(self) -> BuiltinDefinition {
43 BuiltinDefinition {
44 name: self.name,
45 category: self.category,
46 kind: "func",
47 declaration: self.declaration,
48 docs: self.docs,
49 status: self.status,
50 members: self.members,
51 examples: self.examples,
52 rust_path: self.rust_path,
53 representation: self.representation,
54 }
55 }
56}
57
58macro_rules! native_functions {
59 ($(
60 $(#[doc = $doc:expr])*
61 $constant:ident {
62 name: $name:literal,
63 category: $category:literal,
64 declaration: $declaration:expr,
65 status: $status:literal,
66 details: $details:literal,
67 members: $members:expr,
68 examples: &[$(ExampleSpec {
69 title: $title:literal, description: $example_description:literal,
70 source: $source:literal, output: &[$($output:literal),* $(,)?],
71 ticks: $ticks:literal, presentation: $presentation:literal
72 }),* $(,)?],
73 representation: $representation:literal,
74 monomorphic: $monomorphic:literal,
75 }
76 )*) => {
77 $(
78 $(#[doc = $doc])*
79 #[doc = concat!("\n\n", $details)]
80 #[doc = concat!("\n\n# Signature\n\n```text\nfunc ", $name, $declaration, "\n```\n")]
81 $(#[doc = concat!("\n# ", $title, "\n\n", $example_description, "\n\n```text\n", $source, "\n```\n")])*
82 pub const $constant: FunctionDescriptor = FunctionDescriptor {
83 name: $name,
84 category: $category,
85 declaration: concat!("func ", $name, $declaration),
86 docs: concat!($($doc, "\n"),*, "\n", $details),
87 status: $status,
88 members: $members,
89 examples: &[$(ExampleSpec {
90 title: $title, description: $example_description, source: $source,
91 output: &[$($output),*], ticks: $ticks, presentation: $presentation,
92 }),*],
93 rust_path: concat!("/sdk/rust/konjure_lang/catalog/functions/constant.", stringify!($constant), ".html"),
94 representation: $representation,
95 monomorphic: $monomorphic,
96 };
97 )*
98
99 pub const BUILTIN_NAMES: &[&str] = &[$($name),*];
104 const FUNCTIONS: &[FunctionDescriptor] = &[$($constant),*];
105 };
106}
107
108native_functions! {
109 SPAWN {
111 name: "spawn", category: "Entities", declaration: "(component: C) -> Entity", status: "runtime", details: " The C placeholder means one concrete type value, never a trait or primitive. Entity creation is bounded and rejected when the machine has no remaining entity capacity.",
112 members: &[MemberDoc { name: "component", docs: "A constructed type value; traits and primitive values are rejected." }, MemberDoc { name: "return", docs: "The new Entity identity." }],
113 examples: &[ExampleSpec { title: "Create an entity", description: "A spawned component receives the first entity identity.", source: "let entity = spawn(Vec3 {});\nprint(entity);", output: &["entity(1)"], ticks: 0, presentation: "snippet" }],
114 representation: "Rust interpreter builtin dispatch; Type is specialized from a concrete type argument.", monomorphic: false,
115 }
116 ADD {
118 name: "add", category: "Entities", declaration: "(entity: Entity, component: C) -> Unit", status: "runtime", details: " C means a concrete type value. Adding a component that the entity already owns, or addressing a missing entity, rejects the current transaction.",
119 members: &[MemberDoc { name: "entity", docs: "An existing entity identity." }, MemberDoc { name: "component", docs: "A type value whose type is not already attached." }, MemberDoc { name: "return", docs: "Unit after the component update is accepted." }],
120 examples: &[ExampleSpec { title: "Add a component", description: "A new Sphere component becomes queryable on the entity.", source: "let entity = spawn(Vec3 {});\nadd(entity, Sphere {});\nprint(has[Sphere](entity));", output: &["true"], ticks: 0, presentation: "snippet" }],
121 representation: "Rust interpreter builtin dispatch; Type is specialized from the concrete component type.", monomorphic: false,
122 }
123 GET {
125 name: "get", category: "Entities", declaration: "[C](entity: Entity) -> C", status: "runtime", details: " C means a concrete type selector. The result is a component copy; update the live entity with set, or use a system binding or `bind[C](entity)` method callback for persistent mutation.",
126 members: &[MemberDoc { name: "entity", docs: "An entity that has the selected concrete type component." }, MemberDoc { name: "return", docs: "A copy of component C." }],
127 examples: &[ExampleSpec { title: "Select a component", description: "The explicit selector fixes the component type for a function value.", source: "type Counter { value: Number = 2; }\nlet entity = spawn(Counter {});\nlet read: func(Entity) -> Counter = get[Counter];\nprint(read(entity).value);", output: &["2"], ticks: 0, presentation: "snippet" }],
128 representation: "Rust interpreter builtin dispatch; C must name a concrete type and is checked during specialization.", monomorphic: false,
129 }
130 SET {
132 name: "set", category: "Entities", declaration: "(entity: Entity, component: C) -> Unit", status: "runtime", details: " C means a concrete type value. set requires that component to exist already and replaces it atomically; use add for a new component.",
133 members: &[MemberDoc { name: "entity", docs: "An entity that already has the component type." }, MemberDoc { name: "component", docs: "The replacement type value." }, MemberDoc { name: "return", docs: "Unit after the replacement is accepted." }],
134 examples: &[ExampleSpec { title: "Replace a component", description: "set updates an already attached component.", source: "let entity = spawn(Vec3 {});\nset(entity, Vec3 { x: 2 });\nprint(get[Vec3](entity).x);", output: &["2"], ticks: 0, presentation: "snippet" }],
135 representation: "Rust interpreter builtin dispatch; Type is specialized from the concrete component type.", monomorphic: false,
136 }
137 HAS {
139 name: "has", category: "Entities", declaration: "[C](entity: Entity) -> Bool", status: "runtime", details: " C means a concrete type selector. The result observes the entity's current component set and rejects an unknown entity rather than inventing absence.",
140 members: &[MemberDoc { name: "entity", docs: "An existing entity identity." }, MemberDoc { name: "return", docs: "True when the entity has component C." }],
141 examples: &[ExampleSpec { title: "Test component presence", description: "The selector is required when the function value would otherwise not identify C.", source: "type Counter {}\nlet entity = spawn(Counter {});\nlet present: func(Entity) -> Bool = has[Counter];\nprint(present(entity));", output: &["true"], ticks: 0, presentation: "snippet" }],
142 representation: "Rust interpreter builtin dispatch; C must name a concrete type and is checked during specialization.", monomorphic: false,
143 }
144 QUERY {
146 name: "query", category: "Entities", declaration: "[C]() -> List[Entity]", status: "runtime", details: " C means a concrete type or trait selector. The returned entity handles are ordered by creation and are a snapshot value; later lifecycle changes do not mutate the returned list.",
147 members: &[MemberDoc { name: "return", docs: "Matching entities in stable creation order." }],
148 examples: &[ExampleSpec { title: "Query matching entities", description: "The selector makes the query function value concrete.", source: "type Counter {}\nspawn(Counter {});\nlet find: func() -> List[Entity] = query[Counter];\nprint(find().len());", output: &["1"], ticks: 0, presentation: "snippet" }],
149 representation: "Rust interpreter builtin dispatch; C is a checked concrete type or trait selector.", monomorphic: false,
150 }
151 DESPAWN {
153 name: "despawn", category: "Entities", declaration: "(entity: Entity) -> Unit", status: "runtime", details: " The entity must exist. Removal is deferred until the enclosing initializer, callback, or action completes so checked work sees a consistent world.",
154 members: &[MemberDoc { name: "entity", docs: "An existing entity identity." }, MemberDoc { name: "return", docs: "Unit; removal is deferred to preserve transactional execution." }],
155 examples: &[ExampleSpec { title: "Schedule removal", description: "The current value remains printable while removal is pending.", source: "let entity = spawn(Vec3 {});\ndespawn(entity);\nprint(entity);", output: &["entity(1)"], ticks: 0, presentation: "snippet" }],
156 representation: "Rust interpreter builtin dispatch; Type is func(Entity) -> Unit.", monomorphic: true,
157 }
158 PRINT {
160 name: "print", category: "Values", declaration: "(value: T) -> Unit", status: "runtime", details: " Rendering must fit the machine string bound. Logs are a bounded ring buffer: when full, the oldest retained line is discarded, and no external I/O occurs.",
161 members: &[MemberDoc { name: "value", docs: "Any checked value whose rendered log text fits the machine string limit." }, MemberDoc { name: "return", docs: "Unit after the bounded log update." }],
162 examples: &[ExampleSpec { title: "Record a value", description: "print writes the interpreter log.", source: "print(\"hello\");", output: &["hello"], ticks: 0, presentation: "snippet" }],
163 representation: "Rust interpreter builtin dispatch; polymorphic calls and function values are checked from their concrete context.", monomorphic: false,
164 }
165 RANGE { name: "range", category: "Collections", declaration: "(end: Number) -> Res[List[Number], DataError]\nfunc range(start: Number, end: Number) -> Res[List[Number], DataError]", status: "runtime", details: " Each bound must be finite, integral, and exactly representable from -9007199254740991 through 9007199254740991. End is exclusive; descending bounds produce an empty list. Invalid endpoints return DataError; a host resource limit remains a Diagnostic.", members: &[MemberDoc { name: "start", docs: "Exactly representable finite integer from -9007199254740991 through 9007199254740991; omitted start is zero." }, MemberDoc { name: "end", docs: "Exactly representable finite integer from -9007199254740991 through 9007199254740991; it is exclusive." }, MemberDoc { name: "return", docs: "Ok(List[Number]) for valid endpoints, Err(DataError) for invalid numeric endpoints. A host resource limit rejects execution diagnostically." }], examples: &[ExampleSpec { title: "Range from zero", description: "One bound starts at zero.", source: "print(range(3)?.len());", output: &["3"], ticks: 0, presentation: "snippet" }, ExampleSpec { title: "Range with bounds", description: "The start is inclusive and end is exclusive.", source: "print(range(2, 5)?.len());", output: &["3"], ticks: 0, presentation: "snippet" }], representation: "Rust interpreter builtin dispatch; one- and two-argument Number overloads return Res[List[Number], DataError] for invalid numeric endpoints.", monomorphic: false, }
167 NOOP { name: "noop", category: "Values", declaration: "() -> Res[Unit, DataError]", status: "runtime", details: " It is a concrete function value, so it can be stored in Button.action without a string callback name or a host effect.", members: &[MemberDoc { name: "return", docs: "Ok(Unit) without a state change." }], examples: &[ExampleSpec { title: "Default action", description: "noop is assignable to a zero-argument recoverable callback.", source: "let action: func() -> Res[Unit, DataError] = noop;\naction()?;", output: &[], ticks: 0, presentation: "snippet" }], representation: "Rust interpreter builtin dispatch; Type is func() -> Res[Unit, DataError].", monomorphic: true, }
169 IGNORE_NUMBER { name: "ignore_number", category: "Values", declaration: "(value: Number) -> Res[Unit, DataError]", status: "runtime", details: " It is a concrete function value for Slider.action. The Number is checked then discarded, with no scene or host state update.", members: &[MemberDoc { name: "value", docs: "A Number accepted without a state change." }, MemberDoc { name: "return", docs: "Ok(Unit)." }], examples: &[ExampleSpec { title: "Default slider action", description: "ignore_number has the Slider callback type.", source: "let action: func(Number) -> Res[Unit, DataError] = ignore_number;\naction(0.5)?;", output: &[], ticks: 0, presentation: "snippet" }], representation: "Rust interpreter builtin dispatch; Type is func(Number) -> Res[Unit, DataError].", monomorphic: true, }
171 BIND { name: "bind", category: "Entities", declaration: "[C](entity: Entity) -> ComponentReference[C]", status: "runtime", details: " C means a concrete type selector, never a trait. The reference owns an entity and component identity; extracted mutating methods commit back transactionally and fail if the component is unavailable.", members: &[MemberDoc { name: "entity", docs: "An entity with the selected concrete type component." }, MemberDoc { name: "return", docs: "A ComponentReference[C] whose mutating extracted methods write back to that entity." }], examples: &[ExampleSpec { title: "Bind a live component", description: "A bound mutating method commits its component update.", source: "type Counter { value: Number = 0; func advance() -> Res[Unit, DataError] { self.value = (self.value + 1)?; ret Ok(()); } }\nlet entity = spawn(Counter {});\nlet reference = bind[Counter](entity);\nlet advance = reference.advance;\nadvance()?;\nprint(get[Counter](entity).value);", output: &["1"], ticks: 0, presentation: "snippet" }], representation: "Rust interpreter builtin dispatch; C must name a concrete type and produces ComponentReference[C] for typed function values.", monomorphic: false, }
173 TENSOR {
175 name: "tensor", category: "Collections", declaration: "[T](values: List[T], dimensions: List[Number]) -> Res[Tensor[T], DataError]", status: "runtime",
176 details: "T is a numeric dtype. Values are row-major and their count must equal the checked product of the dimensions. Invalid shapes return Err(DataError). Host byte and execution limits reject execution before allocation.",
177 members: &[MemberDoc { name: "values", docs: "Flat elements of the selected dtype; literals inherit T." }, MemberDoc { name: "dimensions", docs: "Nonnegative integer dimensions in row-major axis order; [] constructs a rank-zero scalar from one value." }, MemberDoc { name: "return", docs: "Ok(Tensor[T]) with packed storage, or Err(DataError) for invalid dimensions or an element-count mismatch." }],
178 examples: &[ExampleSpec { title: "Constructs packed numeric data with explicit dimensions", description: "Run the example, then change the data and inspect the result.", source: "let samples = tensor[f32]([1, 2, 3, 4], [2, 2])?;\nprint(samples[1, 0]?);", output: &["3"], ticks: 0, presentation: "snippet" }],
179 representation: "Rust SDK data primitives; the language checker specializes the same runtime operation.", monomorphic: false,
180 }
181 BYTES {
183 name: "bytes", category: "Values", declaration: "(values: List[u8]) -> Bin", status: "runtime",
184 details: "Each element is a u8, so out-of-range literal bytes are compile errors. The Bin owns shared immutable storage and has no text encoding until decoded explicitly.",
185 members: &[MemberDoc { name: "values", docs: "Unsigned 8-bit values; list literals inherit u8." }, MemberDoc { name: "return", docs: "Immutable packed bytes." }],
186 examples: &[ExampleSpec { title: "Builds immutable bytes from checked unsigned 8-bit values", description: "Run the example, then change the data and inspect the result.", source: "let payload: Bin = bytes([65, 66]);\nprint(payload.decode()?);", output: &["AB"], ticks: 0, presentation: "snippet" }],
187 representation: "Rust SDK data primitives; the language checker specializes the same runtime operation.", monomorphic: true,
188 }
189}
190
191pub(crate) fn definitions() -> Vec<BuiltinDefinition> {
194 FUNCTIONS
195 .iter()
196 .copied()
197 .map(FunctionDescriptor::definition)
198 .collect()
199}
200
201pub(crate) fn monomorphic_signature(name: &str) -> Option<Type> {
203 static SIGNATURES: OnceLock<BTreeMap<&'static str, Type>> = OnceLock::new();
204 SIGNATURES
205 .get_or_init(|| {
206 FUNCTIONS
207 .iter()
208 .filter(|descriptor| descriptor.monomorphic)
209 .map(|descriptor| {
210 let source = format!("trait Signature {{ {}; }}", descriptor.declaration);
211 let items = parse(&source, "builtin")
212 .expect("monomorphic builtin declaration must parse");
213 let [Item::Trait(contract)] = items.as_slice() else {
214 panic!("monomorphic builtin declaration must be a trait method");
215 };
216 let [function] = contract.methods.as_slice() else {
217 panic!("monomorphic builtin declaration must have one overload");
218 };
219 (
220 descriptor.name,
221 Type::function(
222 function
223 .parameters
224 .iter()
225 .map(|parameter| parameter.ty.clone())
226 .collect(),
227 function.returns.clone(),
228 ),
229 )
230 })
231 .collect()
232 })
233 .get(name)
234 .cloned()
235}