001package Torello.CSS;
002
003import Torello.Java.Additional.ByRef;
004
005import java.util.Vector;
006import java.util.function.Consumer;
007
008/**
009 * CSS-Tokenizer Class for <B>At-Rule</B> Identifiers.
010 */
011@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="CSS_TOK")
012public class AtKeyword extends Identifier
013    implements CharSequence, java.io.Serializable, Comparable<CharSequence>
014{
015    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
016    protected static final long serialVersionUID = 1;
017
018
019    // ********************************************************************************************
020    // ********************************************************************************************
021    // Private Constructor, API "is" and "if" Methods
022    // ********************************************************************************************
023    // ********************************************************************************************
024
025
026    private AtKeyword(
027            final int[]     css,
028            final int       sPos,
029            final int       ePos,
030            final String    identifier
031        )
032    { super(css, sPos, ePos, identifier); }
033
034    @Override 
035    public final boolean isAtKeyword() { return true; }
036
037    @Override
038    public final AtKeyword ifAtKeyword() { return this; }
039
040
041    // ********************************************************************************************
042    // ********************************************************************************************
043    // User's Constructor: a static "build" method
044    // ********************************************************************************************
045    // ********************************************************************************************
046
047
048    /**
049     * <EMBED CLASS=defs DATA-TOK=AtKeyword DATA-P=atKeyword>
050     * <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_DESC>
051     * @param atKeyword <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_PARAM>
052     * @return <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_RET>
053     * @throws TokenizeException <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_TOK_EX>
054     */
055    @SuppressWarnings("unchecked")
056    public static AtKeyword build(final String atKeyword)
057    { return (AtKeyword) CSSToken.build(atKeyword, INPUT_CHECKER, AtKeyword::consume); }
058
059    private static final CSSToken.InputChecker INPUT_CHECKER = (int[] css) ->
060    {
061        if (css.length < 2) throw new TokenizeException(AtKeyword.class);
062
063        if (css[0] != '@') throw new TokenizeException
064            ("Input String does not start with the @-Symbol");
065
066        if (! Identifier.startsIdentSequence(css, 1)) throw new TokenizeException
067            ("String-text after the opening @-Symbol does not constitute a valid CSS Identifier");
068    };
069
070
071    // ********************************************************************************************
072    // ********************************************************************************************
073    // CONSUME
074    // ********************************************************************************************
075    // ********************************************************************************************
076
077
078    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
079    // Copied from: 
080    // https://drafts.csswg.org/css-syntax-3/ - NO '#' Sub-Page Link
081    // March 2024
082    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
083    // This is an extremely simple one:
084    // 
085    // U+0040 COMMERCIAL AT (@)
086    //
087    // If the next 3 input code points would start an ident sequence, consume an ident sequence,
088    // create an <at-keyword-token> with its value set to the returned value, and return it.
089    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
090
091    /**
092     * This is a tokenizer method which <B>"consumes"</B> the next At-Rule Token from the
093     * input Code-Point Array.
094     * 
095     * <EMBED CLASS=defs DATA-TOK=At-Rule-Identifier DATA-URL=at-keyword-token-diagram
096     *      DATA-OP=Consume>
097     * <EMBED CLASS=external-html DATA-FILE-ID=COPIED_CSS_WG_RR>
098     * <EMBED CLASS=external-html DATA-FILE-ID=AT_KEYWORD_TOK_SVG>  
099     */
100    protected static void consume(                          // When invoked from 'CSSTokenizer'
101            final int[]                 css,                // C, int[] css
102            final ByRef<Integer>        POS,                // P, array-pos loop-variable
103            final Consumer<CSSToken>    returnParsedToken   // T, Vector<CSSToken>.add
104        )
105    {
106        // NOTE: This method is, indeed, package-private and would never be invoked unless the
107        //       code-point at css[0] actually were an `@` Symbol.  The `build` method which allows
108        //       a user to build an AtKeyword token also check this.
109        //
110        // It also guarantees that an actual identifer follows the `@` symbol
111
112        final ByRef<String> identifier = new ByRef<>();
113
114        final int sPos = POS.f; // When I finally get to "consumeIdentSequence", fix this!!
115        final int ePos = Identifier.consumeIdentSequence(css, POS.f + 1, identifier);
116
117        returnParsedToken.accept(new AtKeyword(css, sPos, ePos, identifier.f));
118
119        POS.f = ePos;
120    }
121}