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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package Torello.CSS;

import Torello.Java.Additional.ByRef;

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

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


    // ********************************************************************************************
    // ********************************************************************************************
    // Public & Final Fields
    // ********************************************************************************************
    // ********************************************************************************************


    public final boolean isID;


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


    private Hash(
            final int[]     css,
            final int       sPos,
            final int       ePos,
            final String    identifier,
            final boolean   isID
        )
    {
        super(css, sPos, ePos, identifier);
        this.isID = isID;
    }

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

    @Override
    public final Hash ifHash() { return this; }


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


    /**
     * <EMBED CLASS=defs DATA-TOK=Hash DATA-P=hashIdentifier>
     * <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_DESC>
     * @param hashIdentifier <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 Hash build(final String hashIdentifier)
    { return (Hash) CSSToken.build(hashIdentifier, INPUT_CHECKER, Hash::consume); }

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

        if (! Hash.is(css, 0)) throw new TokenizeException
            ("String-text beginning does not constitute a valid CSS Hash-Token");
    };


    // ********************************************************************************************
    // ********************************************************************************************
    // Tokenizer's "is" Method(s)
    // ********************************************************************************************
    // ********************************************************************************************


    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    // Copied from:
    // https://drafts.csswg.org/css-syntax-3/#consume-token
    // March 27th, 2024
    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    // U+0023 NUMBER SIGN (#)
    //
    // ** If the next input code point is an ident code point or the next two input code points are
    //    a valid escape, then [TRUE]
    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

    static boolean is(int[] css, final int sPos)
    {
        if (css[sPos] != '#') return false;

        final int pos = sPos + 1;

        if (pos >= css.length) return false;

        if (Identifier.isIdentCodePoint(css[pos])) return true;

        if ((pos + 1) >= css.length) return false;

        return CSSUtil.isValidEscape(css, pos);
    }


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


    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    // Copied from:
    // https://drafts.csswg.org/css-syntax-3/#consume-token
    // March 27th, 2024
    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    // Create a <hash-token>.
    // 
    // ** If the next 3 input code points would start an ident sequence, set the <hash-token>’s
    //    type flag to "id".
    // ** Consume an ident sequence, and set the <hash-token>’s value to the returned string.
    // ** Return the <hash-token>.
    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

    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
        )
    {
        final boolean       isID        = Identifier.startsIdentSequence(css, POS.f + 1);
        final ByRef<String> identifier  = new ByRef<String>();

        final int ePos = Identifier.consumeIdentSequence(css, POS.f + 1, identifier);

        returnParsedToken.accept(new Hash(css, POS.f, ePos, identifier.f, isID));

        POS.f = ePos;
    }
}