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