Skip to main content

gdscript_api/
gdscript_layer.rs

1//! The hand-authored GDScript layer the engine dump omits (Playbook §4.4).
2//!
3//! `extension_api.json` describes the engine (classes, builtins, `@GlobalScope` utilities) but
4//! not the *language* surface GDScript adds on top: the `@GlobalScope`/`@GDScript`
5//! pseudo-constants (`PI`/`TAU`/`INF`/`NAN`) and the GDScript builtin functions
6//! (`preload`/`load`/`range`/`len`/…), whose return types are decided here rather than read
7//! from any dump. `gdscript-hir` consults these during global name resolution.
8//!
9//! Types are tagged with the coarse, model-independent [`LayerTy`] (resolved to a `gdscript-hir`
10//! `Ty` by the consumer) because real [`crate::BuiltinId`]s only exist after the model loads.
11
12/// A coarse type tag for hand-authored symbols, mapped to a `gdscript-hir` `Ty` by the consumer.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum LayerTy {
15    /// `float`.
16    Float,
17    /// `int`.
18    Int,
19    /// `bool`.
20    Bool,
21    /// `String`.
22    Str,
23    /// Bare `Array` (`Array[Variant]`).
24    Array,
25    /// The dynamic `Variant` top type.
26    Variant,
27    /// The Phase-3 seam marker — distinct from `Variant`, never warns (e.g. `preload`).
28    Unknown,
29    /// `void`.
30    Void,
31}
32
33/// A `@GlobalScope`/`@GDScript` pseudo-constant (`PI`, `TAU`, `INF`, `NAN`).
34#[derive(Debug, Clone)]
35pub struct GlobalConst {
36    /// The constant name.
37    pub name: &'static str,
38    /// Its type.
39    pub ty: LayerTy,
40}
41
42/// A GDScript builtin function (`preload`, `range`, `len`, …) — distinct from the
43/// `@GlobalScope` *utility* functions, which come from the JSON.
44#[derive(Debug, Clone)]
45pub struct BuiltinFn {
46    /// The function name.
47    pub name: &'static str,
48    /// Minimum argument count.
49    pub min_args: u8,
50    /// Maximum argument count, or `None` for variadic.
51    pub max_args: Option<u8>,
52    /// The decided return type. `preload`/`load` are refined by `gdscript-hir` per the
53    /// literal-vs-variable argument rule (Playbook §4.4); this is the conservative default.
54    pub ret: LayerTy,
55}
56
57/// The pseudo-constants `extension_api.json` reports as empty `global_constants` in 4.5.
58#[must_use]
59pub fn global_consts() -> Vec<GlobalConst> {
60    use LayerTy::Float;
61    vec![
62        GlobalConst {
63            name: "PI",
64            ty: Float,
65        },
66        GlobalConst {
67            name: "TAU",
68            ty: Float,
69        },
70        GlobalConst {
71            name: "INF",
72            ty: Float,
73        },
74        GlobalConst {
75            name: "NAN",
76            ty: Float,
77        },
78    ]
79}
80
81/// The GDScript builtin functions (the `@GDScript` surface). The list grows as features need
82/// it; these are the ones inference and completion rely on in Phase 2.
83#[must_use]
84pub fn builtin_fns() -> Vec<BuiltinFn> {
85    use LayerTy::{Array, Int, Str, Unknown, Void};
86    vec![
87        // `preload(path)` resolves to a script/resource — opaque in Phase 2 (the seam).
88        BuiltinFn {
89            name: "preload",
90            min_args: 1,
91            max_args: Some(1),
92            ret: Unknown,
93        },
94        // `load(path)` returns a `Resource` at runtime, but the concrete script/resource type is
95        // unknowable statically (the arg may be a variable, and even a literal is a *runtime*
96        // call — NOT a compile-time constant like `preload`). Model it as the seam (`Unknown`) so
97        // `var r := load(...)` neither warns (`INFERENCE_ON_VARIANT`) nor cascades, and `load` is
98        // never aliased to `preload` (Playbook §3.M3 / D5 — both literal and variable args opaque).
99        BuiltinFn {
100            name: "load",
101            min_args: 1,
102            max_args: Some(1),
103            ret: Unknown,
104        },
105        BuiltinFn {
106            name: "range",
107            min_args: 1,
108            max_args: Some(3),
109            ret: Array,
110        },
111        BuiltinFn {
112            name: "len",
113            min_args: 1,
114            max_args: Some(1),
115            ret: Int,
116        },
117        BuiltinFn {
118            name: "char",
119            min_args: 1,
120            max_args: Some(1),
121            ret: Str,
122        },
123        BuiltinFn {
124            name: "assert",
125            min_args: 1,
126            max_args: Some(2),
127            ret: Void,
128        },
129    ]
130}