1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! Which bare words SurrealQL accepts as a type name.
//!
//! SurrealDB's type grammar is a **closed keyword set**, not an open namespace.
//! `parse_concrete_kind` ends with `_ => unexpected!(self, next, "a kind name")`
//! (`surrealdb-core/src/syn/parser/kind.rs:218`), so an unrecognised word is a
//! parse failure in the engine and the query never runs.
//!
//! That is the whole reason this module can be certain where
//! [`crate::semantic::assign`] deliberately is not. `assign` answers "is this
//! coercion safe to judge?", and its doc comment requires silence on an
//! unrecognised name so a new SurrealDB release cannot make the checker flag
//! working code. This module answers a different and much narrower question —
//! "does the parser have this word at all?" — where the answer is a fact about a
//! finite keyword table rather than an inference. The two must not be merged:
//! [`PRIMITIVES`](crate::semantic::assign) is a coercion allowlist and diverges
//! from this list on purpose.
/// The type names SurrealDB's kind grammar accepts.
///
/// Transcribed from the `t!("…")` arms of `parse_concrete_kind` and
/// `parse_inner_single_kind` (`syn/parser/kind.rs:45-220`), then verified one name
/// at a time against a live engine (version 3.2.3).
///
/// Two entries need a word of explanation:
///
/// * `option` is here although it is legal *only* as `option<T>` — bare `option`
/// fails with `expected <`. Arity is a separate rule this module does not model,
/// so the name counts as known.
/// * `value` is deliberately **absent**. `LET $x: value = 1` fails with
/// ``Unexpected token `VALUE`, expected a kind name``, even though `VALUE` is a
/// keyword elsewhere in the language. Note that `assign::PRIMITIVES` does list
/// `value`, because there it means "the top of the lattice", not "a name an
/// author may write".
pub const KIND_NAMES: & = &;
/// The two boolean literal types, which reach a type position as a bare
/// `TypeName`.
///
/// The engine reads them as literal types (`t!("true") => Kind::Literal(…)`), so
/// `<true> true` and `LET $x: false = 1` are both legal — SurrealDB's own
/// `casting/basic_literal_kind` test relies on it.
///
/// Kept apart from [`KIND_NAMES`] because they are not kind *names*, and they are
/// here at all only because the tree-sitter `LiteralType` rule covers `String`,
/// `Number`, `Duration`, `ArrayType` and `ObjectType` but omits booleans. `NaN`
/// and `Infinity` need no entry: the grammar reads those as
/// `LiteralType(Number(Float))`, so they never arrive as a `TypeName`.
const BOOLEAN_LITERAL_TYPES: & = &;
/// Constructors whose `<…>` arguments name something other than a type.
///
/// This list is what stops the check reporting valid SurrealQL. `record<person>`,
/// `table<person>`, `file<bucket>` and `geometry<multipoint>` all parse to the very
/// same shape, `ParameterizedType(TypeName, TypeName)`, so the argument cannot be
/// told apart from a type by its node kind alone:
///
/// * `record` and `table` take table names,
/// * `file` takes bucket names,
/// * `geometry` takes a name from its own closed set (`point`, `line`, `polygon`,
/// `multipoint`, `multiline`, `multipolygon`, `collection`), which this module
/// does not check.
///
/// `array`, `set` and `option` are absent on purpose: their arguments really are
/// types, and `array<xxx>` must be reported.
pub const FOREIGN_ARGUMENT_CONSTRUCTORS: & = &;
/// True when SurrealDB's kind grammar has this name.
///
/// Case-insensitive, because the engine lexes these through `UniCase`
/// (`syn/lexer/keywords.rs`) and so accepts `INT` and `String`.
/// True when `name` is a constructor whose `<…>` arguments are not types.
/// The closest real type name to `name`, for a "did you mean" hint.
///
/// Two guards, both borrowed from [`super::analyzer`]'s `keyword_typo_hint`:
///
/// * a `jaro_winkler` score above 0.86, and
/// * a length difference of three characters or less.
///
/// The length guard is what makes this safe on a list of very short words. Without
/// it the prefix bonus pairs any two names that merely start alike. Three rather
/// than two because the useful abbreviations are exactly three characters short of
/// their target — `str`, `rec`, `num` and `obj` all land on the right name at 0.88,
/// while unrelated words (`text`, `json`, `char`) stay well under the threshold.