///|
fn Parser::parse_string_group(
self : Parser,
optional : Bool,
) -> Token? raise ParseFailure {
match self.gullet.scan_argument(optional) {
None => None
Some(arg_token) => {
let builder = StringBuilder()
for ;; {
let token = self.fetch()
if token.text == "EOF" {
self.consume()
arg_token.text = builder.to_string()
break Some(arg_token)
}
builder.write_string(token.text)
self.consume()
}
}
}
}
///|
fn is_ascii_hex_digit(code : UInt16) -> Bool {
(code >= '0' && code <= '9') ||
(code >= 'a' && code <= 'f') ||
(code >= 'A' && code <= 'F')
}
///|
fn all_code_units(text : String, predicate : (UInt16) -> Bool) -> Bool {
guard !text.is_empty() else { false }
for index in 0.. String? {
if text.length() > 0 && text[0] == '#' {
let digits = text.unsafe_substring(start=1, end=text.length())
if (
digits.length() == 3 ||
digits.length() == 4 ||
digits.length() == 6 ||
digits.length() == 8
) &&
all_code_units(digits, is_ascii_hex_digit) {
Some(text)
} else {
None
}
} else if text.length() == 6 && all_code_units(text, is_ascii_hex_digit) {
Some("#" + text)
} else if all_code_units(text, is_ascii_alphabetic) {
Some(text)
} else {
None
}
}
///|
fn Parser::parse_color_group(
self : Parser,
optional : Bool,
) -> ParseNode? raise ParseFailure {
self
.parse_string_group(optional)
.map(token => {
guard normalized_color(token.text) is Some(color) else {
raise InvalidArgument(
message="Invalid color: '" + token.text + "'",
loc=token.loc,
)
}
ColorToken(mode=self.mode, color~)
})
}