1 # src/answer: reading an answer, which is the exit status on its own first 2 # line, then everything the program printed. 3 import Base 4 5 # one char of the status: a newline ends it, and any other char is part of it, 6 # with the rest of the status read only then 7 def code.at(nl: Bool, +ch: Char, rest: Unit -> String) -> String: 8 match nl: 9 case True{}: 10 SNil{} 11 case False{}: 12 SCon{ch, rest(Unit{})} 13 14 # the exit status a run answered with: the answer up to its first newline. 15 # It reads no further, so a long body costs nothing. 16 def code(out: String) -> String: 17 match out: 18 case SNil{}: 19 SNil{} 20 case SCon{+ch, tail}: 21 code.at(Char.is_eq(ch, '\n'), ch, _u => code(tail)) 22 23 # one char before the body: a newline starts the body, which is the rest as 24 # it stands, and any other char is still the status 25 def text.at(nl: Bool, +tail: String, rest: Unit -> String) -> String: 26 match nl: 27 case True{}: 28 tail 29 case False{}: 30 rest(Unit{}) 31 32 # what the program printed, stdout and stderr together: the answer after its 33 # first newline, or nothing when it has none. The body is returned as it 34 # stands, never walked. 35 def text(out: String) -> String: 36 match out: 37 case SNil{}: 38 SNil{} 39 case SCon{ch, +tail}: 40 text.at(Char.is_eq(ch, '\n'), tail, _u => text(tail)) 41 42 # a run that finished with status 0 43 def ok(+out: String) -> Bool: 44 String.eq(code(out), "0")