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}