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
package Torello.CSS;

import Torello.Java.Additional.ByRef;

import java.util.Vector;
import java.util.function.Consumer;

/**
 * CSS-Tokenizer Class for <B>At-Rule</B> Identifiers.
 */
@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="CSS_TOK")
public class AtKeyword extends Identifier
    implements CharSequence, java.io.Serializable, Comparable<CharSequence>
{
    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
    protected static final long serialVersionUID = 1;


    // ********************************************************************************************
    // ********************************************************************************************
    // Private Constructor, API "is" and "if" Methods
    // ********************************************************************************************
    // ********************************************************************************************


    private AtKeyword(
            final int[]     css,
            final int       sPos,
            final int       ePos,
            final String    identifier
        )
    { super(css, sPos, ePos, identifier); }

    @Override 
    public final boolean isAtKeyword() { return true; }

    @Override
    public final AtKeyword ifAtKeyword() { return this; }


    // ********************************************************************************************
    // ********************************************************************************************
    // User's Constructor: a static "build" method
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * <EMBED CLASS=defs DATA-TOK=AtKeyword DATA-P=atKeyword>
     * <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_DESC>
     * @param atKeyword <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_PARAM>
     * @return <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_RET>
     * @throws TokenizeException <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_TOK_EX>
     */
    @SuppressWarnings("unchecked")
    public static AtKeyword build(final String atKeyword)
    { return (AtKeyword) CSSToken.build(atKeyword, INPUT_CHECKER, AtKeyword::consume); }

    private static final CSSToken.InputChecker INPUT_CHECKER = (int[] css) ->
    {
        if (css.length < 2) throw new TokenizeException(AtKeyword.class);

        if (css[0] != '@') throw new TokenizeException
            ("Input String does not start with the @-Symbol");

        if (! Identifier.startsIdentSequence(css, 1)) throw new TokenizeException
            ("String-text after the opening @-Symbol does not constitute a valid CSS Identifier");
    };


    // ********************************************************************************************
    // ********************************************************************************************
    // CONSUME
    // ********************************************************************************************
    // ********************************************************************************************


    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    // Copied from: 
    // https://drafts.csswg.org/css-syntax-3/ - NO '#' Sub-Page Link
    // March 2024
    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    // This is an extremely simple one:
    // 
    // U+0040 COMMERCIAL AT (@)
    //
    // If the next 3 input code points would start an ident sequence, consume an ident sequence,
    // create an <at-keyword-token> with its value set to the returned value, and return it.
    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

    /**
     * This is a tokenizer method which <B>"consumes"</B> the next At-Rule Token from the
     * input Code-Point Array.
     * 
     * <EMBED CLASS=defs DATA-TOK=At-Rule-Identifier DATA-URL=at-keyword-token-diagram
     *      DATA-OP=Consume>
     * <EMBED CLASS=external-html DATA-FILE-ID=COPIED_CSS_WG_RR>
     * <EMBED CLASS=external-html DATA-FILE-ID=AT_KEYWORD_TOK_SVG>  
     */
    protected static void consume(                          // When invoked from 'CSSTokenizer'
            final int[]                 css,                // C, int[] css
            final ByRef<Integer>        POS,                // P, array-pos loop-variable
            final Consumer<CSSToken>    returnParsedToken   // T, Vector<CSSToken>.add
        )
    {
        // NOTE: This method is, indeed, package-private and would never be invoked unless the
        //       code-point at css[0] actually were an `@` Symbol.  The `build` method which allows
        //       a user to build an AtKeyword token also check this.
        //
        // It also guarantees that an actual identifer follows the `@` symbol

        final ByRef<String> identifier = new ByRef<>();

        final int sPos = POS.f; // When I finally get to "consumeIdentSequence", fix this!!
        final int ePos = Identifier.consumeIdentSequence(css, POS.f + 1, identifier);

        returnParsedToken.accept(new AtKeyword(css, sPos, ePos, identifier.f));

        POS.f = ePos;
    }
}