Cli.bend
bend-edit-distance@0.2.0.0 · 63 lines · 0 definitions
1import Base
2
3# Shared boundary for native distance executables. Keep validation ahead of
4# distance evaluation, including empty-input shortcuts in either algorithm.
5type InputStatus is Data:
6 Supported{}
7 NonAscii{}
8 TooLong{}
9
10def max_sequence_length() -> Nat:
11 4096n
12
13def scan_ascii(rest: Unit -> InputStatus, ascii: Bool) -> InputStatus:
14 match ascii:
15 case True{}:
16 rest(Unit{})
17 case False{}:
18 NonAscii{}
19
20# Inspect at most limit + 1 characters, without an unbounded length pass.
21# Match the empty string first so a sequence exactly at the limit is valid.
22def scan(sequence: String, remaining: Nat) -> InputStatus:
23 match sequence remaining:
24 case SNil{} _:
25 Supported{}
26 case SCon{h, t} 0n:
27 TooLong{}
28 case SCon{h, t} 1n+p:
29 +code = Char.to_u32(h)
30 scan_ascii(_ => scan(t, p),
31 Bool.and(U32.is_gt(code, 0), U32.is_le(code, 127)))
32
33def combine(query: InputStatus, target: InputStatus) -> InputStatus:
34 match query:
35 case Supported{}:
36 target
37 case NonAscii{}:
38 NonAscii{}
39 case TooLong{}:
40 TooLong{}
41
42def validate(query: String, target: String) -> InputStatus:
43 q t = scan(query, max_sequence_length()) scan(target, max_sequence_length())
44 combine(q, t)
45
46def respond(~distance: String -> String -> Nat, query: String, target: String,
47 status: InputStatus) -> IO(Unit):
48 match status:
49 case Supported{}:
50 IO.print(Nat.show(distance(query, target)))
51 case NonAscii{}:
52 IO.die(Unit, 2, "Sequences must contain only non-NUL ASCII characters (U+0001..U+007F)")
53 case TooLong{}:
54 IO.die(Unit, 2, "Sequence length exceeds maximum of " ++
55 Nat.show(max_sequence_length()) ++ " ASCII characters per sequence")
56
57def run(~distance: String -> String -> Nat, args: List<String>) -> IO(Unit):
58 match args:
59 # IO.args includes argv[0]; the native runtime consumes flags before --.
60 case Con{_, Con{+query, Con{+target, Nil{}}}}:
61 respond(~distance, query, target, validate(query, target))
62 case _:
63 IO.die(Unit, 2, "Expected QUERY TARGET")