///|
fn selected_node(
doc : Document,
section : String,
key : String,
) -> Result[Node, Diagnostic] {
let entries = doc.entries(section, key)
if entries.is_empty() {
return Err(edit_problem("VALUE001", "key is missing"))
}
if entries.length() > 1 && doc.dialect.duplicates == Reject {
return Err(
diagnostic(
"VALUE002",
"key has ambiguous duplicates",
entries[1].key_span,
),
)
}
let node = if doc.dialect.duplicates == LastWins {
entries[entries.length() - 1]
} else {
entries[0]
}
if doc.diagnostics.any(d => {
d.severity == Error &&
d.span.start >= node.span.start &&
d.span.start < node.span.end
}) {
return Err(
diagnostic("VALUE003", "value has syntax errors", node.value_span),
)
}
Ok(node)
}
///|
/// Decimal signed 32-bit integer only; overflow is checked before conversion.
fn decimal_int(value : String) -> Int? {
if value.length() == 0 {
return None
}
let negative = value[0] == '-'
let start = if negative || value[0] == '+' { 1 } else { 0 }
if start == value.length() {
return None
}
let mut result : Int64 = 0
let limit : Int64 = if negative { 2147483648 } else { 2147483647 }
for i = start; i < value.length(); i = i + 1 {
if value[i] < '0' || value[i] > '9' {
return None
}
let digit = value[i].to_int() - 48
result = result * 10 + Int64::from_int(digit)
if result > limit {
return None
}
}
Some((if negative { -result } else { result }).to_int())
}
///|
fn boolean(value : String) -> Bool? {
match value.to_lower() {
"true" | "yes" | "on" | "1" => Some(true)
"false" | "no" | "off" | "0" => Some(false)
_ => None
}
}
///|
pub fn Document::get_int(
self : Document,
section : String,
key : String,
) -> Result[Int, Diagnostic] {
match selected_node(self, section, key) {
Err(e) => Err(e)
Ok(n) =>
match decimal_int(n.value) {
Some(v) => Ok(v)
None =>
Err(
diagnostic(
"VALUE004",
"expected decimal signed 32-bit integer",
n.value_span,
),
)
}
}
}
///|
pub fn Document::get_bool(
self : Document,
section : String,
key : String,
) -> Result[Bool, Diagnostic] {
match selected_node(self, section, key) {
Err(e) => Err(e)
Ok(n) =>
match boolean(n.value) {
Some(v) => Ok(v)
None =>
Err(
diagnostic(
"VALUE005",
"expected true/false, yes/no, on/off or 1/0",
n.value_span,
),
)
}
}
}