///|
priv enum PluralTokenKind {
Number(Int)
Variable
LeftParen
RightParen
Question
Colon
LogicalOr
LogicalAnd
Equal
NotEqual
Less
LessEqual
Greater
GreaterEqual
Plus
Minus
Star
Slash
Percent
Bang
End
} derive(Eq)
///|
priv struct PluralToken {
kind : PluralTokenKind
position : Int
}
///|
fn make_plural_token(kind : PluralTokenKind, position : Int) -> PluralToken {
{ kind, position }
}
///|
fn tokenize_plural(
expression : String,
) -> Array[PluralToken] raise GettextError {
let chars = expression.to_array()
let tokens : Array[PluralToken] = []
let mut index = 0
while index < chars.length() {
let c = chars[index]
if c.is_whitespace() {
index += 1
continue
}
if c is ('0'..='9') {
let start = index
let mut value = 0
while index < chars.length() && chars[index] is ('0'..='9') {
let digit = chars[index].to_int() - '0'.to_int()
if value > 214748364 || (value == 214748364 && digit > 7) {
raise PluralSyntax(
position=start,
message="integer literal exceeds MoonBit Int range",
)
}
value = value * 10 + digit
index += 1
}
tokens.push(make_plural_token(Number(value), start))
continue
}
match c {
'n' => {
tokens.push(make_plural_token(Variable, index))
index += 1
}
'(' => {
tokens.push(make_plural_token(LeftParen, index))
index += 1
}
')' => {
tokens.push(make_plural_token(RightParen, index))
index += 1
}
'?' => {
tokens.push(make_plural_token(Question, index))
index += 1
}
':' => {
tokens.push(make_plural_token(Colon, index))
index += 1
}
'+' => {
tokens.push(make_plural_token(Plus, index))
index += 1
}
'-' => {
tokens.push(make_plural_token(Minus, index))
index += 1
}
'*' => {
tokens.push(make_plural_token(Star, index))
index += 1
}
'/' => {
tokens.push(make_plural_token(Slash, index))
index += 1
}
'%' => {
tokens.push(make_plural_token(Percent, index))
index += 1
}
'!' =>
if index + 1 < chars.length() && chars[index + 1] == '=' {
tokens.push(make_plural_token(NotEqual, index))
index += 2
} else {
tokens.push(make_plural_token(Bang, index))
index += 1
}
'=' =>
if index + 1 < chars.length() && chars[index + 1] == '=' {
tokens.push(make_plural_token(Equal, index))
index += 2
} else {
raise PluralSyntax(
position=index,
message="use == for equality in a plural expression",
)
}
'<' =>
if index + 1 < chars.length() && chars[index + 1] == '=' {
tokens.push(make_plural_token(LessEqual, index))
index += 2
} else {
tokens.push(make_plural_token(Less, index))
index += 1
}
'>' =>
if index + 1 < chars.length() && chars[index + 1] == '=' {
tokens.push(make_plural_token(GreaterEqual, index))
index += 2
} else {
tokens.push(make_plural_token(Greater, index))
index += 1
}
'&' =>
if index + 1 < chars.length() && chars[index + 1] == '&' {
tokens.push(make_plural_token(LogicalAnd, index))
index += 2
} else {
raise PluralSyntax(
position=index,
message="use && for logical conjunction",
)
}
'|' =>
if index + 1 < chars.length() && chars[index + 1] == '|' {
tokens.push(make_plural_token(LogicalOr, index))
index += 2
} else {
raise PluralSyntax(
position=index,
message="use || for logical disjunction",
)
}
_ =>
raise PluralSyntax(
position=index,
message="unexpected character '\{c}' in plural expression",
)
}
}
tokens.push(make_plural_token(End, chars.length()))
tokens
}