AlignmentCli.bend
bend-edit-distance@0.2.0.0 · 104 lines · 0 definitions
1import Base
2import bend-edit-distance@0.2.0.0/Cli.bend as CLI
3import bend-edit-distance@0.2.0.0/EdlibTypes.bend as E
4
5def read_mode(value: String) -> Maybe<&2, E.Mode>:
6 match value:
7 case "NW":
8 Some{E.NW{}}
9 case "SHW":
10 Some{E.SHW{}}
11 case "HW":
12 Some{E.HW{}}
13 case _:
14 None{}
15
16def read_task(value: String) -> Maybe<&2, E.Task>:
17 match value:
18 case "DISTANCE":
19 Some{E.Distance{}}
20 case "LOC":
21 Some{E.Locations{}}
22 case "PATH":
23 Some{E.Path{}}
24 case _:
25 None{}
26
27def read_format(value: String) -> Maybe<&2, E.CigarFormat>:
28 match value:
29 case "STANDARD":
30 Some{E.Standard{}}
31 case "EXTENDED":
32 Some{E.Extended{}}
33 case _:
34 None{}
35
36def bounded_threshold(value: Nat, valid: Bool) -> Maybe<&2, E.Threshold>:
37 match valid:
38 case True{}:
39 Some{E.MaxDistance{value}}
40 case False{}:
41 None{}
42
43def negative_threshold(magnitude: Nat, valid: Bool) -> Maybe<&2, E.Threshold>:
44 match magnitude valid:
45 case _ False{}:
46 None{}
47 case 0n True{}:
48 Some{E.MaxDistance{0n}}
49 case _ True{}:
50 Some{E.Unlimited{}}
51
52def read_threshold(value: String) -> Maybe<&2, E.Threshold>:
53 match value:
54 case SCon{'-', digits}:
55 do Maybe<&2, E.Threshold>:
56 +magnitude : Nat <- Nat.read(digits)
57 negative_threshold(magnitude, Nat.is_le(magnitude, 2147483648n))
58 case _:
59 do Maybe<&2, E.Threshold>:
60 +maximum : Nat <- Nat.read(value)
61 bounded_threshold(maximum, Nat.is_le(maximum, 2147483647n))
62
63def read_pairs(value: String) -> Maybe<&2, List<&2, E.EqualityPair>>:
64 match value:
65 case SNil{}:
66 Some{Nil{}}
67 case SCon{_, SNil{}}:
68 None{}
69 case SCon{first, SCon{second, tail}}:
70 do Maybe<&2, List<&2, E.EqualityPair>>:
71 pairs : List<&2, E.EqualityPair> <- read_pairs(tail)
72 return E.EqualityPair{first, second} <> pairs
73
74def parse(mode: String, task: String, threshold: String, pairs: String,
75 format: String) -> Maybe<&2, E.AlignConfig>:
76 do Maybe<&2, E.AlignConfig>:
77 m : E.Mode <- read_mode(mode)
78 t : E.Task <- read_task(task)
79 k : E.Threshold <- read_threshold(threshold)
80 eq : List<&2, E.EqualityPair> <- read_pairs(pairs)
81 c : E.CigarFormat <- read_format(format)
82 return E.AlignConfig{m, t, k, eq, c}
83
84def respond(~align: String -> String -> E.AlignConfig -> E.AlignResult,
85 query: String, target: String, config: Maybe<&2, E.AlignConfig>,
86 status: CLI.InputStatus) -> IO(Unit):
87 match config status:
88 case None{} _:
89 IO.die(Unit, 2, "Invalid alignment configuration")
90 case Some{value} CLI.Supported{}:
91 IO.print(E.result_show(align(query, target, value)))
92 case _ CLI.NonAscii{}:
93 IO.die(Unit, 2, "Sequences and equality pairs must contain only non-NUL ASCII characters")
94 case _ CLI.TooLong{}:
95 IO.die(Unit, 2, "Sequence or equality-pair length exceeds maximum of 4096 ASCII characters")
96
97def run(~align: String -> String -> E.AlignConfig -> E.AlignResult,
98 args: List<String>) -> IO(Unit):
99 match args:
100 case _ <> "--config" <> mode <> task <> threshold <> +pairs <> format <> +query <> +target <> Nil{}:
101 respond(~align, query, target, parse(mode, task, threshold, pairs, format),
102 CLI.combine(CLI.validate(query, target), CLI.scan(pairs, CLI.max_sequence_length())))
103 case _:
104 IO.die(Unit, 2, "Expected QUERY TARGET or --config MODE TASK K PAIRS CIGAR QUERY TARGET")