summaryrefslogtreecommitdiff
path: root/src/nbc/parse-state.sml
blob: 8b30a67e9841d35d44de583b5edb1e01ce1de3a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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