-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathlint.sml
682 lines (563 loc) · 25.3 KB
/
lint.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
(* TODO: PARENS AROUND RHS APPLICATION OK IF CLAUSE HAS PARENS AROUND ARG *)
(* TODO: infix thingies of the *same* operator should not have parens, especially
if right associative *)
functor LintFn (structure Report : REPORT where type name = Symbol.symbol
and type pos = SourceMap.charpos
) =
struct
local structure EM = ErrorMsg
open Absyn Ast
structure S = Symbol
val bogusID = S.varSymbol "bogus ID"
fun fst (x, y) = x
fun snd (x, y) = y
fun fixmap f {item=x, fixity=fix, region=r} = {item = f x, fixity=fix, region=r}
(* a slightly more convenient form of foldl *)
fun sequence f [] rpt = rpt
| sequence f (x::xs) rpt = sequence f xs (f x rpt)
val sequence : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b = sequence
in
(*
infix 7 * / mod div
infix 6 + - ^
infixr 5 :: @
infix 4 = <> > >= < <=
infix 3 := o
infix 0 before
*)
infix 3 >>
fun id x = x
fun f >> g = g o f
fun elabOpt f NONE rpt = rpt
| elabOpt f (SOME x) rpt = f x rpt
fun uncurry f (x, y) = f x y
fun curry f x y = f (x, y)
val say = Control_Print.say
val debugging = ref false
fun debugmsg (msg: string) = if !debugging then (say msg; say "\n") else ()
fun bug msg = ErrorMsg.impossible("LintFn: "^msg)
type fixenv = (S.symbol * Fixity.fixity) list
local
val left = [ (7, ["*", "/", "mod", "div"])
, (6, ["+", "-", "^"])
, (4, ["=", "<>", ">", ">=", "<", "<="])
, (3, [":=", "o"])
, (0, ["before"])
]
val right = [ (5, ["::", "@"]) ]
val sym = Symbol.varSymbol
fun addfix assoc ((prec, oprs), env) =
foldl (fn (opr, env) => (sym opr, assoc prec) :: env) env oprs
type env = (Symbol.symbol * Fixity.fixity) list
fun lookup (env, sym) =
case List.find (fn (s, f) => Symbol.eq (sym, s)) env
of SOME (_, f) => f
| NONE => Fixity.NONfix
in
val initEnv = [] : env
val initEnv = foldl (addfix Fixity.infixleft) initEnv left
val initEnv = foldl (addfix Fixity.infixright) initEnv right
structure Precedence = PrecedenceFn(type env = env
val lookup = lookup)
val lookFix = lookup
fun bindFix(id, fixity, env) = (id, fixity) :: env
end
(* sanity check *)
val _ = case Fixity.fixityToString (lookFix (initEnv, Symbol.varSymbol "@"))
of "infixr 5 " => ()
| s => (app print ["Bad fixity ", s, " for operator @\n"] ; bug "fixity")
val debugPrint = (fn x => if !debugging then print x else ())
fun stripExpAst(MarkExp(e,r'),r) = stripExpAst(e,r')
| stripExpAst(ConstraintExp{expr=e,...},r) = stripExpAst(e,r)
| stripExpAst(SeqExp[e],r) = stripExpAst(e,r)
| stripExpAst(FlatAppExp[{item,region,...}],r) = stripExpAst(item,region)
| stripExpAst x = x
fun stripExpAst(MarkExp(e,r')) = stripExpAst e
| stripExpAst(ConstraintExp{expr=e,...}) = stripExpAst e
| stripExpAst(SeqExp[e]) = stripExpAst e
| stripExpAst(FlatAppExp[{item,...}]) = stripExpAst item
| stripExpAst x = x
fun ensureInfix error getfix {item,fixity,region} =
(case getfix fixity
of Fixity.NONfix =>
error region EM.COMPLAIN
"infix operator required, or delete parentheses"
EM.nullErrorBody
| _ => ();
item)
fun ensureNonfix error getfix {item,fixity,region} =
(case (getfix fixity, fixity)
of (Fixity.NONfix,_) => ()
| (_,SOME sym) =>
error region EM.COMPLAIN
("infix operator \"" ^ S.name sym ^
"\" used without \"op\" in fun dec")
EM.nullErrorBody
| _ => bug "ensureNonfix";
item)
fun getname error (MarkPat(p,region),_) = getname error (p,region)
| getname error (VarPat[v], _) = v
| getname error (_, region) =
(error region EM.COMPLAIN "illegal function symbol in clause"
EM.nullErrorBody;
bogusID)
exception Unimp of string
fun unimp what = raise Unimp what
(**** ABSTRACT TYPE DECLARATIONS ****)
fun elabABSTYPEdec({abstycs,withtycs,body},env,rpt,
rpath,region,compInfo) =
let val (datatycs,withtycs,_,env1) =
unimp "ET.elabDATATYPEdec" ({datatycs=abstycs,withtycs=withtycs}, env,
[], rpath, region, compInfo)
val (body,env2) =
unimp "elabDec"(body,env,rpath,region,compInfo)
(* datatycs will be changed to abstycs during type checking
by changing the eqprop field *)
in rpt
end (* function elabABSTYPEdec *)
(**** ELABORATE GENERAL (core) DECLARATIONS ****)
and elabDec ({source}, dec, env, region, rpt) =
let
fun error x = ErrorMsg.error source x
val _ = debugmsg ">>ElabCore.elabDec"
(**** TYPES ****)
datatype tycontext
= Exn
| Constructor
| TConstraint
fun elabTy region tcontext ty rpt = (debugmsg "skipped type"; rpt)
(**** EXCEPTION DECLARATIONS ****)
fun elabEb (region:region) (eb:Ast.eb) rpt =
case eb
of EbGen{exn=id,etype=NONE} => rpt
| EbGen{exn=id,etype=SOME typ} => elabTy region Exn typ rpt
| EbDef{exn=id,edef=qid} => rpt
| MarkEb(eb,region) => elabEb region eb rpt
(**** PATTERNS ****)
fun apply_pat (c as MarkPat(_,(l1,r1)),p as MarkPat(_,(l2,r2))) =
MarkPat(AppPat{constr=c, argument=p},(Int.min(l1,l2),Int.max(r1,r2)))
| apply_pat (c ,p) = AppPat{constr=c, argument=p}
fun tuple_pat (a as MarkPat(_,(l,_)),b as MarkPat(_,(_,r))) =
MarkPat(TuplePat[a,b],(l,r))
| tuple_pat (a,b) = TuplePat[a,b]
datatype comma_syntax = Record | Tuple | List | Vector
(* things that have elements separated by commas *)
fun whatc Record = "record"
| whatc Tuple = "tuple"
| whatc List = "list"
| whatc Vector = "vector"
datatype common_context
= InfixChild
| Function
| Argument
| Element of comma_syntax
| Bracketed of region (* retains location of brackets *)
| Constrained (* under a type contraint exp : ty *)
| Handle (* either pat or exp in handle pat => exp | ... *)
| CaseMatch (* either pat or exp in case e of pat => exp | ... *)
| FnMatch (* either pat or exp in fn pat => exp | ... *)
| HighLevel (* infix expression in an exp-specific context *)
datatype pcontext
= PClause
| PVal
| POr (* SML/NJ or-patterns *)
| P of common_context
datatype econtext
= Condition
| IfCase
| WhileCondition
| WhileBody
| Rhs
| Raise
| LetBody
| Scrutinee (* exp in case exp of ... *)
| Sequent (* exp in (exp1 ; exp2 ; ... ; expn) *)
| E of common_context
fun unE (E context) = context
| unE _ = HighLevel
fun unP (P context) = context
| unP _ = HighLevel
datatype 'a infixed
= ATOM of 'a
| INFIX of 'a infixed * 'a infixed * 'a infixed
| APPLY of 'a infixed * 'a infixed
fun parse items = Precedence.parse {apply=APPLY, infixapp=INFIX} items
fun elabOpr varOnly (ATOM a) = varOnly a
| elabOpr _ _ = bug "lint: syntactic form of infix operator"
fun expVarOnly (VarExp _) = (fn rpt => rpt)
| expVarOnly (MarkExp (e, _)) = expVarOnly e
| expVarOnly _ = bug "lint: syntactic form of infix operator"
fun patVarOnly (VarPat _) = (fn rpt => rpt)
| patVarOnly (MarkPat (p, _)) = patVarOnly p
| patVarOnly _ = bug "lint: syntactic form of infix operator in pattern"
fun elabInfix varOnly wrap atom (thing, env, context, region) =
let fun elab thing context =
elabInfix varOnly wrap atom (thing, env, context, region)
in case thing
of ATOM a => atom (a, env, context, region)
| APPLY (f, arg) => elab f (wrap Function) >> elab arg (wrap Argument)
| INFIX (left, opr, right) =>
elab left (wrap InfixChild) >> elabOpr varOnly opr >> elab right (wrap InfixChild)
end
fun atom (Bracketed region) rpt what =
Report.brackets ("around " ^ what, region, rpt)
| atom _ rpt _ = rpt
fun eatom (E c) rpt what = atom c rpt what
| eatom _ rpt _ = rpt
fun patom (P c) rpt what = atom c rpt what
| patom _ rpt _ = rpt
fun elabPat (p:Ast.pat, env, context : pcontext, region:region) rpt =
let val atom = patom context rpt
fun elab ctx pat rpt = elabPat (pat, env, ctx, region) rpt
val elem = P o Element
in
case p
of WildPat => atom "wildcard '_'"
| VarPat [_] => atom "name"
| VarPat _ => atom "qualified name"
| IntPat s => atom "integer literal"
| WordPat s => atom "word literal"
| StringPat s => atom "string literal"
| CharPat s => atom "character literal"
| RecordPat {def,flexibility} =>
foldl (uncurry (elab (elem Record) o snd)) (atom "record pattern") def
| ListPat pats =>
sequence (elab (elem List)) pats (atom "list pattern")
| TuplePat pats =>
sequence (elab (elem Tuple)) pats (atom "tuple pattern")
| VectorPat pats =>
sequence (elab (elem Vector)) pats (atom "vector pattern")
| OrPat pats =>
sequence (elab POr) pats rpt
| AppPat {constr, argument} =>
(elab (P Function) constr >> elab (P Argument) argument) rpt
| ConstraintPat {pattern=pat,constraint=ty} =>
(elab (P Constrained) pat >> elabTy region TConstraint ty) rpt
| LayeredPat {varPat,expPat} =>
(elab (P InfixChild) varPat >> elab (P InfixChild) expPat) rpt
| MarkPat (pat,region) =>
elabPat (pat, env, context, region) rpt
| FlatAppPat pats =>
elabInfix patVarOnly P elabPat
(parse(map (fixmap ATOM) pats,env,error), env, context, region) rpt
end
and elabPatList(ps, env, context, region:region) rpt =
sequence (fn p => elabPat (p, env, context, region)) ps rpt
(**** EXPRESSIONS ****)
fun checkBracket region context rpt =
case context
of Rhs => Report.brackets("parens on RHS of function", region, rpt)
| _ => (debugmsg "brackets not checked" ; rpt)
fun checkBracket region (context:econtext) rpt e =
let fun fail why = Report.brackets(why, region, rpt)
fun atom what = fail ("around " ^ what) (* should be OK in some
pattern clauses *)
fun badIfFunction (E Function) = fail "around partially applied function"
| badIfFunction _ = rpt
fun checkAtom e k = (* things it is never right to have parens around *)
case e
of VarExp [sym] =>
(case lookFix (env, sym)
of Fixity.NONfix => atom "name"
| _ => k e (* got here because of 'op' *))
| VarExp _ => atom "qualified name"
| IntExp s => atom "integer literal"
| WordExp s => atom "word literal"
| RealExp r => atom "floating-point literal"
| StringExp s => atom "string literal"
| CharExp s => atom "character literal"
| RecordExp _ => atom "record literal"
| SeqExp [e] => checkAtom (stripExpAst e) k
| ListExp _ => atom "list literal"
| TupleExp exps => atom "tuple literal"
| VectorExp exps => atom "vector literal"
| e => k e
fun common c e =
case c
of InfixChild => rpt (* always OK *)
| Function => (debugmsg "function posn not checked"; rpt)
| Argument => rpt (* brackets OK *)
| Element container => fail ("around element of " ^ whatc container)
| Bracketed _ => fail "immediately inside other parentheses"
| Constrained => fail "around exp in (exp) : ty"
| Handle => rpt (* fail "around expression in exception handler" *)
(* evilly flags this:
(f x before evalFuel := old) handle e => (evalFuel := old; raise e)
*)
| CaseMatch => fail "around expression in case match"
| FnMatch => fail "around right-hand side of anonymous 'fn'"
| HighLevel => fail "in some unspecified bad place"
in case stripExpAst e
of CaseExp _ => rpt
| FnExp _ => rpt
| HandleExp _ => rpt
| SeqExp (_::_::_) => rpt
| e => checkAtom e (fn e =>
case context
of Condition => fail "around condition in 'if'"
| IfCase => fail "around case in 'if'"
| WhileCondition => fail "around condition in 'while'"
| WhileBody => fail "around body of 'while'"
| Rhs => fail "around right-hand side of clause"
| Raise => rpt (* let it pass *)
| LetBody => fail "around body of let-expression"
| Scrutinee => fail "around expression scrutinized in 'case'"
| Sequent => fail "around expression in sequence"
| E c => common c e)
end
type env = fixenv
fun elabExp(exp: Ast.exp, env: env, context: econtext, region: region) (rpt : Report.t)
: Report.t =
let val atom = eatom context rpt
fun elab (ctx:econtext) exp rpt = elabExp (exp, env, ctx, region) rpt
val elem = E o Element
in
(case exp
of BracketExp e =>
let val rpt = checkBracket region context rpt e
in elab (E (Bracketed region)) e rpt
end
| VarExp [sym] =>
(case lookFix (env, sym)
of Fixity.NONfix => atom "name"
| _ => rpt (* got here because of 'op' *))
| VarExp _ => atom "qualified name"
| IntExp s => atom "integer literal"
| WordExp s => atom "word literal"
| RealExp r => atom "floating-point literal"
| StringExp s => atom "string literal"
| CharExp s => atom "character literal"
| RecordExp cells =>
sequence (elab (elem Record) o snd) cells (atom "record literal")
| SeqExp [e] => elab context e rpt
| SeqExp exps => sequence (elab Sequent) exps rpt
| ListExp exps =>
sequence (elab (elem List)) exps (atom "list literal")
| TupleExp exps =>
sequence (elab (elem Tuple)) exps (atom "tuple literal")
| VectorExp exps =>
sequence (elab (elem Vector)) exps (atom "vector literal")
| AppExp {function,argument} =>
elab (E Argument) argument (elab (E Function) function rpt)
| ConstraintExp {expr=exp,constraint=ty} =>
(elab (E Constrained) exp >> elabTy region TConstraint ty) rpt
| HandleExp {expr,rules} =>
(elab (E Handle) expr >> elabMatch (rules, env, Handle, region)) rpt
| RaiseExp exp => elab Raise exp rpt
| LetExp {dec,expr} =>
let val (env, rpt) = elabDec'(dec, env, region, rpt)
in elabExp (expr, env, LetBody, region) rpt
end
| CaseExp {expr,rules} =>
(elab Scrutinee expr >> elabMatch (rules, env, CaseMatch, region)) rpt
| IfExp {test,thenCase,elseCase} =>
(elab Condition test >> elab IfCase thenCase >> elab IfCase elseCase) rpt
| AndalsoExp (exp1,exp2) =>
(elab (E InfixChild) exp1 >> elab (E InfixChild) exp2) rpt
| OrelseExp (exp1,exp2) =>
(elab (E InfixChild) exp1 >> elab (E InfixChild) exp2) rpt
| WhileExp {test,expr} =>
(elab WhileCondition test >> elab WhileBody expr) rpt
| FnExp rules => elabMatch (rules, env, FnMatch, region) rpt
| MarkExp (exp,region) => elabExp (exp, env, context, region) rpt
| SelectorExp s => atom "record selector"
| FlatAppExp items =>
elabInfix expVarOnly E elabExp
(parse(map (fixmap ATOM) items,env,error),env,context,region) rpt
)end
and elabMatch (rs,env,context,region) =
sequence (fn (Rule {pat, exp}) =>
elabPat (pat, env, P context, region) >>
elabExp (exp, env, E context, region)) rs
(* XXX TODO: singleton matches special; others may recommend parens
at least in some contexts *)
(**** SIMPLE DECLARATIONS ****)
and elabDb region (_, rpt) = (debugmsg "skipped db"; rpt) (* BOGUS *)
and elabTb region (_, rpt) = (debugmsg "skipped tb"; rpt) (* BOGUS *)
and elabDec'(dec,env,region,rpt) : fixenv * Report.t =
(* N.B. current code *extends* an existing environment,
but it may make more sense to *return* one and combine,
so as to deal with 'local' declarations *)
let fun lift rpt = (env, rpt)
fun elab dev (env, rpt) = elabDec'(dev, env, region, rpt)
in
(case dec
of TypeDec tbs => lift (foldl (elabTb region) rpt tbs)
| DatatypeDec x =>
let val rpt = foldl (elabDb region) rpt (#datatycs x)
val rpt = foldl (elabTb region) rpt (#withtycs x)
in lift rpt
end
| DataReplDec(name,path) => lift rpt
| AbstypeDec x =>
let val rpt = foldl (elabDb region) rpt (#abstycs x)
val rpt = foldl (elabTb region) rpt (#withtycs x)
in elabDec' (#body x, env, region, rpt)
end
| ExceptionDec ebs => (lift o sequence (elabEb region) ebs) rpt
| ValDec(vbs,_) => lift (foldl (elabVb (region, env)) rpt vbs)
| FunDec(fbs,explicitTvs) =>
lift (elabFUNdec(fbs,explicitTvs,env,region,rpt))
| ValrecDec(rvbs,explicitTvs) =>
lift (sequence (elabRvb (region, env)) rvbs rpt)
| SeqDec ds =>
foldl (fn (dec, (env, rpt)) => elabDec'(dec, env, region, rpt)) (env, rpt) ds
| LocalDec (dec, body) =>
let val (env1, rpt) = elab dec (env, rpt)
val (env2, rpt) = elab body (env1, rpt)
in (fixityExtend body env, rpt)
end
| OpenDec ds => lift rpt
| FixDec (ds as {fixity,ops}) =>
(foldl (fn (id, env) => bindFix(id, fixity, env)) env ops, rpt)
| OvldDec dec => lift rpt (* SML/NJ internal; not linted *)
| MarkDec(dec,region') => elabDec'(dec, env, region', rpt)
| StrDec strbs => lift (elabStrbs(strbs, env, region, rpt))
| AbsDec _ => bug "absdec"
| FctDec fctbs => lift (sequence (elabFctb (env, region)) fctbs rpt)
| SigDec _ => bug "sigdec"
| FsigDec _ => bug "fsigdec")
end
and fixityExtend body env = (debugmsg "skipped fixity declarations in 'local'"; env)
and elabStrbs (strbs, env, region, rpt) =
foldl (fn (strb, rpt) => elabStrb (strb, env, region, rpt)) rpt strbs
and elabStrb (strb, env, region, rpt) =
(case strb
of MarkStrb (strb, region) => elabStrb (strb, env, region, rpt)
| Strb {name, def, constraint} => elabStrexp (def, env, region, rpt))
and elabStrexp (def, env, region, rpt) =
(case def
of VarStr _ => rpt
| BaseStr dec => snd (elabDec' (dec, env, region, rpt))
| ConstrainedStr (def, constraint) =>
elabStrexp (def, env, region, rpt) (* XXX constraint not checked *)
| AppStr (_, args) =>
foldl (fn ((def, _), rpt) => elabStrexp(def, env, region, rpt)) rpt args
| AppStrI (path, args) => elabStrexp(AppStr (path, args), env, region, rpt)
| LetStr (dec, def) =>
let val (env, rpt) = elabDec' (dec, env, region, rpt)
in elabStrexp (def, env, region, rpt)
end
| MarkStr (def, region) => elabStrexp (def, env, region, rpt))
and elabFctb (env, region) fctb =
(case fctb
of MarkFctb (fctb, region) => elabFctb (env, region) fctb
| Fctb {name, def} => elabFctexp (env, region) def)
and elabFctexp (env, region) def =
(case def
of VarFct(spath,constraintExpOp) =>
(debugmsg "skipped functor variable"; id)
| LetFct(decl,fct) =>
(debugmsg "skipped let functor (have no idea what this is)"; id)
| AppFct(spath,larg,constraint) =>
(debugmsg "skipped application functor; call me later"; id)
| BaseFct{params,body,constraint} =>
( debugmsg "skipped functor parameters"
; debugmsg "skipped functor constraint"
; (fn rpt => elabStrexp (body, env, region, rpt))
)
| MarkFct(fctexp',region') => elabFctexp (env, region') fctexp')
(**** LOCAL ****)
(*
and elabLOCALdec((ldecs1,ldecs2),env,rpath:IP.path,region) =
let val (ld1,env1,tv1,updt1) = elabDec'(ldecs1,env,IP.IPATH[],region)
val (ld2,env2,tv2,updt2) =
elabDec'(ldecs2,SE.atop(env1,env),rpath,region)
fun updt tv = (updt1 tv;updt2 tv)
in (LOCALdec(ld1,ld2), env2,union(tv1,tv2,error region),updt)
end
*)
(**** VALUE DECLARATIONS ****)
and elabVb (region, env) (vb, rpt) =
(case vb
of MarkVb(vb, region) => elabVb (region, env) (vb, rpt)
| Vb {pat, exp, ...} =>
(elabPat (pat, env, PVal, region) >> elabExp (exp, env, Rhs, region)) rpt)
and elabRvb (region, env) rvb rpt =
(case rvb
of MarkRvb(rvb, region) => elabRvb (region, env) rvb rpt
| Rvb {resultty, exp, ...} =>
( debugmsg "linting rvb"
; elabOpt (elabTy region TConstraint) resultty >>
elabExp (exp, env, Rhs, region)) rpt)
and elabFUNdec(fb,etvs,env,region,rpt) =
let (* makevar: parse the function header to determine the function name *)
fun makevar _ (MarkFb(fb,fbregion)) = makevar fbregion fb
| makevar fbregion (Fb(clauses,lazyp)) =
let fun getfix(SOME f) = lookFix(env,f)
| getfix NONE = Fixity.NONfix
val ensureInfix = ensureInfix error getfix
val ensureNonfix = ensureNonfix error getfix
val getname = getname error
fun parse'({item=FlatAppPat[a,b as {region,...},c],...}
::rest) =
(getname(ensureInfix b, region),
tuple_pat(ensureNonfix a, ensureNonfix c)
:: map ensureNonfix rest)
| parse' [{item,region,...}] =
(error region EM.COMPLAIN
"can't find function arguments in clause"
EM.nullErrorBody;
(getname(item,region), [WildPat]))
| parse' ((a as {region,...}) :: rest) =
(getname(ensureNonfix a, region),
map ensureNonfix rest)
| parse' [] = bug "parse':[]"
fun parse({item=MarkPat(p,_),region,fixity}::rest) =
parse({item=p,region=region,fixity=fixity}::rest)
| parse (pats as [a as {region=ra,...},
b as {item,fixity,region},c]) =
(case getfix fixity
of Fixity.NONfix => parse' pats
| _ => (getname(item,region),
[tuple_pat(ensureNonfix a, ensureNonfix c)]))
| parse pats = parse' pats
fun parseClause(Clause{pats,resultty,exp}) =
let val (funsym,argpats) = parse pats
in {kind=(), funsym=funsym,argpats=argpats,
resultty=resultty,exp=exp}
end
val (clauses, var) =
case map parseClause clauses
of [] => bug "elabcore:no clauses"
| (l as ({funsym=var,...}::_)) => (l,var)
val _ = if List.exists (fn {funsym,...} =>
not(S.eq(var,funsym))) clauses
then error fbregion EM.COMPLAIN
"clauses don't all have same function name"
EM.nullErrorBody
else ()
(* DBM: fix bug 1357
val _ = checkBoundConstructor(env,var,error fbregion)
*)
val v = var
in (v,clauses,fbregion)
end (* makevar *)
val fundecs = map (makevar region) fb
fun elabClause(region,({kind,argpats,resultty,exp,funsym}), rpt) =
(sequence (fn p => elabPat (p, env, PClause, region)) argpats >>
elabExp(exp, env, Rhs, region)) rpt
fun elabFundec ((var,clauses,region),rpt) =
foldl (fn (c2,rpt) => elabClause(region,c2,rpt)) rpt clauses
val rpt = foldl elabFundec rpt fundecs
in rpt
end
(*
and elabSEQdec(ds,env,rpath:IP.path,region) =
let val (ds1,env1,tv1,updt1) =
foldl
(fn (decl2,(ds2,env2,tvs2,updt2)) =>
let val (d3,env3,tvs3,updt3) =
elabDec'(decl2,SE.atop(env2,env),rpath,region)
in (d3::ds2, SE.atop(env3,env2),
union(tvs3,tvs2,error region), updt3::updt2)
end)
([],SE.empty,TS.empty,[]) ds
fun updt tv : unit = app (fn f => f tv) updt1
in (SEQdec(rev ds1),env1,tv1,updt)
end
*)
in elabDec' (dec, env, region, rpt)
end (* function elabDec *)
end (* top-level local *)
end