///|
pub(all) struct Span {
start : Int
end : Int
line : Int
column : Int
} derive(Eq, Debug)
///|
pub(all) struct Diagnostic {
code : String
message : String
span : Span
} derive(Eq, Debug)
///|
pub(all) suberror SieveError {
SieveError(Diagnostic)
} derive(Debug)
///|
pub(all) struct Limits {
source_chars : Int
tokens : Int
string_chars : Int
depth : Int
steps : Int
comparisons : Int
actions : Int
headers : Int
variables : Int
} derive(Eq, Debug)
///|
pub fn Limits::default() -> Limits {
{
source_chars: 262144,
tokens: 32768,
string_chars: 65536,
depth: 64,
steps: 100000,
comparisons: 2000000,
actions: 128,
headers: 1000,
variables: 128,
}
}
///|
pub fn Limits::check(self : Limits) -> Unit raise SieveError {
if self.source_chars < 1 ||
self.source_chars > 4194304 ||
self.tokens < 1 ||
self.tokens > 262144 ||
self.string_chars < 1 ||
self.string_chars > self.source_chars ||
self.depth < 1 ||
self.depth > 128 ||
self.steps < 1 ||
self.steps > 10000000 ||
self.comparisons < 1 ||
self.comparisons > 100000000 ||
self.actions < 1 ||
self.actions > 4096 ||
self.headers < 1 ||
self.headers > 100000 ||
self.variables < 1 ||
self.variables > 4096 {
fail(
"limit.invalid",
"limits must be positive and within safe ceilings",
origin(),
)
}
}
///|
fn origin() -> Span {
{ start: 0, end: 0, line: 1, column: 1 }
}
///|
fn fail(code : String, message : String, span : Span) -> Unit raise SieveError {
raise SieveError({ code, message, span })
}
///|
fn ascii_lower(text : String) -> String {
let b = StringBuilder()
for c in text {
b.write_char(c.to_ascii_lowercase())
}
b.to_string()
}
///|
fn chars_text(chars : Array[Char], start : Int, end : Int) -> String {
let b = StringBuilder()
for i = start; i < end; i = i + 1 {
b.write_char(chars[i])
}
b.to_string()
}