X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/5eeb83d2b620e77000ab77269faa974007c9ff28..4979de888ad699695849a884e0ab8faedd3544f1:/src/pset-parse.lisp diff --git a/src/pset-parse.lisp b/src/pset-parse.lisp index e86be27..cfd2b4a 100644 --- a/src/pset-parse.lisp +++ b/src/pset-parse.lisp @@ -63,24 +63,21 @@ (with-default-error-location (,floc) ,@body)))))) - (flet ((dispatch (name args &rest spec) - ;; Evaluate the ARGS to determine their types and values. Find - ;; the first SPEC, of the form (RETTY OP ARGTY*), where the - ;; ARGTYs match the argument types, in order, and apply OP to - ;; the argument values, return this as a result of type RETTY. - ;; If no SPEC matches, then report an error. - - (oplambda - (let ((args (mapcar (compose #'funcall #'cons) args))) - (aif (find-if (lambda (item) - (every (lambda (type arg) - (eql type (car arg))) - (cddr item) args)) - spec) - (values (car it) (apply (cadr it) (mapcar #'cdr args))) - (error "Type mismatch: operator `~A' applied to ~ - types ~{~(~A~)~#[~; and ~;, ~]~}" - name (mapcar #'car args))))))) + (labels ((want (type thunk) + ;; Evaluate THUNK and convert its result to the given TYPE. + (multiple-value-bind (ty val) (funcall thunk) + (coerce-property-value val ty type))) + + (int-unop (intop x) + ;; Evaluate X to an integer, and apply INTOP to the result, + ;; giving another integer. + (oplambda (values :int (funcall intop (want :int x))))) + + (int-binop (intop x y) + ;; Evaluate X and Y to integers, and apply INTOP to the + ;; results, giving another integer. + (oplambda + (values :int (funcall intop (want :int x) (want :int y)))))) (with-parser-context (token-scanner-context :scanner scanner) (when-parse () @@ -141,29 +138,18 @@ nil nil)))) ;; Binary operators. - ((:op #\* binop "*" (x y 7) - (dispatch "*" (list x y) (list :int #'* :int :int))) - (:op #\/ binop "/" (x y 7) - (dispatch "/" (list x y) - (list :int - (lambda (x y) - (cond ((zerop y) - (cerror* - "Division by zero") - (cons :invalid nil)) - (t - (floor x y)))) - :int :int))) - (:op #\+ binop "+" (x y 5) - (dispatch "+" (list x y) (list :int #'+ :int :int))) - (:op #\- binop "-" (x y 5) - (dispatch "-" (list x y) (list :int #'- :int :int)))) + ((:op #\* binop "*" (x y 70) (int-binop #'* x y)) + (:op #\/ binop "/" (x y 70) + (oplambda + (let ((x (want :int x)) (y (want :int y))) + (when (zerop y) (error "Division by zero")) + (values :int (floor x y))))) + (:op #\+ binop "+" (x y 60) (int-binop #'+ x y)) + (:op #\- binop "-" (x y 60) (int-binop #'- x y))) ;; Prefix operators. - ((:op #\+ preop "+" (x 9) - (dispatch "+" (list x) (list :int #'+ :int))) - (:op #\- preop "-" (x 9) - (dispatch "-" (list x) (list :int #'- :int))) + ((:op #\+ preop "+" (x 90) (int-unop #'identity x)) + (:op #\- preop "-" (x 90) (int-unop #'- x)) (:op #\( lparen #\))) ;; Postfix operators.