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    /// Bare `Dictionary`.
26    Dictionary,
27    /// `Color`.
28    Color,
29    /// The dynamic `Variant` top type.
30    Variant,
31    /// The Phase-3 seam marker — distinct from `Variant`, never warns (e.g. `preload`).
32    Unknown,
33    /// `void`.
34    Void,
35}
36
37/// A `@GlobalScope`/`@GDScript` pseudo-constant (`PI`, `TAU`, `INF`, `NAN`).
38#[derive(Debug, Clone)]
39pub struct GlobalConst {
40    /// The constant name.
41    pub name: &'static str,
42    /// Its type.
43    pub ty: LayerTy,
44}
45
46/// A GDScript builtin function (`preload`, `range`, `len`, …) — distinct from the
47/// `@GlobalScope` *utility* functions, which come from the JSON.
48#[derive(Debug, Clone)]
49pub struct BuiltinFn {
50    /// The function name.
51    pub name: &'static str,
52    /// Minimum argument count.
53    pub min_args: u8,
54    /// Maximum argument count, or `None` for variadic.
55    pub max_args: Option<u8>,
56    /// The decided return type. `preload`/`load` are refined by `gdscript-hir` per the
57    /// literal-vs-variable argument rule (Playbook §4.4); this is the conservative default.
58    pub ret: LayerTy,
59}
60
61/// The pseudo-constants `extension_api.json` reports as empty `global_constants` in 4.5.
62#[must_use]
63pub fn global_consts() -> Vec<GlobalConst> {
64    use LayerTy::Float;
65    vec![
66        GlobalConst {
67            name: "PI",
68            ty: Float,
69        },
70        GlobalConst {
71            name: "TAU",
72            ty: Float,
73        },
74        GlobalConst {
75            name: "INF",
76            ty: Float,
77        },
78        GlobalConst {
79            name: "NAN",
80            ty: Float,
81        },
82    ]
83}
84
85/// The GDScript builtin functions (the `@GDScript` surface). The list grows as features need
86/// it; these are the ones inference and completion rely on in Phase 2.
87#[must_use]
88pub fn builtin_fns() -> Vec<BuiltinFn> {
89    use LayerTy::{Array, Bool, Color, Dictionary, Int, Str, Unknown, Variant, Void};
90    vec![
91        // Two `@GlobalScope` utility functions the extracted blob omits (the extraction filtered
92        // them; they are real bare globals — the corpus calls both). Hand-authored here, exactly
93        // what this layer is for, so bare calls resolve and never false-flag as UNDEFINED.
94        BuiltinFn {
95            name: "Color8",
96            min_args: 3,
97            max_args: Some(4),
98            ret: Color,
99        },
100        BuiltinFn {
101            name: "is_instance_of",
102            min_args: 2,
103            max_args: Some(2),
104            ret: Bool,
105        },
106        // The REST of the `@GDScript` pseudo-class surface (vendor .../doc/classes/@GDScript.xml
107        // lists 15 methods; these complete the set). They exist in no extracted table — with the
108        // A1 `UNDEFINED_FUNCTION` armed, an uncovered one false-flags common code (`print_debug`).
109        BuiltinFn {
110            name: "convert",
111            min_args: 2,
112            max_args: Some(2),
113            ret: Variant,
114        },
115        BuiltinFn {
116            name: "dict_to_inst",
117            min_args: 1,
118            max_args: Some(1),
119            ret: Variant,
120        },
121        BuiltinFn {
122            name: "get_stack",
123            min_args: 0,
124            max_args: Some(0),
125            ret: Array,
126        },
127        BuiltinFn {
128            name: "inst_to_dict",
129            min_args: 1,
130            max_args: Some(1),
131            ret: Dictionary,
132        },
133        BuiltinFn {
134            name: "ord",
135            min_args: 1,
136            max_args: Some(1),
137            ret: Int,
138        },
139        BuiltinFn {
140            name: "print_debug",
141            min_args: 0,
142            max_args: None,
143            ret: Void,
144        },
145        BuiltinFn {
146            name: "print_stack",
147            min_args: 0,
148            max_args: Some(0),
149            ret: Void,
150        },
151        BuiltinFn {
152            name: "type_exists",
153            min_args: 1,
154            max_args: Some(1),
155            ret: Bool,
156        },
157        // `preload(path)` resolves to a script/resource — opaque in Phase 2 (the seam).
158        BuiltinFn {
159            name: "preload",
160            min_args: 1,
161            max_args: Some(1),
162            ret: Unknown,
163        },
164        // `load(path)` returns a `Resource` at runtime, but the concrete script/resource type is
165        // unknowable statically (the arg may be a variable, and even a literal is a *runtime*
166        // call — NOT a compile-time constant like `preload`). Model it as the seam (`Unknown`) so
167        // `var r := load(...)` neither warns (`INFERENCE_ON_VARIANT`) nor cascades, and `load` is
168        // never aliased to `preload` (Playbook §3.M3 / D5 — both literal and variable args opaque).
169        BuiltinFn {
170            name: "load",
171            min_args: 1,
172            max_args: Some(1),
173            ret: Unknown,
174        },
175        BuiltinFn {
176            name: "range",
177            min_args: 1,
178            max_args: Some(3),
179            ret: Array,
180        },
181        BuiltinFn {
182            name: "len",
183            min_args: 1,
184            max_args: Some(1),
185            ret: Int,
186        },
187        BuiltinFn {
188            name: "char",
189            min_args: 1,
190            max_args: Some(1),
191            ret: Str,
192        },
193        BuiltinFn {
194            name: "assert",
195            min_args: 1,
196            max_args: Some(2),
197            ret: Void,
198        },
199    ]
200}