4e987026 |
;;; prec-parse.scm -- do precedence parsing of expressions and patterns
;;;
;;; author : John & Sandra
;;; date : 04 Feb 1992
;;;
;;;
;;; ==================================================================
;;; Handling for pp-exp-list
;;; ==================================================================
;;; This function is called during the scope phase after all of the
;;; exps in a pp-exp-list have already been walked. Basically, the
;;; purpose is to turn the original pp-exp-list into something else.
;;; Look for the section cases first and treat them specially.
;;; Sections are handled by inserting a magic cookie (void) into the
;;; list where the `missing' operand of the section would be and then
;;; making sure the cookie stays at the top.
;;; Unary minus needs checking to avoid things like a*-a.
(define (massage-pp-exp-list exps)
(let* ((first-term (car exps))
(last-term (car (last exps)))
(type (cond ((infix-var-or-con? first-term) 'section-l)
((infix-var-or-con? last-term) 'section-r)
(else 'exp)))
(exps1 (cond ((eq? type 'section-l)
(cons (make void) exps))
((eq? type 'section-r)
(append exps (list (make void))))
(else exps)))
(parsed-exp (parse-pp-list '#f exps1)))
(if (eq? type 'exp)
parsed-exp
(if (or (not (app? parsed-exp))
(not (app? (app-fn parsed-exp))))
(begin
(signal-section-precedence-conflict
(if (eq? type 'section-l) first-term last-term))
(make void))
(let ((rhs (app-arg parsed-exp))
(op (app-fn (app-fn parsed-exp)))
(lhs (app-arg (app-fn parsed-exp))))
(if (eq? type 'section-l)
(if (void? lhs)
(make section-l (op op) (exp rhs))
(begin
(signal-section-precedence-conflict first-term)
(make void)))
(if (void? rhs)
(make section-r (op op) (exp lhs))
(begin
(signal-section-precedence-conflict last-term)
(make void)))))))))
;;; ==================================================================
;;; Handling for pp-pat-list
;;; ==================================================================
;;; In this case, we have to do an explicit walk of the pattern looking
;;; at all of its subpatterns.
;;; ** This is a crock - the scope walker needs fixing.
(define (massage-pattern pat)
(cond ((is-type? 'as-pat pat)
(setf (as-pat-pattern pat) (massage-pattern (as-pat-pattern pat)))
pat)
((is-type? 'irr-pat pat)
(setf (irr-pat-pattern pat) (massage-pattern (irr-pat-pattern pat)))
pat)
((is-type? 'plus-pat pat)
(setf (plus-pat-pattern pat) (massage-pattern (plus-pat-pattern pat)))
pat)
((is-type? 'pcon pat)
(when (eq? (pcon-con pat) *undefined-def*)
(setf (pcon-con pat) (lookup-toplevel-name (pcon-name pat))))
(setf (pcon-pats pat) (massage-pattern-list (pcon-pats pat)))
pat)
((is-type? 'list-pat pat)
(setf (list-pat-pats pat) (massage-pattern-list (list-pat-pats pat)))
pat)
((is-type? 'pp-pat-list pat)
(parse-pp-list '#t (massage-pattern-list (pp-pat-list-pats pat))))
(else
pat)))
(define (massage-pattern-list pats)
(map (function massage-pattern) pats))
;;; ==================================================================
;;; Shared support
;;; ==================================================================
;;; This is the main routine.
(define (parse-pp-list pattern? l)
(mlet (((stack terms) (push-pp-stack '() l)))
(pp-parse-next-term pattern? stack terms)))
(define (pp-parse-next-term pattern? stack terms)
(if (null? terms)
(reduce-complete-stack pattern? stack)
(let ((stack (reduce-stronger-ops pattern? stack (car terms))))
(mlet (((stack terms)
(push-pp-stack (cons (car terms) stack) (cdr terms))))
(pp-parse-next-term pattern? stack terms)))))
(define (reduce-complete-stack pattern? stack)
(if (pp-stack-op-empty? stack)
(car stack)
(reduce-complete-stack pattern? (reduce-pp-stack pattern? stack))))
(define (reduce-pp-stack pattern? stack)
(let ((term (car stack))
(op (cadr stack)))
(if pattern?
(cond ((pp-pat-plus? op)
(let ((lhs (caddr stack)))
(cond ((or (not (const-pat? term))
(and (not (var-pat? lhs))
(not (wildcard-pat? lhs))))
(signal-plus-precedence-conflict term)
(cddr stack))
(else
(cons (make plus-pat (pattern lhs)
(k (integer-const-value
(const-pat-value term))))
(cdddr stack))))))
((pp-pat-negated? op)
(cond ((const-pat? term)
(let ((v (const-pat-value term)))
(if (integer-const? v)
(setf (integer-const-value v)
(- (integer-const-value v)))
(setf (float-const-numerator v)
(- (float-const-numerator v)))))
(cons term (cddr stack)))
(else
(signal-minus-precedence-conflict term)
(cons term (cddr stack)))))
(else
(setf (pcon-pats op) (list (caddr stack) term))
(cons op (cdddr stack))))
(cond ((negate? op)
(cons (**app (**var/def (core-symbol "negate")) term)
(cddr stack)))
(else
(cons (**app op (caddr stack) term) (cdddr stack)))))))
(define (pp-stack-op-empty? stack)
(null? (cdr stack)))
(define (top-stack-op stack)
(cadr stack))
(define (push-pp-stack stack terms)
(let ((term (car terms)))
(if (or (negate? term) (pp-pat-negated? term))
(begin
(when (and stack (stronger-op? (car stack) term))
(unary-minus-prec-conflict term))
(push-pp-stack (cons term stack) (cdr terms)))
(values (cons term stack) (cdr terms)))))
(define (reduce-stronger-ops pattern? stack op)
(cond ((pp-stack-op-empty? stack) stack)
((stronger-op? (top-stack-op stack) op)
(reduce-stronger-ops pattern? (reduce-pp-stack pattern? stack) op))
(else stack)))
(define (stronger-op? op1 op2)
(let ((fixity1 (get-op-fixity op1))
(fixity2 (get-op-fixity op2)))
(cond ((> (fixity-precedence fixity1) (fixity-precedence fixity2))
'#t)
((< (fixity-precedence fixity1) (fixity-precedence fixity2))
'#f)
(else
(let ((a1 (fixity-associativity fixity1))
(a2 (fixity-associativity fixity2)))
(if (eq? a1 a2)
(cond ((eq? a1 'l)
'#t)
((eq? a1 'r)
'#f)
(else
(signal-precedence-conflict op1 op2)
'#t))
(begin
(signal-precedence-conflict op1 op2)
'#t))))
)))
(define (get-op-fixity op)
(cond ((var-ref? op)
(pp-get-var-fixity (var-ref-var op)))
((con-ref? op)
(pp-get-con-fixity (con-ref-con op)))
((pcon? op)
(pp-get-con-fixity (pcon-con op)))
((or (negate? op) (pp-pat-negated? op))
(pp-get-var-fixity (core-symbol "-")))
((pp-pat-plus? op)
(pp-get-var-fixity (core-symbol "+")))
(else
(error "Bad op ~s in pp-parse." op))))
(define (pp-get-var-fixity def)
(if (eq? (var-fixity def) '#f)
default-fixity
(var-fixity def)))
(define (pp-get-con-fixity def)
(if (eq? (con-fixity def) '#f)
default-fixity
(con-fixity def)))
;;; Error handlers
(define (signal-section-precedence-conflict op)
(phase-error 'section-precedence-conflict
"Operators in section body have lower precedence than section operator ~A."
op))
(define (signal-precedence-conflict op1 op2)
(phase-error 'precedence-conflict
"The operators ~s and ~s appear consecutively, but they have the same~%~
precedence and are not either both left or both right associative.~%
You must add parentheses to avoid a precedence conflict."
op1 op2))
(define (signal-plus-precedence-conflict term)
(phase-error 'plus-precedence-conflict
"You need to put parentheses around the plus-pattern ~a~%~
to avoid a precedence conflict."
term))
(define (signal-minus-precedence-conflict arg)
(phase-error 'minus-precedence-conflict
"You need to put parentheses around the negative literal ~a~%~
to avoid a precedence conflict."
arg))
(define (unary-minus-prec-conflict arg)
(recoverable-error 'minus-precedence-conflict
"Operator ~A too strong for unary minus - add parens please!~%"
arg))
|