-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathusm.sml
2845 lines (2753 loc) · 135 KB
/
usm.sml
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(* usm.sml 939a *)
(*****************************************************************)
(* *)
(* \FOOTNOTESIZE SHARED: NAMES, ENVIRONMENTS, STRINGS, ERRORS, PRINTING, INTERACTION, STREAMS, \&\ INITIALIZATION *)
(* *)
(*****************************************************************)
(* \footnotesize shared: names, environments, strings, errors, printing, interaction, streams, \&\ initialization 1143a *)
(* for working with curried functions: [[id]], [[fst]], [[snd]], [[pair]], [[curry]], and [[curry3]] 1169c *)
fun id x = x
fun fst (x, y) = x
fun snd (x, y) = y
fun pair x y = (x, y)
fun curry f x y = f (x, y)
fun curry3 f x y z = f (x, y, z)
(* type declarations for consistency checking *)
val _ = op fst : ('a * 'b) -> 'a
val _ = op snd : ('a * 'b) -> 'b
val _ = op pair : 'a -> 'b -> 'a * 'b
val _ = op curry : ('a * 'b -> 'c) -> ('a -> 'b -> 'c)
val _ = op curry3 : ('a * 'b * 'c -> 'd) -> ('a -> 'b -> 'c -> 'd)
(* support for names and environments 354 *)
type name = string
(* support for names and environments 355 *)
type 'a env = (name * 'a) list
val emptyEnv = []
(* lookup and check of existing bindings *)
exception NotFound of name
fun find (name, []) = raise NotFound name
| find (name, (n, v)::tail) = if name = n then v else find (name, tail)
(* adding new bindings *)
exception BindListLength
fun bind (name, v, rho) = (name, v) :: rho
fun bindList (n::vars, v::vals, rho) = bindList (vars, vals, bind (n, v, rho))
| bindList ([], [], rho) = rho
| bindList _ = raise BindListLength
(* type declarations for consistency checking *)
val _ = op emptyEnv : 'a env
val _ = op find : name * 'a env -> 'a
val _ = op bind : name * 'a * 'a env -> 'a env
val _ = op bindList : name list * 'a list * 'a env -> 'a env
(* support for names and environments 360a *)
fun duplicatename [] = NONE
| duplicatename (x::xs) =
if List.exists (fn x' => x' = x) xs then
SOME x
else
duplicatename xs
(* type declarations for consistency checking *)
val _ = op duplicatename : name list -> name option
(* support for detecting and signaling errors detected at run time 359d *)
exception RuntimeError of string (* error message *)
(* support for detecting and signaling errors detected at run time 360b *)
fun errorIfDups (what, xs, context) =
case duplicatename xs
of NONE => ()
| SOME x => raise RuntimeError (what ^ " " ^ x ^ " appears twice in " ^
context)
(* type declarations for consistency checking *)
val _ = op errorIfDups : string * name list * string -> unit
(* support for detecting and signaling errors detected at run time 360c *)
exception InternalError of string (* bug in the interpreter *)
(* list functions not provided by \sml's initial basis 1147b *)
fun zip3 ([], [], []) = []
| zip3 (x::xs, y::ys, z::zs) = (x, y, z) :: zip3 (xs, ys, zs)
| zip3 _ = raise ListPair.UnequalLengths
fun unzip3 [] = ([], [], [])
| unzip3 (trip::trips) =
let val (x, y, z) = trip
val (xs, ys, zs) = unzip3 trips
in (x::xs, y::ys, z::zs)
end
(* list functions not provided by \sml's initial basis 1147c *)
val reverse = rev
(* list functions not provided by \sml's initial basis 1147d *)
fun optionList [] = SOME []
| optionList (NONE :: _) = NONE
| optionList (SOME x :: rest) =
(case optionList rest
of SOME xs => SOME (x :: xs)
| NONE => NONE)
(* utility functions for string manipulation and printing 1144a *)
fun println s = (print s; print "\n")
fun eprint s = TextIO.output (TextIO.stdErr, s)
fun eprintln s = (eprint s; eprint "\n")
(* utility functions for string manipulation and printing 1144b *)
fun predefinedFunctionError s = eprintln ("while reading predefined functions, "
^ s)
(* utility functions for string manipulation and printing 1144c *)
fun intString n =
String.map (fn #"~" => #"-" | c => c) (Int.toString n)
(* utility functions for string manipulation and printing 1144d *)
fun plural what [x] = what
| plural what _ = what ^ "s"
fun countString xs what =
intString (length xs) ^ " " ^ plural what xs
(* utility functions for string manipulation and printing 1144e *)
fun separate (zero, sep) =
(* list with separator *)
let fun s [] = zero
| s [x] = x
| s (h::t) = h ^ sep ^ s t
in s
end
val spaceSep = separate ("", " ") (* list separated by spaces *)
val commaSep = separate ("", ", ") (* list separated by commas *)
(* type declarations for consistency checking *)
val _ = op intString : int -> string
(* type declarations for consistency checking *)
val _ = op spaceSep : string list -> string
val _ = op commaSep : string list -> string
val _ = op separate : string * string -> string list -> string
(* utility functions for string manipulation and printing 1145a *)
fun printUTF8 code =
let val w = Word.fromInt code
val (&, >>) = (Word.andb, Word.>>)
infix 6 & >>
val _ = if (w & 0wx1fffff) <> w then
raise RuntimeError (intString code ^
" does not represent a Unicode code point")
else
()
fun printbyte w = TextIO.output1 (TextIO.stdOut, chr (Word.toInt w))
fun prefix byte byte' = Word.orb (byte, byte')
in if w > 0wxffff then
app printbyte [ prefix 0wxf0 (w >> 0w18)
, prefix 0wx80 ((w >> 0w12) & 0wx3f)
, prefix 0wx80 ((w >> 0w6) & 0wx3f)
, prefix 0wx80 ((w ) & 0wx3f)
]
else if w > 0wx7ff then
app printbyte [ prefix 0wxe0 (w >> 0w12)
, prefix 0wx80 ((w >> 0w6) & 0wx3f)
, prefix 0wx80 ((w ) & 0wx3f)
]
else if w > 0wx7f then
app printbyte [ prefix 0wxc0 (w >> 0w6)
, prefix 0wx80 ((w ) & 0wx3f)
]
else
printbyte w
end
(* utility functions for string manipulation and printing 1145b *)
fun stripNumericSuffix s =
let fun stripPrefix [] = s (* don't let things get empty *)
| stripPrefix (#"-"::[]) = s
| stripPrefix (#"-"::cs) = implode (reverse cs)
| stripPrefix (c ::cs) = if Char.isDigit c then stripPrefix cs
else implode (reverse (c::cs))
in stripPrefix (reverse (explode s))
end
(* support for representing errors as \ml\ values 1148b *)
datatype 'a error = OK of 'a | ERROR of string
(* support for representing errors as \ml\ values 1149a *)
infix 1 >>=
fun (OK x) >>= k = k x
| (ERROR msg) >>= k = ERROR msg
(* type declarations for consistency checking *)
val _ = op zip3 : 'a list * 'b list * 'c list -> ('a * 'b * 'c) list
val _ = op unzip3 : ('a * 'b * 'c) list -> 'a list * 'b list * 'c list
(* type declarations for consistency checking *)
val _ = op optionList : 'a option list -> 'a list option
(* type declarations for consistency checking *)
val _ = op >>= : 'a error * ('a -> 'b error) -> 'b error
(* support for representing errors as \ml\ values 1149b *)
infix 1 >>=+
fun e >>=+ k' = e >>= (OK o k')
(* type declarations for consistency checking *)
val _ = op >>=+ : 'a error * ('a -> 'b) -> 'b error
(* support for representing errors as \ml\ values 1150a *)
fun errorList es =
let fun cons (OK x, OK xs) = OK (x :: xs)
| cons (ERROR m1, ERROR m2) = ERROR (m1 ^ "; " ^ m2)
| cons (ERROR m, OK _) = ERROR m
| cons (OK _, ERROR m) = ERROR m
in foldr cons (OK []) es
end
(* type declarations for consistency checking *)
val _ = op errorList : 'a error list -> 'a list error
(* type [[interactivity]] plus related functions and value 367a *)
datatype input_interactivity = PROMPTING | NOT_PROMPTING
(* type [[interactivity]] plus related functions and value 367b *)
datatype output_interactivity = PRINTING | NOT_PRINTING
(* type [[interactivity]] plus related functions and value 367c *)
type interactivity =
input_interactivity * output_interactivity
val noninteractive =
(NOT_PROMPTING, NOT_PRINTING)
fun prompts (PROMPTING, _) = true
| prompts (NOT_PROMPTING, _) = false
fun prints (_, PRINTING) = true
| prints (_, NOT_PRINTING) = false
(* type declarations for consistency checking *)
type interactivity = interactivity
val _ = op noninteractive : interactivity
val _ = op prompts : interactivity -> bool
val _ = op prints : interactivity -> bool
(* simple implementations of set operations 1146a *)
type 'a set = 'a list
val emptyset = []
fun member x =
List.exists (fn y => y = x)
fun insert (x, ys) =
if member x ys then ys else x::ys
fun union (xs, ys) = foldl insert ys xs
fun inter (xs, ys) =
List.filter (fn x => member x ys) xs
fun diff (xs, ys) =
List.filter (fn x => not (member x ys)) xs
(* type declarations for consistency checking *)
type 'a set = 'a set
val _ = op emptyset : 'a set
val _ = op member : ''a -> ''a set -> bool
val _ = op insert : ''a * ''a set -> ''a set
val _ = op union : ''a set * ''a set -> ''a set
val _ = op inter : ''a set * ''a set -> ''a set
val _ = op diff : ''a set * ''a set -> ''a set
(* collections with mapping and combining functions 1146b *)
datatype 'a collection = C of 'a set
fun elemsC (C xs) = xs
fun singleC x = C [x]
val emptyC = C []
(* type declarations for consistency checking *)
type 'a collection = 'a collection
val _ = op elemsC : 'a collection -> 'a set
val _ = op singleC : 'a -> 'a collection
val _ = op emptyC : 'a collection
(* collections with mapping and combining functions 1147a *)
fun joinC (C xs) = C (List.concat (map elemsC xs))
fun mapC f (C xs) = C (map f xs)
fun filterC p (C xs) = C (List.filter p xs)
fun mapC2 f (xc, yc) = joinC (mapC (fn x => mapC (fn y => f (x, y)) yc) xc)
(* type declarations for consistency checking *)
val _ = op joinC : 'a collection collection -> 'a collection
val _ = op mapC : ('a -> 'b) -> ('a collection -> 'b collection)
val _ = op filterC : ('a -> bool) -> ('a collection -> 'a collection)
val _ = op mapC2 : ('a * 'b -> 'c) -> ('a collection * 'b collection -> 'c
collection)
(* suspensions 1155a *)
datatype 'a action
= PENDING of unit -> 'a
| PRODUCED of 'a
type 'a susp = 'a action ref
(* type declarations for consistency checking *)
type 'a susp = 'a susp
(* suspensions 1155b *)
fun delay f = ref (PENDING f)
fun demand cell =
case !cell
of PENDING f => let val result = f ()
in (cell := PRODUCED result; result)
end
| PRODUCED v => v
(* type declarations for consistency checking *)
val _ = op delay : (unit -> 'a) -> 'a susp
val _ = op demand : 'a susp -> 'a
(* streams 1156a *)
datatype 'a stream
= EOS
| ::: of 'a * 'a stream
| SUSPENDED of 'a stream susp
infixr 3 :::
(* streams 1156b *)
fun streamGet EOS = NONE
| streamGet (x ::: xs) = SOME (x, xs)
| streamGet (SUSPENDED s) = streamGet (demand s)
(* streams 1156c *)
fun streamOfList xs =
foldr (op :::) EOS xs
(* type declarations for consistency checking *)
val _ = op streamGet : 'a stream -> ('a * 'a stream) option
(* type declarations for consistency checking *)
val _ = op streamOfList : 'a list -> 'a stream
(* streams 1156d *)
fun listOfStream xs =
case streamGet xs
of NONE => []
| SOME (x, xs) => x :: listOfStream xs
(* streams 1156e *)
fun delayedStream action =
SUSPENDED (delay action)
(* type declarations for consistency checking *)
val _ = op listOfStream : 'a stream -> 'a list
(* type declarations for consistency checking *)
val _ = op delayedStream : (unit -> 'a stream) -> 'a stream
(* streams 1157a *)
fun streamOfEffects action =
delayedStream (fn () => case action () of NONE => EOS
| SOME a => a ::: streamOfEffects
action)
(* type declarations for consistency checking *)
val _ = op streamOfEffects : (unit -> 'a option) -> 'a stream
(* streams 1157b *)
type line = string
fun filelines infile =
streamOfEffects (fn () => TextIO.inputLine infile)
(* type declarations for consistency checking *)
type line = line
val _ = op filelines : TextIO.instream -> line stream
(* streams 1157c *)
fun streamRepeat x =
delayedStream (fn () => x ::: streamRepeat x)
(* type declarations for consistency checking *)
val _ = op streamRepeat : 'a -> 'a stream
(* streams 1157d *)
fun streamOfUnfold next state =
delayedStream (fn () => case next state
of NONE => EOS
| SOME (a, state') => a ::: streamOfUnfold next
state')
(* type declarations for consistency checking *)
val _ = op streamOfUnfold : ('b -> ('a * 'b) option) -> 'b -> 'a stream
(* streams 1157e *)
val naturals =
streamOfUnfold (fn n => SOME (n, n+1)) 0 (* 0 to infinity *)
(* type declarations for consistency checking *)
val _ = op naturals : int stream
(* streams 1158a *)
fun preStream (pre, xs) =
streamOfUnfold (fn xs => (pre (); streamGet xs)) xs
(* streams 1158b *)
fun postStream (xs, post) =
streamOfUnfold (fn xs => case streamGet xs
of NONE => NONE
| head as SOME (x, _) => (post x; head)) xs
(* type declarations for consistency checking *)
val _ = op preStream : (unit -> unit) * 'a stream -> 'a stream
(* type declarations for consistency checking *)
val _ = op postStream : 'a stream * ('a -> unit) -> 'a stream
(* streams 1158c *)
fun streamMap f xs =
delayedStream (fn () => case streamGet xs
of NONE => EOS
| SOME (x, xs) => f x ::: streamMap f xs)
(* type declarations for consistency checking *)
val _ = op streamMap : ('a -> 'b) -> 'a stream -> 'b stream
(* streams 1158d *)
fun streamFilter p xs =
delayedStream (fn () => case streamGet xs
of NONE => EOS
| SOME (x, xs) => if p x then x ::: streamFilter p
xs
else streamFilter p xs)
(* type declarations for consistency checking *)
val _ = op streamFilter : ('a -> bool) -> 'a stream -> 'a stream
(* streams 1158e *)
fun streamFold f z xs =
case streamGet xs of NONE => z
| SOME (x, xs) => streamFold f (f (x, z)) xs
(* type declarations for consistency checking *)
val _ = op streamFold : ('a * 'b -> 'b) -> 'b -> 'a stream -> 'b
(* streams 1159a *)
fun streamZip (xs, ys) =
delayedStream
(fn () => case (streamGet xs, streamGet ys)
of (SOME (x, xs), SOME (y, ys)) => (x, y) ::: streamZip (xs, ys)
| _ => EOS)
(* streams 1159b *)
fun streamConcat xss =
let fun get (xs, xss) =
case streamGet xs
of SOME (x, xs) => SOME (x, (xs, xss))
| NONE => case streamGet xss
of SOME (xs, xss) => get (xs, xss)
| NONE => NONE
in streamOfUnfold get (EOS, xss)
end
(* type declarations for consistency checking *)
val _ = op streamZip : 'a stream * 'b stream -> ('a * 'b) stream
(* type declarations for consistency checking *)
val _ = op streamConcat : 'a stream stream -> 'a stream
(* streams 1159c *)
fun streamConcatMap f xs = streamConcat (streamMap f xs)
(* type declarations for consistency checking *)
val _ = op streamConcatMap : ('a -> 'b stream) -> 'a stream -> 'b stream
(* streams 1159d *)
infix 5 @@@
fun xs @@@ xs' = streamConcat (streamOfList [xs, xs'])
(* type declarations for consistency checking *)
val _ = op @@@ : 'a stream * 'a stream -> 'a stream
(* streams 1159e *)
fun streamTake (0, xs) = []
| streamTake (n, xs) =
case streamGet xs
of SOME (x, xs) => x :: streamTake (n-1, xs)
| NONE => []
(* type declarations for consistency checking *)
val _ = op streamTake : int * 'a stream -> 'a list
(* streams 1160a *)
fun streamDrop (0, xs) = xs
| streamDrop (n, xs) =
case streamGet xs
of SOME (_, xs) => streamDrop (n-1, xs)
| NONE => EOS
(* type declarations for consistency checking *)
val _ = op streamDrop : int * 'a stream -> 'a stream
(* stream transformers and their combinators 1167a *)
type ('a, 'b) xformer =
'a stream -> ('b error * 'a stream) option
(* type declarations for consistency checking *)
type ('a, 'b) xformer = ('a, 'b) xformer
(* stream transformers and their combinators 1167b *)
fun pure y = fn xs => SOME (OK y, xs)
(* type declarations for consistency checking *)
val _ = op pure : 'b -> ('a, 'b) xformer
(* stream transformers and their combinators 1169a *)
infix 3 <*>
fun tx_f <*> tx_b =
fn xs => case tx_f xs
of NONE => NONE
| SOME (ERROR msg, xs) => SOME (ERROR msg, xs)
| SOME (OK f, xs) =>
case tx_b xs
of NONE => NONE
| SOME (ERROR msg, xs) => SOME (ERROR msg, xs)
| SOME (OK y, xs) => SOME (OK (f y), xs)
(* type declarations for consistency checking *)
val _ = op <*> : ('a, 'b -> 'c) xformer * ('a, 'b) xformer -> ('a, 'c) xformer
(* stream transformers and their combinators 1169b *)
infixr 4 <$>
fun f <$> p = pure f <*> p
(* type declarations for consistency checking *)
val _ = op <$> : ('b -> 'c) * ('a, 'b) xformer -> ('a, 'c) xformer
(* stream transformers and their combinators 1170a *)
infix 1 <|>
fun t1 <|> t2 = (fn xs => case t1 xs of SOME y => SOME y | NONE => t2 xs)
(* type declarations for consistency checking *)
val _ = op <|> : ('a, 'b) xformer * ('a, 'b) xformer -> ('a, 'b) xformer
(* stream transformers and their combinators 1170b *)
fun pzero _ = NONE
(* stream transformers and their combinators 1170c *)
fun anyParser ts =
foldr op <|> pzero ts
(* type declarations for consistency checking *)
val _ = op pzero : ('a, 'b) xformer
(* type declarations for consistency checking *)
val _ = op anyParser : ('a, 'b) xformer list -> ('a, 'b) xformer
(* stream transformers and their combinators 1171a *)
infix 6 <* *>
fun p1 <* p2 = curry fst <$> p1 <*> p2
fun p1 *> p2 = curry snd <$> p1 <*> p2
infixr 4 <$
fun v <$ p = (fn _ => v) <$> p
(* type declarations for consistency checking *)
val _ = op <* : ('a, 'b) xformer * ('a, 'c) xformer -> ('a, 'b) xformer
val _ = op *> : ('a, 'b) xformer * ('a, 'c) xformer -> ('a, 'c) xformer
val _ = op <$ : 'b * ('a, 'c) xformer -> ('a, 'b) xformer
(* stream transformers and their combinators 1171b *)
fun one xs = case streamGet xs
of NONE => NONE
| SOME (x, xs) => SOME (OK x, xs)
(* type declarations for consistency checking *)
val _ = op one : ('a, 'a) xformer
(* stream transformers and their combinators 1171c *)
fun eos xs = case streamGet xs
of NONE => SOME (OK (), EOS)
| SOME _ => NONE
(* type declarations for consistency checking *)
val _ = op eos : ('a, unit) xformer
(* stream transformers and their combinators 1172a *)
fun peek tx xs =
case tx xs of SOME (OK y, _) => SOME y
| _ => NONE
(* type declarations for consistency checking *)
val _ = op peek : ('a, 'b) xformer -> 'a stream -> 'b option
(* stream transformers and their combinators 1172b *)
fun rewind tx xs =
case tx xs of SOME (ey, _) => SOME (ey, xs)
| NONE => NONE
(* type declarations for consistency checking *)
val _ = op rewind : ('a, 'b) xformer -> ('a, 'b) xformer
(* stream transformers and their combinators 1172c *)
fun sat p tx xs =
case tx xs
of answer as SOME (OK y, xs) => if p y then answer else NONE
| answer => answer
(* type declarations for consistency checking *)
val _ = op sat : ('b -> bool) -> ('a, 'b) xformer -> ('a, 'b) xformer
(* stream transformers and their combinators 1172d *)
fun eqx y =
sat (fn y' => y = y')
(* type declarations for consistency checking *)
val _ = op eqx : ''b -> ('a, ''b) xformer -> ('a, ''b) xformer
(* stream transformers and their combinators 1173a *)
infixr 4 <$>?
fun f <$>? tx =
fn xs => case tx xs
of NONE => NONE
| SOME (ERROR msg, xs) => SOME (ERROR msg, xs)
| SOME (OK y, xs) =>
case f y
of NONE => NONE
| SOME z => SOME (OK z, xs)
(* type declarations for consistency checking *)
val _ = op <$>? : ('b -> 'c option) * ('a, 'b) xformer -> ('a, 'c) xformer
(* stream transformers and their combinators 1173b *)
infix 3 <&>
fun t1 <&> t2 = fn xs =>
case t1 xs
of SOME (OK _, _) => t2 xs
| SOME (ERROR _, _) => NONE
| NONE => NONE
(* type declarations for consistency checking *)
val _ = op <&> : ('a, 'b) xformer * ('a, 'c) xformer -> ('a, 'c) xformer
(* stream transformers and their combinators 1173c *)
fun notFollowedBy t xs =
case t xs
of NONE => SOME (OK (), xs)
| SOME _ => NONE
(* type declarations for consistency checking *)
val _ = op notFollowedBy : ('a, 'b) xformer -> ('a, unit) xformer
(* stream transformers and their combinators 1173d *)
fun many t =
curry (op ::) <$> t <*> (fn xs => many t xs) <|> pure []
(* type declarations for consistency checking *)
val _ = op many : ('a, 'b) xformer -> ('a, 'b list) xformer
(* stream transformers and their combinators 1174a *)
fun many1 t =
curry (op ::) <$> t <*> many t
(* type declarations for consistency checking *)
val _ = op many1 : ('a, 'b) xformer -> ('a, 'b list) xformer
(* stream transformers and their combinators 1174b *)
fun optional t =
SOME <$> t <|> pure NONE
(* type declarations for consistency checking *)
val _ = op optional : ('a, 'b) xformer -> ('a, 'b option) xformer
(* stream transformers and their combinators 1175a *)
infix 2 <*>!
fun tx_ef <*>! tx_x =
fn xs => case (tx_ef <*> tx_x) xs
of NONE => NONE
| SOME (OK (OK y), xs) => SOME (OK y, xs)
| SOME (OK (ERROR msg), xs) => SOME (ERROR msg, xs)
| SOME (ERROR msg, xs) => SOME (ERROR msg, xs)
infixr 4 <$>!
fun ef <$>! tx_x = pure ef <*>! tx_x
(* type declarations for consistency checking *)
val _ = op <*>! : ('a, 'b -> 'c error) xformer * ('a, 'b) xformer -> ('a, 'c)
xformer
val _ = op <$>! : ('b -> 'c error) * ('a, 'b) xformer -> ('a, 'c)
xformer
(* support for source-code locations and located streams 1160c *)
type srcloc = string * int
fun srclocString (source, line) =
source ^ ", line " ^ intString line
(* support for source-code locations and located streams 1160d *)
datatype error_format = WITH_LOCATIONS | WITHOUT_LOCATIONS
val toplevel_error_format = ref WITH_LOCATIONS
(* support for source-code locations and located streams 1161a *)
fun synerrormsg (source, line) strings =
if !toplevel_error_format = WITHOUT_LOCATIONS andalso source =
"standard input"
then
concat ("syntax error: " :: strings)
else
concat ("syntax error in " :: srclocString (source, line) :: ": " :: strings
)
(* support for source-code locations and located streams 1161b *)
exception Located of srcloc * exn
(* support for source-code locations and located streams 1161c *)
fun atLoc loc f a =
f a handle e as RuntimeError _ => raise Located (loc, e)
| e as NotFound _ => raise Located (loc, e)
(* more handlers for [[atLoc]] 1161d *)
| e as IO.Io _ => raise Located (loc, e)
| e as Div => raise Located (loc, e)
| e as Overflow => raise Located (loc, e)
| e as Subscript => raise Located (loc, e)
| e as Size => raise Located (loc, e)
(* type declarations for consistency checking *)
type srcloc = srcloc
val _ = op srclocString : srcloc -> string
(* type declarations for consistency checking *)
val _ = op atLoc : srcloc -> ('a -> 'b) -> ('a -> 'b)
(* support for source-code locations and located streams 1162a *)
fun fillComplaintTemplate (s, maybeLoc) =
let val string_to_fill = " <at loc>"
val (prefix, atloc) = Substring.position string_to_fill (Substring.full s)
val suffix = Substring.triml (size string_to_fill) atloc
val splice_in =
Substring.full (case maybeLoc
of NONE => ""
| SOME (loc as (file, line)) =>
if !toplevel_error_format =
WITHOUT_LOCATIONS
andalso file = "standard input"
then
""
else
" in " ^ srclocString loc)
in if Substring.size atloc = 0 then (* <at loc> is not present *)
s
else
Substring.concat [prefix, splice_in, suffix]
end
(* type declarations for consistency checking *)
val _ = op fillComplaintTemplate : string * srcloc option -> string
(* support for source-code locations and located streams 1162b *)
fun errorAt msg loc =
ERROR (synerrormsg loc [msg])
(* support for source-code locations and located streams 1162c *)
type 'a located = srcloc * 'a
(* type declarations for consistency checking *)
val _ = op errorAt : string -> srcloc -> 'a error
(* type declarations for consistency checking *)
type 'a located = 'a located
(* support for source-code locations and located streams 1162d *)
fun locatedStream (streamname, inputs) =
let val locations = streamZip (streamRepeat streamname, streamDrop (1,
naturals))
in streamZip (locations, inputs)
end
(* type declarations for consistency checking *)
val _ = op locatedStream : string * line stream -> line located stream
(* streams that track line boundaries 1179a *)
datatype 'a eol_marked
= EOL of int (* number of the line that ends here *)
| INLINE of 'a
fun drainLine EOS = EOS
| drainLine (SUSPENDED s) = drainLine (demand s)
| drainLine (EOL _ ::: xs) = xs
| drainLine (INLINE _ ::: xs) = drainLine xs
(* streams that track line boundaries 1179b *)
local
fun asEol (EOL n) = SOME n
| asEol (INLINE _) = NONE
fun asInline (INLINE x) = SOME x
| asInline (EOL _) = NONE
in
fun eol xs = (asEol <$>? one) xs
fun inline xs = (asInline <$>? many eol *> one) xs
fun srcloc xs = rewind (fst <$> inline) xs
end
(* type declarations for consistency checking *)
type 'a eol_marked = 'a eol_marked
val _ = op drainLine : 'a eol_marked stream -> 'a eol_marked stream
(* type declarations for consistency checking *)
val _ = op eol : ('a eol_marked, int) xformer
val _ = op inline : ('a eol_marked, 'a) xformer
val _ = op srcloc : ('a located eol_marked, srcloc) xformer
(* support for lexical analysis 1175b *)
type 'a lexer = (char, 'a) xformer
(* type declarations for consistency checking *)
type 'a lexer = 'a lexer
(* support for lexical analysis 1175c *)
fun isDelim c =
Char.isSpace c orelse Char.contains "()[]{};" c
(* type declarations for consistency checking *)
val _ = op isDelim : char -> bool
(* support for lexical analysis 1177a *)
val whitespace = many (sat Char.isSpace one)
(* type declarations for consistency checking *)
val _ = op whitespace : char list lexer
(* support for lexical analysis 1177b *)
fun intChars isDelim =
(curry (op ::) <$> eqx #"-" one <|> pure id) <*> many1 (sat Char.isDigit one)
<*
notFollowedBy (sat (not o isDelim) one)
(* type declarations for consistency checking *)
val _ = op intChars : (char -> bool) -> char list lexer
(* support for lexical analysis 1177c *)
fun intFromChars (#"-" :: cs) =
intFromChars cs >>=+ Int.~
| intFromChars cs =
(OK o valOf o Int.fromString o implode) cs
handle Overflow => ERROR
"this interpreter can't read arbitrarily large integers"
(* type declarations for consistency checking *)
val _ = op intFromChars : char list -> int error
(* support for lexical analysis 1177d *)
fun intToken isDelim =
intFromChars <$>! intChars isDelim
(* type declarations for consistency checking *)
val _ = op intToken : (char -> bool) -> int lexer
(* support for lexical analysis 1178a *)
datatype bracket_shape = ROUND | SQUARE | CURLY
fun leftString ROUND = "("
| leftString SQUARE = "["
| leftString CURLY = "{"
fun rightString ROUND = ")"
| rightString SQUARE = "]"
| rightString CURLY = "}"
(* support for lexical analysis 1178b *)
datatype 'a plus_brackets
= LEFT of bracket_shape
| RIGHT of bracket_shape
| PRETOKEN of 'a
fun bracketLexer pretoken
= LEFT ROUND <$ eqx #"(" one
<|> LEFT SQUARE <$ eqx #"[" one
<|> LEFT CURLY <$ eqx #"{" one
<|> RIGHT ROUND <$ eqx #")" one
<|> RIGHT SQUARE <$ eqx #"]" one
<|> RIGHT CURLY <$ eqx #"}" one
<|> PRETOKEN <$> pretoken
fun plusBracketsString _ (LEFT shape) = leftString shape
| plusBracketsString _ (RIGHT shape) = rightString shape
| plusBracketsString pts (PRETOKEN pt) = pts pt
(* type declarations for consistency checking *)
type 'a plus_brackets = 'a plus_brackets
val _ = op bracketLexer : 'a lexer -> 'a plus_brackets lexer
(* common parsing code 1166 *)
(* combinators and utilities for parsing located streams 1179c *)
type ('t, 'a) polyparser = ('t located eol_marked, 'a) xformer
(* combinators and utilities for parsing located streams 1180a *)
fun token stream = (snd <$> inline) stream
fun noTokens stream = (notFollowedBy token) stream
(* type declarations for consistency checking *)
val _ = op token : ('t, 't) polyparser
val _ = op noTokens : ('t, unit) polyparser
(* combinators and utilities for parsing located streams 1180b *)
fun @@ p = pair <$> srcloc <*> p
(* type declarations for consistency checking *)
val _ = op @@ : ('t, 'a) polyparser -> ('t, 'a located) polyparser
(* combinators and utilities for parsing located streams 1180c *)
infix 0 <?>
fun p <?> what = p <|> errorAt ("expected " ^ what) <$>! srcloc
(* type declarations for consistency checking *)
val _ = op <?> : ('t, 'a) polyparser * string -> ('t, 'a) polyparser
(* combinators and utilities for parsing located streams 1181 *)
infix 4 <!>
fun p <!> msg =
fn tokens => (case p tokens
of SOME (OK _, unread) =>
(case peek srcloc tokens
of SOME loc => SOME (errorAt msg loc, unread)
| NONE => NONE)
| _ => NONE)
(* type declarations for consistency checking *)
val _ = op <!> : ('t, 'a) polyparser * string -> ('t, 'b) polyparser
(* combinators and utilities for parsing located streams 1184d *)
fun nodups (what, context) (loc, names) =
let fun dup [] = OK names
| dup (x::xs) = if List.exists (fn y : string => y = x) xs then
errorAt (what ^ " " ^ x ^ " appears twice in " ^
context) loc
else
dup xs
in dup names
end
(* type declarations for consistency checking *)
val _ = op nodups : string * string -> srcloc * name list -> name list error
(* transformers for interchangeable brackets 1182 *)
fun notCurly (_, CURLY) = false
| notCurly _ = true
(* left: takes shape, succeeds or fails
right: takes shape and
succeeds with right bracket of correct shape
errors with right bracket of incorrect shape
fails with token that is not right bracket *)
fun left tokens = ((fn (loc, LEFT s) => SOME (loc, s) | _ => NONE) <$>? inline
) tokens
fun right tokens = ((fn (loc, RIGHT s) => SOME (loc, s) | _ => NONE) <$>? inline
) tokens
fun leftCurly tokens = sat (not o notCurly) left tokens
fun atRight expected = rewind right <?> expected
fun badRight msg =
(fn (loc, shape) => errorAt (msg ^ " " ^ rightString shape) loc) <$>! right
(* transformers for interchangeable brackets 1183 *)
type ('t, 'a) pb_parser = ('t plus_brackets, 'a) polyparser
datatype right_result
= FOUND_RIGHT of bracket_shape located
| SCANNED_TO_RIGHT of srcloc (* location where scanning started *)
| NO_RIGHT
fun scanToClose tokens =
let val loc = getOpt (peek srcloc tokens, ("end of stream", 9999))
fun scan lpcount tokens =
(* lpcount is the number of unmatched left parentheses *)
case tokens
of EOL _ ::: tokens => scan lpcount tokens
| INLINE (_, LEFT t) ::: tokens => scan (lpcount+1) tokens
| INLINE (_, RIGHT t) ::: tokens => if lpcount = 0 then
pure (SCANNED_TO_RIGHT loc)
tokens
else
scan (lpcount-1) tokens
| INLINE (_, PRETOKEN _) ::: tokens => scan lpcount tokens
| EOS => pure NO_RIGHT tokens
| SUSPENDED s => scan lpcount (demand s)
in scan 0 tokens
end
fun matchingRight tokens = (FOUND_RIGHT <$> right <|> scanToClose) tokens
fun matchBrackets _ (loc, left) _ NO_RIGHT =
errorAt ("unmatched " ^ leftString left) loc
| matchBrackets e (loc, left) _ (SCANNED_TO_RIGHT loc') =
errorAt ("expected " ^ e) loc
| matchBrackets _ (loc, left) a (FOUND_RIGHT (loc', right)) =
if left = right then
OK a
else
errorAt (rightString right ^ " does not match " ^ leftString left ^
(if loc <> loc' then " at " ^ srclocString loc else "")) loc'
(* type declarations for consistency checking *)
type right_result = right_result
val _ = op matchingRight : ('t, right_result) pb_parser
val _ = op scanToClose : ('t, right_result) pb_parser
val _ = op matchBrackets : string -> bracket_shape located -> 'a -> right_result
-> 'a error
(* transformers for interchangeable brackets 1184a *)
fun liberalBracket (expected, p) =
matchBrackets expected <$> sat notCurly left <*> p <*>! matchingRight
fun bracketKeyword (keyword, expected, p) =
liberalBracket (expected, keyword *> (p <?> expected))
fun bracket (expected, p) =
liberalBracket (expected, p <?> expected)
fun curlyBracket (expected, p) =
matchBrackets expected <$> leftCurly <*> (p <?> expected) <*>! matchingRight
(* type declarations for consistency checking *)
val _ = op bracketKeyword : ('t, 'keyword) pb_parser * string * ('t, 'a)
pb_parser -> ('t, 'a) pb_parser
(* transformers for interchangeable brackets 1184b *)
fun usageParser keyword =
let val getkeyword = eqx #"(" one *> (implode <$> many1 (sat (not o isDelim)
one))
in fn (usage, p) =>
case getkeyword (streamOfList (explode usage))
of SOME (OK k, _) => bracketKeyword (keyword k, usage, p)
| _ => let exception BadUsage of string in raise BadUsage usage end
end
(* type declarations for consistency checking *)
val _ = op usageParser : (string -> ('t, string) pb_parser) -> string * ('t, 'a)
pb_parser -> ('t, 'a) pb_parser
(* transformers for interchangeable brackets 1184c *)
fun pretoken stream = ((fn PRETOKEN t => SOME t | _ => NONE) <$>? token) stream
(* code used to debug parsers 1185a *)
fun safeTokens stream =
let fun tokens (seenEol, seenSuspended) =
let fun get (EOL _ ::: ts) = if seenSuspended then []
else tokens (true, false) ts
| get (INLINE (_, t) ::: ts) = t :: get ts
| get EOS = []
| get (SUSPENDED (ref (PRODUCED ts))) = get ts
| get (SUSPENDED s) = if seenEol then []
else tokens (false, true) (demand s)
in get
end
in tokens (false, false) stream
end
(* type declarations for consistency checking *)
val _ = op safeTokens : 'a located eol_marked stream -> 'a list
(* code used to debug parsers 1185b *)
fun showErrorInput asString p tokens =
case p tokens
of result as SOME (ERROR msg, rest) =>
if String.isSubstring " [input: " msg then
result
else
SOME (ERROR (msg ^ " [input: " ^
spaceSep (map asString (safeTokens tokens)) ^ "]"),
rest)
| result => result
(* type declarations for consistency checking *)
val _ = op showErrorInput : ('t -> string) -> ('t, 'a) polyparser -> ('t, 'a)
polyparser
(* code used to debug parsers 1186a *)
fun wrapAround tokenString what p tokens =
let fun t tok = " " ^ tokenString tok
val _ = app eprint ["Looking for ", what, " at"]
val _ = app (eprint o t) (safeTokens tokens)
val _ = eprint "\n"
val answer = p tokens
val _ = app eprint [case answer of NONE => "Didn't find " | SOME _ =>
"Found ",
what, "\n"]
in answer
end handle e => ( app eprint ["Search for ", what, " raised ", exnName e, "\n"
]
; raise e)
(* type declarations for consistency checking *)
val _ = op wrapAround : ('t -> string) -> string -> ('t, 'a) polyparser -> ('t,
'a) polyparser
(* streams that issue two forms of prompts 1186b *)
fun echoTagStream lines =
let fun echoIfTagged line =
if (String.substring (line, 0, 2) = ";#" handle _ => false) then
print line
else
()
in postStream (lines, echoIfTagged)
end
(* type declarations for consistency checking *)
val _ = op echoTagStream : line stream -> line stream
(* streams that issue two forms of prompts 1187a *)
fun stripAndReportErrors xs =
let fun next xs =
case streamGet xs
of SOME (ERROR msg, xs) => (eprintln msg; next xs)
| SOME (OK x, xs) => SOME (x, xs)
| NONE => NONE
in streamOfUnfold next xs
end
(* type declarations for consistency checking *)
val _ = op stripAndReportErrors : 'a error stream -> 'a stream
(* streams that issue two forms of prompts 1187b *)
fun lexLineWith lexer =
stripAndReportErrors o streamOfUnfold lexer o streamOfList o explode
(* type declarations for consistency checking *)
val _ = op lexLineWith : 't lexer -> line -> 't stream
(* streams that issue two forms of prompts 1187c *)
fun parseWithErrors parser =
let fun adjust (SOME (ERROR msg, tokens)) = SOME (ERROR msg, drainLine tokens)
| adjust other = other
in streamOfUnfold (adjust o parser)
end
(* type declarations for consistency checking *)
val _ = op parseWithErrors : ('t, 'a) polyparser -> 't located eol_marked stream
-> 'a error stream
(* streams that issue two forms of prompts 1187d *)
type prompts = { ps1 : string, ps2 : string }
val stdPrompts = { ps1 = "-> ", ps2 = " " }
val noPrompts = { ps1 = "", ps2 = "" }
(* type declarations for consistency checking *)
type prompts = prompts
val _ = op stdPrompts : prompts
val _ = op noPrompts : prompts
(* streams that issue two forms of prompts 1188 *)
fun ('t, 'a) interactiveParsedStream (lexer, parser) (name, lines, prompts) =
let val { ps1, ps2 } = prompts
val thePrompt = ref ps1
fun setPrompt ps = fn _ => thePrompt := ps
val lines = preStream (fn () => print (!thePrompt), echoTagStream lines)
fun lexAndDecorate (loc, line) =
let val tokens = postStream (lexLineWith lexer line, setPrompt ps2)
in streamMap INLINE (streamZip (streamRepeat loc, tokens)) @@@
streamOfList [EOL (snd loc)]
end
val xdefs_with_errors : 'a error stream =
(parseWithErrors parser o streamConcatMap lexAndDecorate o locatedStream
)
(name, lines)
(* type declarations for consistency checking *)
val _ = op interactiveParsedStream : 't lexer * ('t, 'a) polyparser -> string *
line stream * prompts -> 'a stream
val _ = op lexAndDecorate : srcloc * line -> 't located eol_marked stream
in
stripAndReportErrors (preStream (setPrompt ps1, xdefs_with_errors))
end
(* shared utility functions for initializing interpreters 371b *)
fun override_if_testing () = (*OMIT*)
if isSome (OS.Process.getEnv "NOERRORLOC") then (*OMIT*)
toplevel_error_format := WITHOUT_LOCATIONS (*OMIT*)
else (*OMIT*)
() (*OMIT*)
fun setup_error_format interactivity =
if prompts interactivity then
toplevel_error_format := WITHOUT_LOCATIONS
before override_if_testing () (*OMIT*)
else
toplevel_error_format := WITH_LOCATIONS
before override_if_testing () (*OMIT*)
(* function [[forward]], for mutual recursion through mutable reference cells 1148a *)
fun forward what _ =
let exception UnresolvedForwardDeclaration of string
in raise UnresolvedForwardDeclaration what
end
exception LeftAsExercise of string
(*****************************************************************)
(* *)
(* ABSTRACT SYNTAX AND VALUES FOR \USMALLTALK *)
(* *)
(*****************************************************************)
(* abstract syntax and values for \usmalltalk 932d *)
(* definitions of [[exp]], [[value]], [[rep]], [[class]], and [[method]] for \usmalltalk 931a *)
datatype exp = VAR of name
| SET of name * exp
| SEND of srcloc * name * exp * exp list
| BEGIN of exp list
| BLOCK of name list * exp list
| LITERAL of rep
| VALUE of value
| SUPER
(* definitions of [[exp]], [[value]], [[rep]], [[class]], and [[method]] for \usmalltalk 931c *)
and rep = USER of value ref env (* collection of named instance variables *)