001package Torello.CSS;
002
003import Torello.Java.Additional.ByRef;
004
005import java.util.Vector;
006import java.util.function.Consumer;
007
008/** Represents a CSS Comment-Block */
009@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="CSS_TOK")
010public class Comment extends CSSToken
011    implements CharSequence, java.io.Serializable, Comparable<CharSequence>
012{
013    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
014    protected static final long serialVersionUID = 1;
015
016
017    // ********************************************************************************************
018    // ********************************************************************************************
019    // Private Constructor, API "is" and "if" Methods
020    // ********************************************************************************************
021    // ********************************************************************************************
022
023
024    private Comment(final int[] css, final int sPos, final int ePos)
025    { super(css, sPos, ePos); }
026
027    @Override
028    public final boolean isComment() { return true; }
029
030    @Override
031    public final Comment ifComment() { return this; }
032
033
034    // ********************************************************************************************
035    // ********************************************************************************************
036    // User's Constructor: a static "build" method
037    // ********************************************************************************************
038    // ********************************************************************************************
039
040
041    /**
042     * <EMBED CLASS=defs DATA-TOK=Comment DATA-P=commentStr>
043     * <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_DESC>
044     * @param commentStr <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_PARAM>
045     * @return <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_RET>
046     * @throws TokenizeException <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_TOK_EX>
047     */
048    @SuppressWarnings("unchecked")
049    public static Comment build(final String commentStr)
050    { return (Comment) CSSToken.build(commentStr, INPUT_CHECKER, Comment::consume); }
051
052    private static final CSSToken.InputChecker INPUT_CHECKER = (int[] css) ->
053    {
054        if (css.length < 4) throw new TokenizeException(Comment.class);
055
056        if ((css[0] != '/') || (css[1] != '*')) throw new TokenizeException
057            ("Input-String does not start with \"/*\"");
058    };
059
060
061    // ********************************************************************************************
062    // ********************************************************************************************
063    // Tokenizer's "is" Method(s)
064    // ********************************************************************************************
065    // ********************************************************************************************
066
067
068    /**
069     * Checks whether or not the next token to consume is a Comment
070     * <EMBED CLASS=defs DATA-TOK=Comment DATA-URL=comment-diagram DATA-OP=Check>
071     * <EMBED CLASS=external-html DATA-FILE-ID=COPIED_CSS_WG_RR>
072     * <EMBED CLASS=external-html DATA-FILE-ID=COMMENT_SVG>
073     * @param css CSS-{@code String} as an array of code-points.
074     * @param sPos The array-index where the tokenizer is to consume its next token
075     * @return {@code TRUE} if and only if the next token in the array is a comment
076     */
077    public static boolean is(final int[] css, final int sPos)
078    {
079        if ((sPos + 1) >= css.length)
080            return false;
081
082        if ((css[sPos] != '/') || (css[sPos + 1] != '*'))
083            return false;
084
085        return true;
086    }
087
088
089    // ********************************************************************************************
090    // ********************************************************************************************
091    // CONSUME
092    // ********************************************************************************************
093    // ********************************************************************************************
094
095
096    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
097    // Copied from:
098    // https://drafts.csswg.org/css-syntax-3/#consume-comment
099    // April 2024
100    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
101    //
102    // 4.3.2. Consume comments
103    // 
104    // This section describes how to consume comments from a stream of code points. It returns
105    // nothing.
106    // 
107    // If the next two input code point are U+002F SOLIDUS (/) followed by a U+002A ASTERISK (*),
108    // consume them and all following code points up to and including the first U+002A ASTERISK (*)
109    // followed by a U+002F SOLIDUS (/), or up to an EOF code point. Return to the start of this
110    // step.
111    // 
112    // If the preceding paragraph ended by consuming an EOF code point, this is a parse error.
113    // 
114    // Return nothing.
115
116    /**
117     * This is a tokenizer method which <B>"consumes"</B> the next Comment-Token from the
118     * input Code-Point Array.
119     * 
120     * <EMBED CLASS=defs DATA-TOK=Comment DATA-URL=consume-comment
121     *      DATA-OP=Consume>
122     * <EMBED CLASS=external-html DATA-FILE-ID=COPIED_CSS_WG>
123     * <EMBED CLASS=external-html DATA-FILE-ID=COMMENTS>  
124     */
125    protected static void consume(                              // When invoked from 'CSSTokenizer'
126            final int[]                     css,                // C, int[] css
127            final ByRef<Integer>            POS,                // P, array-pos loop-variable
128            final Consumer<CSSToken>        returnParsedToken,  // T, Vector<CSSToken>.add
129            final Consumer<TokenizeError>   errorEncountered    // E, Vector<TokenizeError>.add
130        )
131    {
132        int pos = POS.f + 2;
133
134        for (; (pos + 1) < css.length; pos++)
135
136            if ((css[pos] == '*') && (css[pos + 1] == '/'))
137            {
138                returnParsedToken.accept(new Comment(css, POS.f, pos += 2));
139                POS.f = pos;
140                return;
141            }
142
143        errorEncountered.accept(
144            new TokenizeError(
145                css, POS.f, pos, Comment.class,
146                "An Opening-Comment '/*' Character-Sequence was encountered, but EOF was " +
147                "reached before the Matching, Closing '*/' sequence was identified."
148            ));
149
150        POS.f = pos;
151    }
152}