///|
pub(all) enum ZoneDirective {
OriginDirective(DomainName)
DefaultTtlDirective(Ttl)
} derive(Eq, Debug)
///|
fn directive_error(
code : ZoneErrorCode,
message : String,
token : ZoneToken,
) -> ZoneError {
ZoneError::new(code, message, token.span())
}
///|
fn require_directive_arity(
tokens : Array[ZoneToken],
expected : Int,
) -> Result[Unit, ZoneError] {
if tokens.length() == expected {
Ok(())
} else {
Err(
directive_error(
InvalidDirective,
"zone directive has an invalid number of fields",
tokens[0],
),
)
}
}
///|
fn parse_origin_directive(
tokens : Array[ZoneToken],
current_origin : DomainName?,
) -> Result[ZoneDirective, ZoneError] {
match require_directive_arity(tokens, 2) {
Ok(_) => ()
Err(error) => return Err(error)
}
let name = match parse_domain_name(tokens[1].text()) {
Ok(value) => value
Err(error) =>
return Err(
ZoneError::new(InvalidDomainName, error.message(), tokens[1].span()),
)
}
if name.is_absolute() {
Ok(OriginDirective(name))
} else {
match current_origin {
Some(origin) =>
match name.resolve(origin) {
Ok(value) => Ok(OriginDirective(value))
Err(error) => Err(error)
}
None =>
Err(
directive_error(
RelativeNameWithoutOrigin,
"relative $ORIGIN requires an existing absolute origin",
tokens[1],
),
)
}
}
}
///|
fn parse_ttl_directive(
tokens : Array[ZoneToken],
) -> Result[ZoneDirective, ZoneError] {
match require_directive_arity(tokens, 2) {
Ok(_) => ()
Err(error) => return Err(error)
}
match parse_ttl(tokens[1].text()) {
Ok(value) => Ok(DefaultTtlDirective(value))
Err(error) =>
Err(ZoneError::new(InvalidTtl, error.message(), tokens[1].span()))
}
}
///|
pub fn parse_zone_directive(
statement : ZoneStatement,
current_origin? : DomainName? = None,
) -> Result[ZoneDirective, ZoneError] {
let tokens = statement.tokens()
if tokens.length() == 0 {
return Err(
ZoneError::new(
InvalidDirective,
"zone directive statement is empty",
SourceSpan::point(0, 0),
),
)
}
let keyword = ascii_lower(tokens[0].text())
match keyword {
"$origin" => parse_origin_directive(tokens, current_origin)
"$ttl" => parse_ttl_directive(tokens)
"$include" =>
Err(
directive_error(
UnsupportedDirective,
"$INCLUDE requires caller-managed file I/O and is not loaded",
tokens[0],
),
)
_ =>
Err(
directive_error(
InvalidDirective,
"statement does not begin with a supported zone directive",
tokens[0],
),
)
}
}