diff options
Diffstat (limited to 'src/nbc/parse-state.sml')
-rw-r--r-- | src/nbc/parse-state.sml | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/src/nbc/parse-state.sml b/src/nbc/parse-state.sml new file mode 100644 index 0000000..8b30a67 --- /dev/null +++ b/src/nbc/parse-state.sml @@ -0,0 +1,89 @@ +signature PARSE_STATE = sig + type ('argument, 'result) state + val create: unit -> ('argument, 'result) state + type ('argument, 'result) handler = + TextIO.instream * 'argument -> 'result + datatype whichCharacters = These of char list | Any + val build: { + state: ('argument, 'result) state + , characters: + (whichCharacters * ('argument, 'result) handler) list + , endOfFile: ('argument, 'result) handler + } -> unit + val enter: + ('argument, 'result) state + * TextIO.instream + * 'argument + -> 'result +end + +structure ParseState :> PARSE_STATE = struct + type ('argument, 'result) handler = + TextIO.instream * 'argument -> 'result + datatype whichCharacters = These of char list | Any + type ('argument, 'result) state = { + byCharacter: Int8.int vector ref + , byIndex: ('argument, 'result) handler vector ref + , endOfFile: ('argument, 'result) handler option ref + } + fun create () = { + byCharacter = ref (Vector.fromList nil) + , byIndex = ref (Vector.fromList nil) + , endOfFile = ref NONE + } + fun build { + state = {byCharacter, byIndex, endOfFile} + , characters + , endOfFile = newEndOfFile + } = + let + val characters = vector characters + fun equal (one: char) (two: char) = + one = two + fun shallHandle ((whichToHandle, _), char) = + case whichToHandle of + Any => true + | These charactersToHandle => + List.exists (equal char) + charactersToHandle + fun charToIndex char = + case + Vector.findi (fn (_, handler) => + shallHandle (handler, char) + ) characters + of + NONE => raise Fail ( + "ParseState.build: " + ^ Char.toString char + ^ " not found" + ) | SOME (index, _) => + Int8.fromInt index + fun handlerToFunction (_, function) = function + fun indexToFunction index = handlerToFunction ( + Vector.sub (characters, index) + ) + in + byCharacter := Vector.tabulate ( + Char.maxOrd + 1 + , charToIndex o chr + ); byIndex := + Vector.map (fn (_, function) => + function + ) characters + ; endOfFile := SOME newEndOfFile + end + fun enter ( + { + byCharacter = ref byCharacter + , byIndex = ref byIndex + , endOfFile = ref endOfFile + } + , instream + , argument + ) = case TextIO.input1 instream of + NONE => (valOf endOfFile) (instream, argument) + | SOME char => Vector.sub ( + byIndex + , Int8.toInt (Vector.sub (byCharacter, ord char)) + ) (instream, argument) +end |