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