///|
pub fn execute(request : Json) -> Json {
dispatch(from_json(request)).to_json() catch {
InputError(message) =>
record([("verdict", String("invalid_input")), ("reason", String(message))]).to_json()
}
}
///|
fn word(value : Value) -> Array[String] raise InputError {
let result = array(value).map(v => identifier(v))
if result.length() > 20000 {
raise InputError("input sequence exceeds 20000 symbols")
}
result
}
///|
fn dispatch(request : Value) -> Value raise InputError {
let operation = if has(request, "operation") {
string(field(request, "operation"))
} else {
"compare"
}
let max_pairs = limit(request, "max_pairs", 20000, 65536)
let max_steps = limit(request, "max_steps", 2000000, 10000000)
match operation {
"compare" | "verify_difference" => {
let allowed = ["operation", "old", "new", "mode"]
if operation == "compare" {
allowed.push("max_pairs")
allowed.push("max_steps")
} else {
allowed.push("word")
}
fields_only(request, allowed)
let old = parse_machine(required(request, "old"))
let new = parse_machine(required(request, "new"))
let mode = if has(request, "mode") {
string(field(request, "mode"))
} else {
"equivalence"
}
if mode != "equivalence" && mode != "backward" {
raise InputError("mode must be equivalence or backward")
}
if operation == "verify_difference" {
verify_difference(old, new, word(required(request, "word")), mode)
} else {
comparison(old, new, mode, max_pairs, max_steps)
}
}
"audit_suite" => {
fields_only(request, ["operation", "machine", "tests"])
audit_suite(
parse_machine(required(request, "machine")),
array(required(request, "tests")),
)
}
"suite" => {
fields_only(request, ["operation", "machine", "max_tests"])
transition_suite(
parse_machine(required(request, "machine")),
limit(request, "max_tests", 4096, 4096),
)
}
"minimize" => {
fields_only(request, ["operation", "machine"])
minimize_machine(parse_machine(required(request, "machine")))
}
"run" | "analyze" => {
fields_only(
request,
if operation == "run" {
["operation", "machine", "word"]
} else {
["operation", "machine"]
},
)
let machine = parse_machine(required(request, "machine"))
if operation == "run" {
observations(machine, word(required(request, "word")))
} else {
let (reached, access) = reachable(machine)
record([
("machine", machine_value(machine)),
("reachable", strings(reached.map(fn(i) { machine.states[i] }))),
(
"access_sequences",
Array(
reached.map(fn(i) {
record([
("state", String(machine.states[i])),
("word", strings(access[i])),
])
}),
),
),
(
"missing_transitions",
Number(
(machine.states.length() * machine.alphabet.length() -
machine.edges.length()).to_double(),
),
),
])
}
}
_ => raise InputError("unsupported operation: " + operation)
}
}