a gleam implementation of a CS assignment originally written in cpp
at gleam 3.7 kB view raw
1import gleam/int 2import gleam/io 3import gleam/list 4import gleam/result 5import gleam/string 6import input.{input} 7import simplifile 8 9const filepath = "./OT.txt" 10 11pub type Reference { 12 Reference(book: String, chapter: Int, verse: Int) 13} 14 15pub type Phase { 16 Book 17 Chapter 18 Verse 19 Done 20} 21 22pub type ScanState { 23 ScanState( 24 phase: Phase, 25 ref: Reference, 26 found_book: Bool, 27 found_chapter: Bool, 28 verse_text: Result(String, String), 29 ) 30} 31 32pub type ScanResult { 33 ScanResult(ref: Reference, verse: Result(String, String)) 34} 35 36pub fn parse_reference(input: String) -> Result(Reference, String) { 37 let parts = string.split(input, on: " ") 38 39 case parts { 40 [book, chapter_s, verse_s] -> 41 case int.parse(chapter_s) { 42 Ok(chapter) -> 43 case int.parse(verse_s) { 44 Ok(verse) -> 45 Ok(Reference(book: string.uppercase(book), chapter:, verse:)) 46 Error(_) -> Error("Invalid verse: " <> verse_s) 47 } 48 Error(_) -> Error("Invalid chapter: " <> chapter_s) 49 } 50 [book_p1, book_p2, chapter_s, verse_s] -> 51 case int.parse(chapter_s) { 52 Ok(chapter) -> 53 case int.parse(verse_s) { 54 Ok(verse) -> 55 Ok(Reference( 56 book: string.uppercase(book_p1 <> " " <> book_p2), 57 chapter:, 58 verse:, 59 )) 60 Error(_) -> Error("Invalid verse: " <> verse_s) 61 } 62 Error(_) -> Error("Invalid chapter: " <> chapter_s) 63 } 64 65 _ -> Error("invalid parse") 66 } 67} 68 69pub fn bible_scan( 70 reference reference: Reference, 71 bible bible: String, 72) -> ScanResult { 73 let inital_state = 74 ScanState( 75 phase: Book, 76 ref: reference, 77 found_book: False, 78 found_chapter: False, 79 verse_text: Error("Verse not found"), 80 ) 81 82 let bible_lines = string.split(bible, "\n") 83 84 let result = 85 list.fold(bible_lines, inital_state, fn(state, line) -> ScanState { 86 case state.phase { 87 Done -> state 88 Book -> 89 case line { 90 "THE BOOK OF " <> book -> 91 case book == state.ref.book { 92 True -> ScanState(..state, phase: Chapter, found_book: True) 93 False -> state 94 } 95 _ -> state 96 } 97 Chapter -> 98 case line { 99 "CHAPTER " <> chapter -> 100 case result.unwrap(int.parse(chapter), 0) == state.ref.chapter { 101 True -> ScanState(..state, phase: Verse, found_chapter: True) 102 False -> state 103 } 104 _ -> state 105 } 106 Verse -> 107 fn() { 108 let parts = string.split(line, " ") 109 case parts { 110 [first, ..rest] -> 111 case result.unwrap(int.parse(first), 0) == state.ref.verse { 112 True -> 113 ScanState( 114 ..state, 115 phase: Done, 116 verse_text: Ok(string.join(rest, " ")), 117 ) 118 False -> state 119 } 120 _ -> state 121 } 122 }() 123 } 124 }) 125 126 ScanResult(ref: reference, verse: result.verse_text) 127} 128 129pub fn main() -> Nil { 130 let assert Ok(bible) = simplifile.read(from: filepath) 131 132 let assert Ok(search) = input(prompt: "> ") 133 134 let assert Ok(reference) = parse_reference(search) 135 136 let scan = bible_scan(reference, bible) 137 138 case scan.verse { 139 Ok(text) -> 140 io.println( 141 scan.ref.book 142 <> " " 143 <> int.to_string(scan.ref.chapter) 144 <> ":" 145 <> int.to_string(scan.ref.verse) 146 <> " " 147 <> text, 148 ) 149 Error(e) -> io.println_error(e) 150 } 151}