d1367d8434ccbe04394aadac46fbde74af0412699d85e361faec63e2c9417b03.tri (9502B)
1 !import prelude * 2 !export * 3 4 -- Finite-stream parser protocol. Keep this module independent of token codecs. 5 -- Reply = pair status (pair payload (pair rest (pair consumed committed))) 6 -- status is true for success; payload is value or diagnostic respectively. 7 -- Flags are relative to this parser invocation. A diagnostic may itself carry 8 -- a location; rollback never changes that location. 9 -- Diagnostic = pair code (pair expected (pair found (pair location contexts))). 10 -- A field of t denotes unspecified information; contexts is a list from the 11 -- outermost context to the innermost. Source/byte adapters supply locations. 12 parserDiagnostic code expected found location contexts = 13 pair code (pair expected (pair found (pair location contexts))) 14 15 parserDiagnosticCode diagnostic = fst diagnostic 16 parserDiagnosticExpected diagnostic = fst (snd diagnostic) 17 parserDiagnosticFound diagnostic = fst (snd (snd diagnostic)) 18 parserDiagnosticLocation diagnostic = fst (snd (snd (snd diagnostic))) 19 parserDiagnosticContexts diagnostic = snd (snd (snd (snd diagnostic))) 20 21 parserDiagnosticWithExpected label diagnostic = 22 parserDiagnostic (parserDiagnosticCode diagnostic) label 23 (parserDiagnosticFound diagnostic) (parserDiagnosticLocation diagnostic) 24 (parserDiagnosticContexts diagnostic) 25 26 parserDiagnosticWithContext context diagnostic = 27 parserDiagnostic (parserDiagnosticCode diagnostic) 28 (parserDiagnosticExpected diagnostic) (parserDiagnosticFound diagnostic) 29 (parserDiagnosticLocation diagnostic) 30 (pair context (parserDiagnosticContexts diagnostic)) 31 32 parserReplyOk value rest consumed committed = 33 pair true (pair value (pair rest (pair consumed committed))) 34 35 parserReplyFail diagnostic rest consumed committed = 36 pair false (pair diagnostic (pair rest (pair consumed committed))) 37 38 parserReplyPayload reply = fst (snd reply) 39 parserReplyRest reply = fst (snd (snd reply)) 40 parserReplyConsumed reply = fst (snd (snd (snd reply))) 41 parserReplyCommitted reply = snd (snd (snd (snd reply))) 42 43 -- The branch handlers take payload, remainder, consumed, committed. 44 parserMatchReply failK okK reply = 45 lazyBool 46 (_ : okK (parserReplyPayload reply) (parserReplyRest reply) 47 (parserReplyConsumed reply) (parserReplyCommitted reply)) 48 (_ : failK (parserReplyPayload reply) (parserReplyRest reply) 49 (parserReplyConsumed reply) (parserReplyCommitted reply)) 50 (fst reply) 51 52 parserPure value input = parserReplyOk value input false false 53 parserFailure diagnostic input = parserReplyFail diagnostic input false false 54 parserCommit input = parserReplyOk t input false true 55 56 parserMap f parser input = 57 parserMatchReply 58 (diagnostic rest consumed committed : 59 parserReplyFail diagnostic rest consumed committed) 60 (value rest consumed committed : 61 parserReplyOk (f value) rest consumed committed) 62 (parser input) 63 64 parserBind parser next input = 65 parserMatchReply 66 (diagnostic rest consumed committed : 67 parserReplyFail diagnostic rest consumed committed) 68 (value rest consumed committed : 69 parserMatchReply 70 (diagnostic2 rest2 consumed2 committed2 : 71 parserReplyFail diagnostic2 rest2 72 (or? consumed consumed2) (or? committed committed2)) 73 (value2 rest2 consumed2 committed2 : 74 parserReplyOk value2 rest2 75 (or? consumed consumed2) (or? committed committed2)) 76 (next value rest)) 77 (parser input) 78 79 parserThen first second = parserBind first (_ : second) 80 parserBefore first second = parserBind first (value : parserMap (_ : value) second) 81 82 -- Compose a character lexer and a token parser without discarding either 83 -- failure's original remainder. Successful lexing contributes consumption. 84 parserWithLexer lexer grammar characters = 85 parserMatchReply 86 (diagnostic rest consumed committed : 87 parserReplyFail diagnostic rest consumed committed) 88 (tokens rest consumed committed : 89 parserMatchReply 90 (diagnostic2 tokensRest consumed2 committed2 : 91 parserReplyFail diagnostic2 tokensRest 92 (or? consumed consumed2) (or? committed committed2)) 93 (value tokensRest consumed2 committed2 : 94 parserReplyOk value tokensRest 95 (or? consumed consumed2) (or? committed committed2)) 96 (grammar tokens)) 97 (lexer characters) 98 parserApply functionParser valueParser = 99 parserBind functionParser (f : parserMap f valueParser) 100 101 parserOr left right input = 102 parserMatchReply 103 (diagnostic rest consumed committed : 104 lazyBool 105 (_ : parserReplyFail diagnostic rest consumed committed) 106 (_ : right input) 107 (or? consumed committed)) 108 (value rest consumed committed : 109 parserReplyOk value rest consumed committed) 110 (left input) 111 112 parserLabel label parser input = 113 parserMatchReply 114 (diagnostic rest consumed committed : 115 parserReplyFail (parserDiagnosticWithExpected label diagnostic) 116 rest consumed committed) 117 (value rest consumed committed : 118 parserReplyOk value rest consumed committed) 119 (parser input) 120 121 parserContext context parser input = 122 parserMatchReply 123 (diagnostic rest consumed committed : 124 parserReplyFail (parserDiagnosticWithContext context diagnostic) 125 rest consumed committed) 126 (value rest consumed committed : 127 parserReplyOk value rest consumed committed) 128 (parser input) 129 130 parserAttempt parser input = 131 parserMatchReply 132 (diagnostic rest consumed committed : 133 parserReplyFail diagnostic input false false) 134 (value rest consumed committed : 135 parserReplyOk value rest consumed committed) 136 (parser input) 137 138 parserUnexpectedEof = parserDiagnostic 1 t t t t 139 parserUnexpectedToken token = parserDiagnostic 2 t token t t 140 141 parserAny input = 142 lazyList 143 (_ : parserReplyFail parserUnexpectedEof input false false) 144 (head rest : parserReplyOk head rest true false) 145 input 146 147 parserSatisfy predicate input = 148 parserMatchReply 149 (diagnostic rest consumed committed : 150 parserReplyFail diagnostic rest consumed committed) 151 (value rest consumed committed : 152 lazyBool 153 (_ : parserReplyOk value rest true false) 154 (_ : parserReplyFail (parserUnexpectedToken value) input false false) 155 (predicate value)) 156 (parserAny input) 157 158 parserExpect token = 159 parserLabel token (parserSatisfy (value : equal? token value)) 160 161 parserPeek input = 162 parserMatchReply 163 (diagnostic rest consumed committed : 164 parserReplyFail diagnostic input false false) 165 (value rest consumed committed : 166 parserReplyOk value input false false) 167 (parserAny input) 168 169 parserEof input = 170 lazyList 171 (_ : parserReplyOk t input false false) 172 (head rest : parserReplyFail (parserUnexpectedToken head) input false false) 173 input 174 175 parserOptional parser = 176 parserOr (parserMap just parser) (parserPure nothing) 177 178 parserNonConsumingRepetition = parserDiagnostic 3 t t t t 179 180 -- The worker's first runtime argument is the stream. An iteration may only 181 -- recur after actual consumption, never merely because it committed. Build the 182 -- result backwards with constant-time cons, reversing only at the stopping 183 -- branch. Failure after progress retains that progress and the failing suffix. 184 parserMany_ self input parser acc consumed committed = 185 parserMatchReply 186 (diagnostic rest stepConsumed stepCommitted : 187 lazyBool 188 (_ : parserReplyFail diagnostic rest 189 (or? consumed stepConsumed) (or? committed stepCommitted)) 190 (_ : parserReplyOk (reverse acc) input consumed committed) 191 (or? stepConsumed stepCommitted)) 192 (value rest stepConsumed stepCommitted : 193 lazyBool 194 (_ : self rest parser (pair value acc) 195 true (or? committed stepCommitted)) 196 (_ : parserReplyFail parserNonConsumingRepetition input 197 consumed (or? committed stepCommitted)) 198 stepConsumed) 199 (parser input) 200 201 parserMany parser input = y parserMany_ input parser t false false 202 parserSome parser = 203 parserBind parser (first : 204 parserMap (rest : pair first rest) (parserMany parser)) 205 206 parserTakeWhile predicate = parserMany (parserSatisfy predicate) 207 parserTakeWhile1 predicate = parserSome (parserSatisfy predicate) 208 209 parserBetween open content close = 210 parserThen open (parserBefore content close) 211 212 -- A separator consumes and commits its following element on failure; callers 213 -- who want a trailing separator must express that rule explicitly. 214 parserSepBy1 element separator = 215 parserBind element (first : 216 parserMap (rest : pair first rest) 217 (parserMany (parserThen separator element))) 218 219 -- Choice for an empty sequence applies only to the *first element*. Once 220 -- that element succeeds, a later zero-width or committed failure must not be 221 -- hidden by falling back to the empty sequence. 222 parserSepBy element separator input = 223 parserMatchReply 224 (diagnostic rest consumed committed : 225 lazyBool 226 (_ : parserReplyFail diagnostic rest consumed committed) 227 (_ : parserReplyOk t input false false) 228 (or? consumed committed)) 229 (first rest consumed committed : 230 parserMatchReply 231 (diagnostic2 rest2 consumed2 committed2 : 232 parserReplyFail diagnostic2 rest2 233 (or? consumed consumed2) (or? committed committed2)) 234 (tail rest2 consumed2 committed2 : 235 parserReplyOk (pair first tail) rest2 236 (or? consumed consumed2) (or? committed committed2)) 237 (parserMany (parserThen separator element) rest)) 238 (element input) 239