Skip to main content

omena_syntax/
lib.rs

1//! Shared syntax vocabulary for the Omena CSS-family parser stack.
2//!
3//! This crate is intentionally substrate-only: it defines stable syntax kind
4//! ranges and CST integration without parsing source text yet.
5//!
6//! syntax_kind_extraction_decision: keep `SyntaxKind` extracted in
7//! `omena-syntax`; parser, semantic, resolver, LSP, and checker layers consume
8//! this crate instead of re-declaring local node/token taxonomies.
9
10use cstree::{RawSyntaxKind, Syntax};
11
12pub const TOKEN_START: u32 = 0x0000;
13pub const TOKEN_END: u32 = 0x03ff;
14pub const DIALECT_TOKEN_START: u32 = 0x0400;
15pub const DIALECT_TOKEN_END: u32 = 0x04ff;
16pub const NODE_START: u32 = 0x1000;
17pub const NODE_END: u32 = 0x13ff;
18pub const DIALECT_NODE_START: u32 = 0x1400;
19pub const DIALECT_NODE_END: u32 = 0x14ff;
20pub const BOGUS_START: u32 = 0x2000;
21pub const BOGUS_END: u32 = 0x20ff;
22pub const MARKER_START: u32 = 0x2100;
23pub const MARKER_END: u32 = 0x21ff;
24
25const _: () = {
26    assert!(TOKEN_END < DIALECT_TOKEN_START);
27    assert!(DIALECT_TOKEN_END < NODE_START);
28    assert!(NODE_END < DIALECT_NODE_START);
29    assert!(DIALECT_NODE_END < BOGUS_START);
30    assert!(BOGUS_END < MARKER_START);
31};
32
33pub type SyntaxNode<D = ()> = cstree::syntax::SyntaxNode<SyntaxKind, D>;
34pub type SyntaxToken<D = ()> = cstree::syntax::SyntaxToken<SyntaxKind, D>;
35pub type SyntaxElement<D = ()> = cstree::syntax::SyntaxElement<SyntaxKind, D>;
36pub type SyntaxElementRef<'a, D = ()> = cstree::syntax::SyntaxElementRef<'a, SyntaxKind, D>;
37
38macro_rules! syntax_kinds {
39    ($($name:ident = $value:expr,)+) => {
40        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
41        #[repr(u32)]
42        pub enum SyntaxKind {
43            $($name = $value,)+
44        }
45
46        impl SyntaxKind {
47            pub const ALL: &'static [Self] = &[$(Self::$name,)+];
48
49            pub const fn as_u32(self) -> u32 {
50                self as u32
51            }
52
53            pub fn from_raw_kind(raw: u32) -> Option<Self> {
54                let mut index = 0;
55                while index < Self::ALL.len() {
56                    let kind = Self::ALL[index];
57                    if kind.as_u32() == raw {
58                        return Some(kind);
59                    }
60                    index += 1;
61                }
62                None
63            }
64
65            pub const fn is_token(self) -> bool {
66                let raw = self.as_u32();
67                (raw >= TOKEN_START && raw <= TOKEN_END)
68                    || (raw >= DIALECT_TOKEN_START && raw <= DIALECT_TOKEN_END)
69            }
70
71            pub const fn is_node(self) -> bool {
72                let raw = self.as_u32();
73                (raw >= NODE_START && raw <= NODE_END)
74                    || (raw >= DIALECT_NODE_START && raw <= DIALECT_NODE_END)
75            }
76
77            pub const fn is_bogus(self) -> bool {
78                let raw = self.as_u32();
79                raw >= BOGUS_START && raw <= BOGUS_END
80            }
81
82            pub const fn is_marker(self) -> bool {
83                let raw = self.as_u32();
84                raw >= MARKER_START && raw <= MARKER_END
85            }
86
87            pub const fn is_dialect_specific(self) -> bool {
88                let raw = self.as_u32();
89                (raw >= DIALECT_TOKEN_START && raw <= DIALECT_TOKEN_END)
90                    || (raw >= DIALECT_NODE_START && raw <= DIALECT_NODE_END)
91            }
92
93            pub const fn is_dialect(self) -> bool {
94                self.is_dialect_specific()
95            }
96
97            pub const fn is_trivia(self) -> bool {
98                matches!(
99                    self,
100                    Self::Whitespace
101                        | Self::LineComment
102                        | Self::BlockComment
103                        | Self::SassIndentedNewline
104                )
105            }
106        }
107    };
108}
109
110syntax_kinds! {
111    Whitespace = 0x0000,
112    LineComment = 0x0001,
113    BlockComment = 0x0002,
114    Ident = 0x0003,
115    Hash = 0x0004,
116    String = 0x0005,
117    BadString = 0x0006,
118    Url = 0x0007,
119    BadUrl = 0x0008,
120    Number = 0x0009,
121    Percentage = 0x000a,
122    Dimension = 0x000b,
123    UnicodeRange = 0x000c,
124    AtKeyword = 0x000d,
125    Delim = 0x000e,
126    Important = 0x000f,
127    Dot = 0x0010,
128    Comma = 0x0011,
129    Colon = 0x0012,
130    Semicolon = 0x0013,
131    LeftBrace = 0x0014,
132    RightBrace = 0x0015,
133    LeftParen = 0x0016,
134    RightParen = 0x0017,
135    LeftBracket = 0x0018,
136    RightBracket = 0x0019,
137    Plus = 0x001a,
138    Minus = 0x001b,
139    Star = 0x001c,
140    Slash = 0x001d,
141    Percent = 0x001e,
142    Equals = 0x001f,
143    Tilde = 0x0020,
144    Pipe = 0x0021,
145    Caret = 0x0022,
146    Dollar = 0x0023,
147    Ampersand = 0x0024,
148    GreaterThan = 0x0025,
149    LessThan = 0x0026,
150    PlusEquals = 0x0027,
151    MinusEquals = 0x0028,
152    StarEquals = 0x0029,
153    SlashEquals = 0x002a,
154    PipeEquals = 0x002b,
155    TildeEquals = 0x002c,
156    CaretEquals = 0x002d,
157    DollarEquals = 0x002e,
158    DoubleColon = 0x002f,
159    DoublePipe = 0x0030,
160    DoubleAmpersand = 0x0031,
161    Arrow = 0x0032,
162    IncludesMatch = 0x0033,
163    DashMatch = 0x0034,
164    PrefixMatch = 0x0035,
165    SuffixMatch = 0x0036,
166    SubstringMatch = 0x0037,
167    ColumnCombinator = 0x0038,
168    NestingSelector = 0x0039,
169    CustomPropertyName = 0x003a,
170    ClassName = 0x003b,
171    IdName = 0x003c,
172    KeywordAnd = 0x003d,
173    KeywordOr = 0x003e,
174    KeywordNot = 0x003f,
175    KeywordOnly = 0x0040,
176    KeywordFrom = 0x0041,
177    KeywordTo = 0x0042,
178    KeywordThrough = 0x0043,
179    KeywordImportant = 0x0044,
180    KeywordGlobal = 0x0045,
181    KeywordLocal = 0x0046,
182    KeywordExport = 0x0047,
183    KeywordImport = 0x0048,
184    KeywordComposes = 0x0049,
185    KeywordAs = 0x004a,
186    KeywordWith = 0x004b,
187    KeywordLayer = 0x004c,
188    KeywordSupports = 0x004d,
189    KeywordContainer = 0x004e,
190    KeywordScope = 0x004f,
191    KeywordMedia = 0x0050,
192    KeywordKeyframes = 0x0051,
193    KeywordCharset = 0x0052,
194    KeywordNamespace = 0x0053,
195    KeywordPage = 0x0054,
196    KeywordFontFace = 0x0055,
197    KeywordProperty = 0x0056,
198    KeywordStartingStyle = 0x0057,
199    KeywordWhen = 0x0058,
200    KeywordElse = 0x0059,
201    KeywordUse = 0x005a,
202    KeywordForward = 0x005b,
203    KeywordMixin = 0x005c,
204    KeywordInclude = 0x005d,
205    KeywordFunction = 0x005e,
206    KeywordReturn = 0x005f,
207    KeywordIf = 0x0060,
208    KeywordEach = 0x0061,
209    KeywordFor = 0x0062,
210    KeywordWhile = 0x0063,
211    KeywordIn = 0x0064,
212    Cdo = 0x0065,
213    Cdc = 0x0066,
214
215    ScssVariable = 0x0400,
216    ScssInterpolationStart = 0x0401,
217    ScssInterpolationEnd = 0x0402,
218    ScssSilentComment = 0x0403,
219    ScssPlaceholder = 0x0404,
220    ScssModuleNamespace = 0x0405,
221    SassIndentedNewline = 0x0406,
222    SassIndent = 0x0407,
223    SassDedent = 0x0408,
224    SassOptionalSemicolon = 0x0409,
225    LessVariable = 0x0410,
226    LessEscapedString = 0x0411,
227    LessDetachedRuleset = 0x0412,
228    LessMixinGuardWhen = 0x0413,
229    LessExtendKeyword = 0x0414,
230    LessNamespaceSeparator = 0x0415,
231    LessInterpolationStart = 0x0416,
232    LessInterpolationEnd = 0x0417,
233    LessPropertyVariableToken = 0x0418,
234
235    Stylesheet = 0x1000,
236    Rule = 0x1001,
237    QualifiedRule = 0x1002,
238    Declaration = 0x1003,
239    DeclarationList = 0x1004,
240    RuleList = 0x1005,
241    SelectorList = 0x1006,
242    Selector = 0x1007,
243    ComplexSelector = 0x1008,
244    CompoundSelector = 0x1009,
245    ClassSelector = 0x100a,
246    IdSelector = 0x100b,
247    TypeSelector = 0x100c,
248    UniversalSelector = 0x100d,
249    AttributeSelector = 0x100e,
250    AttributeMatcher = 0x100f,
251    PseudoClassSelector = 0x1010,
252    PseudoElementSelector = 0x1011,
253    PseudoSelectorArgument = 0x1012,
254    NestingSelectorNode = 0x1013,
255    Combinator = 0x1014,
256    SelectorValue = 0x1015,
257    PropertyName = 0x1016,
258    CustomPropertyDeclaration = 0x1017,
259    Value = 0x1018,
260    ValueList = 0x1019,
261    FunctionCall = 0x101a,
262    FunctionArguments = 0x101b,
263    BinaryExpression = 0x101c,
264    UnaryExpression = 0x101d,
265    ParenthesizedExpression = 0x101e,
266    Interpolation = 0x101f,
267    DimensionValue = 0x1020,
268    ColorValue = 0x1021,
269    UrlValue = 0x1022,
270    VarFunction = 0x1023,
271    CalcFunction = 0x1024,
272    AtRule = 0x1025,
273    MediaRule = 0x1026,
274    SupportsRule = 0x1027,
275    ContainerRule = 0x1028,
276    LayerRule = 0x1029,
277    ScopeRule = 0x102a,
278    KeyframesRule = 0x102b,
279    KeyframeBlock = 0x102c,
280    FontFaceRule = 0x102d,
281    PageRule = 0x102e,
282    NamespaceRule = 0x102f,
283    ImportRule = 0x1030,
284    CharsetRule = 0x1031,
285    PropertyRule = 0x1032,
286    StartingStyleRule = 0x1033,
287    MediaQueryList = 0x1034,
288    MediaQuery = 0x1035,
289    MediaFeature = 0x1036,
290    SupportsCondition = 0x1037,
291    ContainerCondition = 0x1038,
292    LayerName = 0x1039,
293    ScopeRange = 0x103a,
294    CssModuleLocalBlock = 0x103b,
295    CssModuleGlobalBlock = 0x103c,
296    CssModuleExportBlock = 0x103d,
297    CssModuleImportBlock = 0x103e,
298    CssModuleComposesDeclaration = 0x103f,
299    CssModuleComposesTarget = 0x1040,
300    CssModuleFromClause = 0x1041,
301    TokenDefinition = 0x1042,
302    TokenReference = 0x1043,
303    Comment = 0x1044,
304    ErrorNode = 0x1045,
305    EnvFunction = 0x1046,
306    AttrFunction = 0x1047,
307    MathFunction = 0x1048,
308    PageMarginRule = 0x1049,
309    WhenRule = 0x104a,
310    ElseRule = 0x104b,
311    CounterStyleRule = 0x104c,
312    FontPaletteValuesRule = 0x104d,
313    ColorProfileRule = 0x104e,
314    PositionTryRule = 0x104f,
315    FontFeatureValuesRule = 0x1050,
316    FontFeatureValuesStylisticRule = 0x1051,
317    FontFeatureValuesStylesetRule = 0x1052,
318    FontFeatureValuesCharacterVariantRule = 0x1053,
319    FontFeatureValuesSwashRule = 0x1054,
320    FontFeatureValuesOrnamentsRule = 0x1055,
321    FontFeatureValuesAnnotationRule = 0x1056,
322    FontFeatureValuesHistoricalFormsRule = 0x1057,
323    ViewTransitionRule = 0x1058,
324    GradientFunction = 0x1059,
325    TransformFunction = 0x105a,
326    FilterFunction = 0x105b,
327    ImageFunction = 0x105c,
328    ShapeFunction = 0x105d,
329    AtRulePrelude = 0x105e,
330    NestRule = 0x105f,
331    CustomMediaRule = 0x1060,
332    IdentifierValue = 0x1061,
333    StringValue = 0x1062,
334    UnicodeRangeValue = 0x1063,
335    NumberValue = 0x1064,
336    PercentageValue = 0x1065,
337    BracketedValue = 0x1066,
338    ImportantAnnotation = 0x1067,
339    ComponentValue = 0x1068,
340    SimpleBlock = 0x1069,
341    ComponentValueList = 0x106a,
342    CommaSeparatedComponentValueList = 0x106b,
343    CustomPropertyValue = 0x106c,
344    AttributeName = 0x106d,
345    AttributeValue = 0x106e,
346    AttributeModifier = 0x106f,
347    NthSelectorArgument = 0x1070,
348    NthSelectorFormula = 0x1071,
349    NthSelectorOfSelectorList = 0x1072,
350    RelativeSelectorList = 0x1073,
351    RelativeSelector = 0x1074,
352    LanguageSelectorArgument = 0x1075,
353    LanguageTag = 0x1076,
354    DirectionalitySelectorArgument = 0x1077,
355    NamespacePrefix = 0x1078,
356
357    ScssStylesheet = 0x1400,
358    ScssUseRule = 0x1401,
359    ScssForwardRule = 0x1402,
360    ScssMixinDeclaration = 0x1403,
361    ScssIncludeRule = 0x1404,
362    ScssFunctionDeclaration = 0x1405,
363    ScssReturnRule = 0x1406,
364    ScssVariableDeclaration = 0x1407,
365    ScssVariableReference = 0x1408,
366    ScssPlaceholderSelector = 0x1409,
367    ScssExtendRule = 0x140a,
368    ScssControlIf = 0x140b,
369    ScssControlElse = 0x140c,
370    ScssControlEach = 0x140d,
371    ScssControlFor = 0x140e,
372    ScssControlWhile = 0x140f,
373    ScssNestedProperty = 0x1410,
374    ScssModuleConfig = 0x1411,
375    SassIndentedBlock = 0x1412,
376    SassIndentedRule = 0x1413,
377    ScssAtRootRule = 0x1414,
378    ScssErrorRule = 0x1415,
379    ScssWarnRule = 0x1416,
380    ScssDebugRule = 0x1417,
381    ScssContentRule = 0x1418,
382    ScssVariableFlag = 0x1419,
383    LessStylesheet = 0x1420,
384    LessVariableDeclaration = 0x1421,
385    LessVariableReference = 0x1422,
386    LessMixinDeclaration = 0x1423,
387    LessMixinCall = 0x1424,
388    LessMixinGuard = 0x1425,
389    LessDetachedRulesetNode = 0x1426,
390    LessExtendRule = 0x1427,
391    LessNamespaceAccess = 0x1428,
392    LessPropertyVariable = 0x1429,
393
394    BogusToken = 0x2000,
395    BogusTrivia = 0x2001,
396    BogusRule = 0x2002,
397    BogusSelector = 0x2003,
398    BogusSelectorList = 0x2004,
399    BogusCompoundSelector = 0x2005,
400    BogusCombinator = 0x2006,
401    BogusDeclaration = 0x2007,
402    BogusDeclarationList = 0x2008,
403    BogusPropertyName = 0x2009,
404    BogusValue = 0x200a,
405    BogusValueList = 0x200b,
406    BogusFunctionCall = 0x200c,
407    BogusFunctionArguments = 0x200d,
408    BogusAtRule = 0x200e,
409    BogusMediaQuery = 0x200f,
410    BogusSupportsCondition = 0x2010,
411    BogusContainerCondition = 0x2011,
412    BogusLayerName = 0x2012,
413    BogusScopeRange = 0x2013,
414    BogusKeyframeBlock = 0x2014,
415    BogusCssModuleBlock = 0x2015,
416    BogusComposesDeclaration = 0x2016,
417    BogusComposesTarget = 0x2017,
418    BogusFromClause = 0x2018,
419    BogusInterpolation = 0x2019,
420    BogusScssVariable = 0x201a,
421    BogusScssMixin = 0x201b,
422    BogusScssFunction = 0x201c,
423    BogusScssControl = 0x201d,
424    BogusSassIndentation = 0x201e,
425    BogusLessVariable = 0x201f,
426    BogusLessMixin = 0x2020,
427    BogusLessGuard = 0x2021,
428    BogusLessDetachedRuleset = 0x2022,
429    BogusRecovery = 0x2023,
430    BogusScssModuleConfig = 0x2024,
431    BogusAtRulePrelude = 0x2025,
432    BogusBracketedValue = 0x2026,
433    BogusSimpleBlock = 0x2027,
434
435    Root = 0x2100,
436    Eof = 0x2101,
437    Unknown = 0x21fe,
438    Tombstone = 0x21ff,
439}
440
441impl Syntax for SyntaxKind {
442    fn from_raw(raw: RawSyntaxKind) -> Self {
443        match Self::from_raw_kind(raw.0) {
444            Some(kind) => kind,
445            None => Self::Unknown,
446        }
447    }
448
449    fn into_raw(self) -> RawSyntaxKind {
450        RawSyntaxKind(self.as_u32())
451    }
452
453    fn static_text(self) -> Option<&'static str> {
454        match self {
455            Self::Dot => Some("."),
456            Self::Comma => Some(","),
457            Self::Colon => Some(":"),
458            Self::Semicolon => Some(";"),
459            Self::LeftBrace => Some("{"),
460            Self::RightBrace => Some("}"),
461            Self::LeftParen => Some("("),
462            Self::RightParen => Some(")"),
463            Self::LeftBracket => Some("["),
464            Self::RightBracket => Some("]"),
465            Self::Plus => Some("+"),
466            Self::Minus => Some("-"),
467            Self::Star => Some("*"),
468            Self::Slash => Some("/"),
469            Self::Percent => Some("%"),
470            Self::Equals => Some("="),
471            Self::Tilde => Some("~"),
472            Self::Pipe => Some("|"),
473            Self::Caret => Some("^"),
474            Self::Dollar => Some("$"),
475            Self::Ampersand => Some("&"),
476            Self::GreaterThan => Some(">"),
477            Self::LessThan => Some("<"),
478            Self::PlusEquals => Some("+="),
479            Self::MinusEquals => Some("-="),
480            Self::StarEquals => Some("*="),
481            Self::SlashEquals => Some("/="),
482            Self::PipeEquals => Some("|="),
483            Self::TildeEquals => Some("~="),
484            Self::CaretEquals => Some("^="),
485            Self::DollarEquals => Some("$="),
486            Self::DoubleColon => Some("::"),
487            Self::DoublePipe => Some("||"),
488            Self::DoubleAmpersand => Some("&&"),
489            Self::Arrow => Some("=>"),
490            Self::IncludesMatch => Some("~="),
491            Self::DashMatch => Some("|="),
492            Self::PrefixMatch => Some("^="),
493            Self::SuffixMatch => Some("$="),
494            Self::SubstringMatch => Some("*="),
495            Self::ColumnCombinator => Some("||"),
496            Self::KeywordAnd => Some("and"),
497            Self::KeywordOr => Some("or"),
498            Self::KeywordNot => Some("not"),
499            Self::KeywordOnly => Some("only"),
500            Self::KeywordFrom => Some("from"),
501            Self::KeywordTo => Some("to"),
502            Self::KeywordThrough => Some("through"),
503            Self::KeywordImportant => Some("important"),
504            Self::Cdo => Some("<!--"),
505            Self::Cdc => Some("-->"),
506            Self::KeywordGlobal => Some("global"),
507            Self::KeywordLocal => Some("local"),
508            Self::KeywordExport => Some("export"),
509            Self::KeywordImport => Some("import"),
510            Self::KeywordComposes => Some("composes"),
511            Self::KeywordAs => Some("as"),
512            Self::KeywordWith => Some("with"),
513            Self::KeywordLayer => Some("layer"),
514            Self::KeywordSupports => Some("supports"),
515            Self::KeywordContainer => Some("container"),
516            Self::KeywordScope => Some("scope"),
517            Self::KeywordMedia => Some("media"),
518            Self::KeywordKeyframes => Some("keyframes"),
519            Self::KeywordCharset => Some("charset"),
520            Self::KeywordNamespace => Some("namespace"),
521            Self::KeywordPage => Some("page"),
522            Self::KeywordFontFace => Some("font-face"),
523            Self::KeywordProperty => Some("property"),
524            Self::KeywordStartingStyle => Some("starting-style"),
525            Self::KeywordWhen => Some("when"),
526            Self::KeywordElse => Some("else"),
527            Self::KeywordUse => Some("use"),
528            Self::KeywordForward => Some("forward"),
529            Self::KeywordMixin => Some("mixin"),
530            Self::KeywordInclude => Some("include"),
531            Self::KeywordFunction => Some("function"),
532            Self::KeywordReturn => Some("return"),
533            Self::KeywordIf => Some("if"),
534            Self::KeywordEach => Some("each"),
535            Self::KeywordFor => Some("for"),
536            Self::KeywordWhile => Some("while"),
537            Self::KeywordIn => Some("in"),
538            Self::Eof => Some(""),
539            _ => None,
540        }
541    }
542}
543
544#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
545pub enum StyleDialect {
546    Css,
547    Scss,
548    Sass,
549    Less,
550}
551
552impl StyleDialect {
553    pub const ALL: &'static [Self] = &[Self::Css, Self::Scss, Self::Sass, Self::Less];
554}
555
556#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
557pub enum ModuleMode {
558    Plain,
559    CssModules,
560}
561
562impl ModuleMode {
563    pub const ALL: &'static [Self] = &[Self::Plain, Self::CssModules];
564}
565
566#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
567pub enum SymbolKind {
568    Class,
569    Id,
570    TypeSelector,
571    PlaceholderSelector,
572    Keyframes,
573    CustomProperty,
574    ScssVariable,
575    LessVariable,
576    Mixin,
577    Function,
578    ValueDeclaration,
579    ComposesTarget,
580    Namespace,
581    Layer,
582    Container,
583    Scope,
584    Import,
585    Export,
586    ModuleLocal,
587    ModuleGlobal,
588}
589
590impl SymbolKind {
591    pub const ALL: &'static [Self] = &[
592        Self::Class,
593        Self::Id,
594        Self::TypeSelector,
595        Self::PlaceholderSelector,
596        Self::Keyframes,
597        Self::CustomProperty,
598        Self::ScssVariable,
599        Self::LessVariable,
600        Self::Mixin,
601        Self::Function,
602        Self::ValueDeclaration,
603        Self::ComposesTarget,
604        Self::Namespace,
605        Self::Layer,
606        Self::Container,
607        Self::Scope,
608        Self::Import,
609        Self::Export,
610        Self::ModuleLocal,
611        Self::ModuleGlobal,
612    ];
613}
614
615#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
616pub enum ScopeKind {
617    File,
618    LocalBlock,
619    GlobalBlock,
620    SelectorBlock,
621    MixinBody,
622    FunctionBody,
623    AtRuleScope,
624    NestedRule,
625    ScopeAtRule,
626    MediaQuery,
627    SupportsQuery,
628    ContainerQuery,
629    CascadeLayer,
630    ModuleNamespace,
631    LessMixin,
632    SassControlFlow,
633    CssModuleExport,
634    CssModuleImport,
635}
636
637impl ScopeKind {
638    pub const ALL: &'static [Self] = &[
639        Self::File,
640        Self::LocalBlock,
641        Self::GlobalBlock,
642        Self::SelectorBlock,
643        Self::MixinBody,
644        Self::FunctionBody,
645        Self::AtRuleScope,
646        Self::NestedRule,
647        Self::ScopeAtRule,
648        Self::MediaQuery,
649        Self::SupportsQuery,
650        Self::ContainerQuery,
651        Self::CascadeLayer,
652        Self::ModuleNamespace,
653        Self::LessMixin,
654        Self::SassControlFlow,
655        Self::CssModuleExport,
656        Self::CssModuleImport,
657    ];
658}
659
660#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
661pub enum ReferenceKind {
662    Class,
663    Id,
664    TypeSelector,
665    PlaceholderSelector,
666    Keyframes,
667    ComposesTarget,
668    ComposesFrom,
669    CustomPropertyRead,
670    VarRead,
671    ValueRead,
672    Import,
673    Export,
674    MixinInclude,
675    FunctionCall,
676    NamespaceMember,
677    Layer,
678    Container,
679    SelectorExtends,
680    CssModuleAccess,
681    CssModuleToken,
682}
683
684impl ReferenceKind {
685    pub const ALL: &'static [Self] = &[
686        Self::Class,
687        Self::Id,
688        Self::TypeSelector,
689        Self::PlaceholderSelector,
690        Self::Keyframes,
691        Self::ComposesTarget,
692        Self::ComposesFrom,
693        Self::CustomPropertyRead,
694        Self::VarRead,
695        Self::ValueRead,
696        Self::Import,
697        Self::Export,
698        Self::MixinInclude,
699        Self::FunctionCall,
700        Self::NamespaceMember,
701        Self::Layer,
702        Self::Container,
703        Self::SelectorExtends,
704        Self::CssModuleAccess,
705        Self::CssModuleToken,
706    ];
707}
708
709#[derive(Debug, Clone, PartialEq, Eq)]
710pub struct OmenaSyntaxBoundarySummaryV0 {
711    pub schema_version: &'static str,
712    pub product: &'static str,
713    pub phase: &'static str,
714    pub syntax_kind_owner_crate: &'static str,
715    pub parser_consumer_policy: &'static str,
716    pub syntax_kind_count: usize,
717    pub token_kind_count: usize,
718    pub node_kind_count: usize,
719    pub bogus_kind_count: usize,
720    pub marker_kind_count: usize,
721    pub dialect_kind_count: usize,
722    pub style_dialect_count: usize,
723    pub module_mode_count: usize,
724    pub symbol_kind_count: usize,
725    pub scope_kind_count: usize,
726    pub reference_kind_count: usize,
727    pub cstree_integration_ready: bool,
728    pub ready_surfaces: Vec<&'static str>,
729    pub next_surfaces: Vec<&'static str>,
730}
731
732pub fn summarize_omena_syntax_boundary() -> OmenaSyntaxBoundarySummaryV0 {
733    OmenaSyntaxBoundarySummaryV0 {
734        schema_version: "0",
735        product: "omena-syntax.boundary",
736        phase: "h1-alpha-syntax-substrate",
737        syntax_kind_owner_crate: "omena-syntax",
738        parser_consumer_policy: "parserConsumesOmenaSyntaxKindNoLocalTaxonomy",
739        syntax_kind_count: SyntaxKind::ALL.len(),
740        token_kind_count: SyntaxKind::ALL
741            .iter()
742            .filter(|kind| kind.is_token())
743            .count(),
744        node_kind_count: SyntaxKind::ALL.iter().filter(|kind| kind.is_node()).count(),
745        bogus_kind_count: SyntaxKind::ALL
746            .iter()
747            .filter(|kind| kind.is_bogus())
748            .count(),
749        marker_kind_count: SyntaxKind::ALL
750            .iter()
751            .filter(|kind| kind.is_marker())
752            .count(),
753        dialect_kind_count: SyntaxKind::ALL
754            .iter()
755            .filter(|kind| kind.is_dialect())
756            .count(),
757        style_dialect_count: StyleDialect::ALL.len(),
758        module_mode_count: ModuleMode::ALL.len(),
759        symbol_kind_count: SymbolKind::ALL.len(),
760        scope_kind_count: ScopeKind::ALL.len(),
761        reference_kind_count: ReferenceKind::ALL.len(),
762        cstree_integration_ready: SyntaxKind::Ident.into_raw()
763            == RawSyntaxKind(SyntaxKind::Ident.as_u32())
764            && SyntaxKind::from_raw(RawSyntaxKind(SyntaxKind::Ident.as_u32())) == SyntaxKind::Ident,
765        ready_surfaces: vec![
766            "rangeDividedSyntaxKind",
767            "symbolScopeReferenceVocabulary",
768            "styleDialectAndModuleMode",
769            "cstreeRawKindBridge",
770            "bogusRecoveryKindSuperset",
771            "semanticSoaTables",
772            "parserCstEquivalence",
773        ],
774        next_surfaces: Vec::new(),
775    }
776}
777
778#[cfg(test)]
779mod tests {
780    use super::*;
781
782    #[test]
783    fn syntax_kind_ranges_are_disjoint() {
784        let mut raws: Vec<u32> = SyntaxKind::ALL.iter().map(|kind| kind.as_u32()).collect();
785        raws.sort_unstable();
786
787        for pair in raws.windows(2) {
788            assert_ne!(pair[0], pair[1]);
789        }
790    }
791
792    #[test]
793    fn classifies_token_node_bogus_marker_ranges() {
794        assert!(SyntaxKind::Ident.is_token());
795        assert!(SyntaxKind::ScssVariable.is_token());
796        assert!(SyntaxKind::Selector.is_node());
797        assert!(SyntaxKind::LessMixinCall.is_node());
798        assert!(SyntaxKind::BogusSelector.is_bogus());
799        assert!(SyntaxKind::Root.is_marker());
800        assert!(SyntaxKind::Whitespace.is_trivia());
801        assert!(SyntaxKind::ScssUseRule.is_dialect_specific());
802    }
803
804    #[test]
805    fn declares_four_style_dialects_and_module_modes() {
806        assert_eq!(StyleDialect::ALL.len(), 4);
807        assert_eq!(ModuleMode::ALL.len(), 2);
808    }
809
810    #[test]
811    fn cstree_round_trip_preserves_known_kinds() {
812        for kind in [
813            SyntaxKind::Ident,
814            SyntaxKind::Selector,
815            SyntaxKind::ScssUseRule,
816            SyntaxKind::BogusLessGuard,
817            SyntaxKind::Root,
818        ] {
819            let raw = kind.into_raw();
820            assert_eq!(SyntaxKind::from_raw(raw), kind);
821        }
822    }
823
824    #[test]
825    fn declares_bogus_superset_contract() {
826        let bogus_count = SyntaxKind::ALL
827            .iter()
828            .filter(|kind| kind.is_bogus())
829            .count();
830
831        assert!(bogus_count >= 33);
832    }
833
834    #[test]
835    fn syntax_kind_count_tracks_phase_alpha_contract() {
836        let token_count = SyntaxKind::ALL
837            .iter()
838            .filter(|kind| kind.is_token())
839            .count();
840        let node_count = SyntaxKind::ALL.iter().filter(|kind| kind.is_node()).count();
841
842        assert!(SyntaxKind::ALL.len() >= 160);
843        assert!(token_count >= 80);
844        assert!(node_count >= 80);
845    }
846
847    #[test]
848    fn summarizes_phase_alpha_boundary_contract() {
849        let summary = summarize_omena_syntax_boundary();
850
851        assert_eq!(summary.product, "omena-syntax.boundary");
852        assert_eq!(summary.phase, "h1-alpha-syntax-substrate");
853        assert_eq!(summary.syntax_kind_owner_crate, "omena-syntax");
854        assert_eq!(
855            summary.parser_consumer_policy,
856            "parserConsumesOmenaSyntaxKindNoLocalTaxonomy"
857        );
858        assert!(summary.syntax_kind_count >= 160);
859        assert!(summary.bogus_kind_count >= 33);
860        assert_eq!(summary.style_dialect_count, 4);
861        assert_eq!(summary.module_mode_count, 2);
862        assert_eq!(summary.symbol_kind_count, SymbolKind::ALL.len());
863        assert_eq!(summary.scope_kind_count, ScopeKind::ALL.len());
864        assert_eq!(summary.reference_kind_count, ReferenceKind::ALL.len());
865        assert!(summary.cstree_integration_ready);
866        assert!(SyntaxKind::ScssUseRule.is_dialect());
867        assert!(
868            summary
869                .ready_surfaces
870                .contains(&"symbolScopeReferenceVocabulary")
871        );
872        assert!(summary.ready_surfaces.contains(&"semanticSoaTables"));
873        assert!(summary.ready_surfaces.contains(&"parserCstEquivalence"));
874        assert!(!summary.next_surfaces.contains(&"semanticSoaTables"));
875        assert!(!summary.next_surfaces.contains(&"parserCstEquivalence"));
876    }
877}