///|
/// Whether JavaScript's `\s` (and `String.prototype.trim`) takes `c` for
/// white space.
pub fn is_js_space(c : Char) -> Bool {
c
is ('\t'
| '\n'
| '\u{0b}'
| '\u{0c}'
| '\r'
| ' '
| '\u{a0}'
| '\u{1680}'
| '\u{2000}'..<='\u{200a}'
| '\u{2028}'
| '\u{2029}'
| '\u{202f}'
| '\u{205f}'
| '\u{3000}'
| '\u{feff}')
}
///|
/// JavaScript's `parseFloat`: the number the longest numeric prefix of
/// the text stands for, `NaN` without one.
pub fn parse_float(text : String) -> Double {
let chars = text.to_array()
let n = chars.length()
let mut i = 0
while i < n && is_js_space(chars[i]) {
i += 1
}
let start = i
let mut negative = false
if i < n && chars[i] is ('+' | '-') {
negative = chars[i] == '-'
i += 1
}
if String::from_array(chars[i:]).has_prefix("Infinity") {
return if negative { @double.neg_infinity } else { @double.infinity }
}
let is_digit = (k : Int32) => k < n && chars[k] is ('0'..<='9')
let mut digits = 0
while is_digit(i) {
i += 1
digits += 1
}
if i < n && chars[i] == '.' && (digits > 0 || is_digit(i + 1)) {
i += 1
while is_digit(i) {
i += 1
digits += 1
}
}
if digits == 0 {
return @double.not_a_number
}
if i < n && chars[i] is ('e' | 'E') {
let mut j = i + 1
if j < n && chars[j] is ('+' | '-') {
j += 1
}
if is_digit(j) {
while is_digit(j) {
j += 1
}
i = j
}
}
let literal = String::from_array(chars[start:i])
// A trailing point is part of the number in JavaScript.
let literal = if literal.has_suffix(".") { literal + "0" } else { literal }
let literal = literal
.replace(old="+.", new="+0.")
.replace(old="-.", new="-0.")
let literal = if literal.has_prefix(".") { "0" + literal } else { literal }
let literal = literal
.replace(old=".e", new=".0e")
.replace(old=".E", new=".0E")
@string.parse_double(literal) catch {
_ => @double.not_a_number
}
}
///|
/// JavaScript's `Number(value)` for a value read from configuration or
/// metadata: a number as it is, a string as a numeric literal (`"20"` is
/// 20, `""` is 0, `"20px"` is `NaN`), `true` and `false` as 1 and 0,
/// `null` as 0. An array goes through its text, its elements joined by
/// commas (`[5]` is 5, `[]` is 0); an object is `NaN`.
pub fn to_number(value : Json) -> Double {
match value {
Number(n, ..) => n
String(text) => @journeycommon.js_number(text)
True => 1.0
False | Null => 0.0
Array([]) => 0.0
Array([Null]) => 0.0
Array([String(_) | Number(_, ..) | Array(_) as element]) =>
to_number(element)
Array(_) | Object(_) => @double.not_a_number
}
}