1use crate::metadata::{FunctionCategory, FunctionInfo, ParameterInfo, PropertyInfo};
7
8#[derive(Clone, Debug)]
12pub struct BuiltinMetadata {
13 pub name: &'static str,
15 pub signature: &'static str,
17 pub description: &'static str,
19 pub category: &'static str,
21 pub parameters: &'static [BuiltinParam],
23 pub return_type: &'static str,
25 pub example: Option<&'static str>,
27}
28
29#[derive(Clone, Debug)]
31pub struct BuiltinParam {
32 pub name: &'static str,
34 pub param_type: &'static str,
36 pub optional: bool,
38 pub description: &'static str,
40}
41
42#[derive(Clone, Debug)]
44pub struct TypeMetadata {
45 pub name: &'static str,
47 pub description: &'static str,
49 pub properties: &'static [PropertyMetadata],
51}
52
53#[derive(Clone, Debug)]
55pub struct PropertyMetadata {
56 pub name: &'static str,
58 pub prop_type: &'static str,
60 pub description: &'static str,
62}
63
64impl TypeMetadata {
65 pub fn to_property_infos(&self) -> Vec<PropertyInfo> {
67 self.properties
68 .iter()
69 .map(|p| PropertyInfo {
70 name: p.name.to_string(),
71 property_type: p.prop_type.to_string(),
72 description: p.description.to_string(),
73 })
74 .collect()
75 }
76}
77
78impl From<&BuiltinMetadata> for FunctionInfo {
79 fn from(meta: &BuiltinMetadata) -> Self {
80 let category = match meta.category {
81 "Simulation" => FunctionCategory::Simulation,
82 "Math" => FunctionCategory::Math,
83 "Vec" => FunctionCategory::Array,
84 "Column" => FunctionCategory::Column,
85 "Statistics" => FunctionCategory::Statistics,
86 "Data" => FunctionCategory::Data,
87 _ => FunctionCategory::Utility,
88 };
89
90 FunctionInfo {
91 name: meta.name.to_string(),
92 signature: meta.signature.to_string(),
93 description: meta.description.to_string(),
94 category,
95 parameters: meta
96 .parameters
97 .iter()
98 .map(|p| ParameterInfo {
99 name: p.name.to_string(),
100 param_type: p.param_type.to_string(),
101 optional: p.optional,
102 description: p.description.to_string(),
103 constraints: None, })
105 .collect(),
106 return_type: meta.return_type.to_string(),
107 example: meta.example.map(|s| s.to_string()),
108 implemented: true,
109 comptime_only: meta.category == "Comptime",
110 }
111 }
112}
113
114static CORE_BUILTINS: &[BuiltinMetadata] = &[
120 BuiltinMetadata {
122 name: "abs",
123 signature: "abs(value: number) -> number",
124 description: "Return the absolute value of a number.",
125 category: "Math",
126 parameters: &[BuiltinParam {
127 name: "value",
128 param_type: "number",
129 optional: false,
130 description: "Input value",
131 }],
132 return_type: "number",
133 example: Some("abs(-5) // 5"),
134 },
135 BuiltinMetadata {
136 name: "sqrt",
137 signature: "sqrt(value: number) -> number",
138 description: "Return the square root of a number.",
139 category: "Math",
140 parameters: &[BuiltinParam {
141 name: "value",
142 param_type: "number",
143 optional: false,
144 description: "Input value",
145 }],
146 return_type: "number",
147 example: Some("sqrt(16) // 4"),
148 },
149 BuiltinMetadata {
150 name: "pow",
151 signature: "pow(base: number, exponent: number) -> number",
152 description: "Raise base to the power of exponent.",
153 category: "Math",
154 parameters: &[
155 BuiltinParam {
156 name: "base",
157 param_type: "number",
158 optional: false,
159 description: "Base value",
160 },
161 BuiltinParam {
162 name: "exponent",
163 param_type: "number",
164 optional: false,
165 description: "Exponent",
166 },
167 ],
168 return_type: "number",
169 example: Some("pow(2, 3) // 8"),
170 },
171 BuiltinMetadata {
172 name: "log",
173 signature: "log(value: number) -> number",
174 description: "Return the natural logarithm of a number.",
175 category: "Math",
176 parameters: &[BuiltinParam {
177 name: "value",
178 param_type: "number",
179 optional: false,
180 description: "Input value",
181 }],
182 return_type: "number",
183 example: Some("log(2.718) // ~1.0"),
184 },
185 BuiltinMetadata {
186 name: "exp",
187 signature: "exp(value: number) -> number",
188 description: "Return e raised to the power of value.",
189 category: "Math",
190 parameters: &[BuiltinParam {
191 name: "value",
192 param_type: "number",
193 optional: false,
194 description: "Exponent",
195 }],
196 return_type: "number",
197 example: Some("exp(1) // ~2.718"),
198 },
199 BuiltinMetadata {
200 name: "floor",
201 signature: "floor(value: number) -> number",
202 description: "Round down to the nearest integer.",
203 category: "Math",
204 parameters: &[BuiltinParam {
205 name: "value",
206 param_type: "number",
207 optional: false,
208 description: "Input value",
209 }],
210 return_type: "number",
211 example: Some("floor(3.7) // 3"),
212 },
213 BuiltinMetadata {
214 name: "ceil",
215 signature: "ceil(value: number) -> number",
216 description: "Round up to the nearest integer.",
217 category: "Math",
218 parameters: &[BuiltinParam {
219 name: "value",
220 param_type: "number",
221 optional: false,
222 description: "Input value",
223 }],
224 return_type: "number",
225 example: Some("ceil(3.2) // 4"),
226 },
227 BuiltinMetadata {
228 name: "round",
229 signature: "round(value: number, decimals?: number) -> number",
230 description: "Round a number to the specified number of decimal places.",
231 category: "Math",
232 parameters: &[
233 BuiltinParam {
234 name: "value",
235 param_type: "number",
236 optional: false,
237 description: "Input value",
238 },
239 BuiltinParam {
240 name: "decimals",
241 param_type: "number",
242 optional: true,
243 description: "Decimal places (default 0)",
244 },
245 ],
246 return_type: "number",
247 example: Some("round(3.456, 2) // 3.46"),
248 },
249 BuiltinMetadata {
250 name: "max",
251 signature: "max(a: number, b: number) -> number",
252 description: "Return the larger of two numbers.",
253 category: "Math",
254 parameters: &[
255 BuiltinParam {
256 name: "a",
257 param_type: "number",
258 optional: false,
259 description: "First value",
260 },
261 BuiltinParam {
262 name: "b",
263 param_type: "number",
264 optional: false,
265 description: "Second value",
266 },
267 ],
268 return_type: "number",
269 example: Some("max(3, 7) // 7"),
270 },
271 BuiltinMetadata {
272 name: "min",
273 signature: "min(a: number, b: number) -> number",
274 description: "Return the smaller of two numbers.",
275 category: "Math",
276 parameters: &[
277 BuiltinParam {
278 name: "a",
279 param_type: "number",
280 optional: false,
281 description: "First value",
282 },
283 BuiltinParam {
284 name: "b",
285 param_type: "number",
286 optional: false,
287 description: "Second value",
288 },
289 ],
290 return_type: "number",
291 example: Some("min(3, 7) // 3"),
292 },
293 BuiltinMetadata {
295 name: "print",
296 signature: "print(...values) -> ()",
297 description: "Print values to output. Supports string interpolation and meta format functions.",
298 category: "Utility",
299 parameters: &[BuiltinParam {
300 name: "values",
301 param_type: "any",
302 optional: false,
303 description: "Values to print",
304 }],
305 return_type: "()",
306 example: Some("print(\"hello\", x)"),
307 },
308 BuiltinMetadata {
309 name: "range",
310 signature: "range(start, end, step?) -> Vec<number>",
311 description: "Generate an array of numbers from start to end.",
312 category: "Utility",
313 parameters: &[
314 BuiltinParam {
315 name: "start",
316 param_type: "number",
317 optional: false,
318 description: "Start value",
319 },
320 BuiltinParam {
321 name: "end",
322 param_type: "number",
323 optional: false,
324 description: "End value (exclusive)",
325 },
326 BuiltinParam {
327 name: "step",
328 param_type: "number",
329 optional: true,
330 description: "Step size (default 1)",
331 },
332 ],
333 return_type: "Vec<number>",
334 example: Some("range(0, 5) // [0, 1, 2, 3, 4]"),
335 },
336 BuiltinMetadata {
339 name: "avg",
340 signature: "avg(collection, value: number) -> number",
341 description: "Compute the average of values in a collection.",
342 category: "Statistics",
343 parameters: &[
344 BuiltinParam {
345 name: "collection",
346 param_type: "any",
347 optional: false,
348 description: "Input collection",
349 },
350 BuiltinParam {
351 name: "value",
352 param_type: "number",
353 optional: false,
354 description: "Value to average",
355 },
356 ],
357 return_type: "number",
358 example: Some("avg(items, row => row.price)"),
359 },
360 BuiltinMetadata {
361 name: "sum",
362 signature: "sum(table: Table<any>) -> number",
363 description: "Compute the sum of all values in a series.",
364 category: "Statistics",
365 parameters: &[BuiltinParam {
366 name: "series",
367 param_type: "Table<any>",
368 optional: false,
369 description: "Input series",
370 }],
371 return_type: "number",
372 example: Some("sum(volumes)"),
373 },
374 BuiltinMetadata {
375 name: "mean",
376 signature: "mean(table: Table<any>) -> number",
377 description: "Compute the mean of all values in a series.",
378 category: "Statistics",
379 parameters: &[BuiltinParam {
380 name: "series",
381 param_type: "Table<any>",
382 optional: false,
383 description: "Input series",
384 }],
385 return_type: "number",
386 example: Some("mean(prices)"),
387 },
388 BuiltinMetadata {
389 name: "stddev",
390 signature: "stddev(values) -> number",
391 description: "Compute the standard deviation.",
392 category: "Statistics",
393 parameters: &[BuiltinParam {
394 name: "values",
395 param_type: "any",
396 optional: false,
397 description: "Input values",
398 }],
399 return_type: "number",
400 example: Some("stddev(returns)"),
401 },
402 BuiltinMetadata {
403 name: "count",
404 signature: "count(array: Vec) -> number",
405 description: "Count the number of elements in an array.",
406 category: "Vec",
407 parameters: &[BuiltinParam {
408 name: "array",
409 param_type: "Vec",
410 optional: false,
411 description: "Input array",
412 }],
413 return_type: "number",
414 example: Some("count(items)"),
415 },
416 BuiltinMetadata {
417 name: "highest",
418 signature: "highest(collection, count: number) -> number",
419 description: "Return the highest value from a collection.",
420 category: "Vec",
421 parameters: &[
422 BuiltinParam {
423 name: "collection",
424 param_type: "any",
425 optional: false,
426 description: "Input collection",
427 },
428 BuiltinParam {
429 name: "count",
430 param_type: "number",
431 optional: false,
432 description: "Number of values",
433 },
434 ],
435 return_type: "number",
436 example: Some("highest(prices, 10)"),
437 },
438 BuiltinMetadata {
439 name: "lowest",
440 signature: "lowest(collection, count: number) -> number",
441 description: "Return the lowest value from a collection.",
442 category: "Vec",
443 parameters: &[
444 BuiltinParam {
445 name: "collection",
446 param_type: "any",
447 optional: false,
448 description: "Input collection",
449 },
450 BuiltinParam {
451 name: "count",
452 param_type: "number",
453 optional: false,
454 description: "Number of values",
455 },
456 ],
457 return_type: "number",
458 example: Some("lowest(prices, 10)"),
459 },
460 BuiltinMetadata {
462 name: "format",
463 signature: "format(value, template) -> string",
464 description: "Format a value using a template string.",
465 category: "Utility",
466 parameters: &[
467 BuiltinParam {
468 name: "value",
469 param_type: "any",
470 optional: false,
471 description: "Value to format",
472 },
473 BuiltinParam {
474 name: "template",
475 param_type: "any",
476 optional: false,
477 description: "Format template",
478 },
479 ],
480 return_type: "string",
481 example: Some("format(0.15, \"percent\") // \"15%\""),
482 },
483 BuiltinMetadata {
484 name: "format_percent",
485 signature: "format_percent(value) -> string",
486 description: "Format a number as a percentage string.",
487 category: "Utility",
488 parameters: &[BuiltinParam {
489 name: "value",
490 param_type: "number",
491 optional: false,
492 description: "Decimal value",
493 }],
494 return_type: "string",
495 example: Some("format_percent(0.15) // \"15%\""),
496 },
497 BuiltinMetadata {
498 name: "format_number",
499 signature: "format_number(value, decimals?) -> string",
500 description: "Format a number with optional decimal places.",
501 category: "Utility",
502 parameters: &[
503 BuiltinParam {
504 name: "value",
505 param_type: "number",
506 optional: false,
507 description: "Number to format",
508 },
509 BuiltinParam {
510 name: "decimals",
511 param_type: "number",
512 optional: true,
513 description: "Decimal places",
514 },
515 ],
516 return_type: "string",
517 example: Some("format_number(1234.5, 2) // \"1234.50\""),
518 },
519 BuiltinMetadata {
521 name: "shift",
522 signature: "shift(table: Table<any>, periods: number) -> Table<any>",
523 description: "Shift series values by a number of periods.",
524 category: "Column",
525 parameters: &[
526 BuiltinParam {
527 name: "series",
528 param_type: "Table<any>",
529 optional: false,
530 description: "Input series",
531 },
532 BuiltinParam {
533 name: "periods",
534 param_type: "number",
535 optional: false,
536 description: "Number of periods to shift",
537 },
538 ],
539 return_type: "Table<any>",
540 example: Some("shift(prices, 1) // previous day's prices"),
541 },
542 BuiltinMetadata {
543 name: "resample",
544 signature: "resample(table: Table<any>, timeframe: string, method: string) -> Table<any>",
545 description: "Resample a series to a different timeframe.",
546 category: "Column",
547 parameters: &[
548 BuiltinParam {
549 name: "series",
550 param_type: "Table<any>",
551 optional: false,
552 description: "Input series",
553 },
554 BuiltinParam {
555 name: "timeframe",
556 param_type: "string",
557 optional: false,
558 description: "Target timeframe",
559 },
560 BuiltinParam {
561 name: "method",
562 param_type: "string",
563 optional: false,
564 description: "Aggregation method",
565 },
566 ],
567 return_type: "Table<any>",
568 example: Some("resample(prices, \"1h\", \"last\")"),
569 },
570 BuiltinMetadata {
571 name: "map",
572 signature: "map(table: Table<any>, fn: Function) -> Table<any>",
573 description: "Apply a function to each element of a series.",
574 category: "Column",
575 parameters: &[
576 BuiltinParam {
577 name: "series",
578 param_type: "Table<any>",
579 optional: false,
580 description: "Input series",
581 },
582 BuiltinParam {
583 name: "fn",
584 param_type: "Function",
585 optional: false,
586 description: "Transform function",
587 },
588 ],
589 return_type: "Table<any>",
590 example: Some("map(prices, (p) => p * 1.1)"),
591 },
592 BuiltinMetadata {
593 name: "filter",
594 signature: "filter(table: Table<any>, predicate: Function) -> Table<any>",
595 description: "Filter series elements by a predicate function.",
596 category: "Column",
597 parameters: &[
598 BuiltinParam {
599 name: "series",
600 param_type: "Table<any>",
601 optional: false,
602 description: "Input series",
603 },
604 BuiltinParam {
605 name: "predicate",
606 param_type: "Function",
607 optional: false,
608 description: "Filter predicate",
609 },
610 ],
611 return_type: "Table<any>",
612 example: Some("filter(prices, (p) => p > 100)"),
613 },
614 BuiltinMetadata {
616 name: "Ok",
617 signature: "Ok(value) -> Result<T>",
618 description: "Wrap a value in a successful Result.",
619 category: "Utility",
620 parameters: &[BuiltinParam {
621 name: "value",
622 param_type: "any",
623 optional: false,
624 description: "Success value",
625 }],
626 return_type: "Result<T>",
627 example: Some("Ok(42)"),
628 },
629 BuiltinMetadata {
630 name: "Err",
631 signature: "Err(error) -> Result<T>",
632 description: "Create an error Result.",
633 category: "Utility",
634 parameters: &[BuiltinParam {
635 name: "error",
636 param_type: "any",
637 optional: false,
638 description: "Error value",
639 }],
640 return_type: "Result<T>",
641 example: Some("Err(\"not found\")"),
642 },
643 BuiltinMetadata {
645 name: "snapshot",
646 signature: "snapshot() -> Snapshot",
647 description: "Create a snapshot suspension point. Returns Snapshot::Hash(id) after saving, or Snapshot::Resumed when restoring from a snapshot.",
648 category: "Resumability",
649 parameters: &[],
650 return_type: "Snapshot",
651 example: Some(
652 "let result = snapshot()\nmatch result {\n Snapshot::Hash(id) => print(\"Saved: \" + id),\n Snapshot::Resumed => print(\"Restored!\"),\n}",
653 ),
654 },
655 BuiltinMetadata {
656 name: "exit",
657 signature: "exit(code?: number) -> ()",
658 description: "Terminate the process with an optional exit code.",
659 category: "Utility",
660 parameters: &[BuiltinParam {
661 name: "code",
662 param_type: "number",
663 optional: true,
664 description: "Exit code (default 0)",
665 }],
666 return_type: "()",
667 example: Some("exit(0)"),
668 },
669 BuiltinMetadata {
671 name: "implements",
672 signature: "implements(type_name: string, trait_name: string) -> bool",
673 description: "Returns true if the given type implements the specified trait. Only valid inside comptime blocks.",
674 category: "Comptime",
675 parameters: &[
676 BuiltinParam {
677 name: "type_name",
678 param_type: "string",
679 optional: false,
680 description: "Type name to check",
681 },
682 BuiltinParam {
683 name: "trait_name",
684 param_type: "string",
685 optional: false,
686 description: "Trait name to check",
687 },
688 ],
689 return_type: "bool",
690 example: Some("comptime { implements(\"Point\", \"Display\") }"),
691 },
692 BuiltinMetadata {
693 name: "warning",
694 signature: "warning(msg: string) -> ()",
695 description: "Emit a compile-time warning. Only valid inside comptime blocks.",
696 category: "Comptime",
697 parameters: &[BuiltinParam {
698 name: "msg",
699 param_type: "string",
700 optional: false,
701 description: "Warning message",
702 }],
703 return_type: "()",
704 example: Some("comptime { warning(\"generated fallback path\") }"),
705 },
706 BuiltinMetadata {
707 name: "error",
708 signature: "error(msg: string) -> never",
709 description: "Emit a compile-time error and abort compilation. Only valid inside comptime blocks.",
710 category: "Comptime",
711 parameters: &[BuiltinParam {
712 name: "msg",
713 param_type: "string",
714 optional: false,
715 description: "Error message",
716 }],
717 return_type: "never",
718 example: Some("comptime { error(\"invariant violated\") }"),
719 },
720 BuiltinMetadata {
721 name: "build_config",
722 signature: "build_config() -> Object",
723 description: "Returns build-time configuration (debug, version, target_os, target_arch). Only valid inside comptime blocks.",
724 category: "Comptime",
725 parameters: &[],
726 return_type: "Object",
727 example: Some("let v = comptime { build_config().version }"),
728 },
729];
730
731pub fn collect_builtin_metadata() -> Vec<&'static BuiltinMetadata> {
735 CORE_BUILTINS.iter().collect()
736}
737
738pub fn builtin_functions_from_macros() -> Vec<FunctionInfo> {
740 collect_builtin_metadata()
741 .into_iter()
742 .map(|m| m.into())
743 .collect()
744}
745
746pub fn is_comptime_builtin_function(name: &str) -> bool {
750 CORE_BUILTINS
751 .iter()
752 .any(|m| m.name == name && m.category == "Comptime")
753}
754
755pub static TYPE_METADATA_ROW: TypeMetadata = TypeMetadata {
759 name: "Row",
760 description: "Generic data row with dynamic fields",
761 properties: &[],
762};
763
764pub fn collect_core_type_metadata() -> Vec<&'static TypeMetadata> {
770 vec![&TYPE_METADATA_ROW]
771}
772
773pub fn collect_domain_type_metadata() -> Vec<&'static TypeMetadata> {
779 vec![]
780}
781
782pub fn collect_type_metadata() -> Vec<&'static TypeMetadata> {
792 let mut types = collect_core_type_metadata();
793 types.extend(collect_domain_type_metadata());
794 types
795}
796
797#[cfg(test)]
798mod tests {
799 use super::*;
800
801 #[test]
802 fn test_builtin_metadata_to_function_info() {
803 static TEST_PARAMS: &[BuiltinParam] = &[BuiltinParam {
804 name: "value",
805 param_type: "Number",
806 optional: false,
807 description: "Input value",
808 }];
809
810 let meta = BuiltinMetadata {
811 name: "test_fn",
812 signature: "test_fn(value: Number) -> Number",
813 description: "A test function",
814 category: "Math",
815 parameters: TEST_PARAMS,
816 return_type: "Number",
817 example: Some("test_fn(42)"),
818 };
819
820 let info: FunctionInfo = (&meta).into();
821
822 assert_eq!(info.name, "test_fn");
823 assert_eq!(info.signature, "test_fn(value: Number) -> Number");
824 assert_eq!(info.description, "A test function");
825 assert_eq!(info.category, FunctionCategory::Math);
826 assert_eq!(info.parameters.len(), 1);
827 assert_eq!(info.parameters[0].name, "value");
828 assert_eq!(info.return_type, "Number");
829 assert_eq!(info.example, Some("test_fn(42)".to_string()));
830 assert!(info.implemented);
831 }
832}