summaryrefslogtreecommitdiff
path: root/util/prec-utils.scm
blob: 6ff7a1a6274f95bfcf44a5551686c7d160028f24 (about) (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
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
;;; prec-util.scm -- utilities for precedence parsing and printing of
;;;                  expressions
;;;
;;; author :  Sandra Loosemore
;;; date   :  15 Feb 1992
;;;
;;; The functions in this file are used by the expression printers
;;; and by precedence parsing.


;;; Uncurry the function application, looking for a con-ref as the
;;; actual function being applied.  Return the con-ref-con and a list
;;; of the arguments.

(define (extract-constructor fn args)
  (cond ((is-type? 'con-ref fn)
	 (values (con-ref-con fn) args))
	((is-type? 'app fn)
	 (extract-constructor (app-fn fn) (cons (app-arg fn) args)))
	(else
	 (values '#f '()))))


;;; If this is an infix operator application, there are really two nested
;;; applications that we handle at once.  The "fn" on the outer app
;;; points to a nested app which is a var-ref or con-ref with the infix?
;;; slot set to T.
;;; Returns three values: the fixity info, the operator, and the first
;;; argument (the arg to the outer application is the second argument).

(define (extract-infix-operator fn)
  (if (is-type? 'app fn)
      (let* ((new-fn  (app-fn  fn))
	     (arg     (app-arg fn))
	     (fixity  (operator-fixity new-fn)))
	(if fixity
	    (values fixity new-fn arg)
	    (values '#f '#f '#f)))
      (values '#f '#f '#f)))


;;; Return the fixity info for a reference to a var or con.
;;; If it doesn't have an explicit fixity, use the default of
;;; left associativity and precedence 9.

(define default-fixity
  (make fixity (associativity 'l) (precedence 9)))

(define (operator-fixity fn)
  (if (is-type? 'save-old-exp fn)
      (operator-fixity (save-old-exp-old-exp fn))
      (or (and (is-type? 'var-ref fn)
	       (var-ref-infix? fn)
	       (or (and (var-ref-var fn)
			(not (eq? (var-ref-var fn) *undefined-def*))
			(var-fixity (var-ref-var fn)))
		   default-fixity))
	  (and (is-type? 'con-ref fn)
	       (con-ref-infix? fn)
	       (or (and (con-ref-con fn)
			(not (eq? (con-ref-con fn) *undefined-def*))
			(con-fixity (con-ref-con fn)))
		   default-fixity))
	  (and (is-type? 'pcon fn)
	       (pcon-infix? fn)
	       (or (and (pcon-con fn)
			(not (eq? (pcon-con fn) *undefined-def*))
			(con-fixity (pcon-con fn)))
		   default-fixity))
	  '#f)))
  


;;; Determine the precedence of an expression.
;;; *** What about unary -?

(define (precedence-of-exp exp associativity)
  (cond ((is-type? 'save-old-exp exp)
	 (precedence-of-exp (save-old-exp-old-exp exp) associativity))
	((is-type? 'aexp exp) 10)
	((is-type? 'app exp)
	 (multiple-value-bind (fixity op arg1)
	     (extract-infix-operator (app-fn exp))
	   (declare (ignore op arg1))
	   (if fixity
	       (if (eq? associativity (fixity-associativity fixity))
		   (1+ (fixity-precedence fixity))
		   (fixity-precedence fixity))
	       10)))
	((is-type? 'lambda exp) 10)
	((is-type? 'let exp) 10)
	((is-type? 'if exp) 10)
	((is-type? 'case exp) 10)
	((pp-exp-list-section? exp) 10)
	((is-type? 'negate exp) 10)  ; hack, hack
	(else
	 0)))


;;; Determine whether a pp-exp-list is really a section -- the
;;; first or last exp in the list is really an infix op.

(define (pp-exp-list-section? object)
  (if (is-type? 'pp-exp-list object)
      (let ((exps  (pp-exp-list-exps object)))
	(or (infix-var-or-con? (car exps))
	    (infix-var-or-con? (list-ref exps (1- (length exps))))))
      '#f))

(define (infix-var-or-con? object)
  (or (and (is-type? 'var-ref object)
	   (var-ref-infix? object))
      (and (is-type? 'con-ref object)
	   (con-ref-infix? object))))