Commit 93810c8c authored by hal's avatar hal Committed by Jeffrey I. Schiller

Change division by 0 to show generate an error.

We trigger an “ErrorOccurred” event when we attempt to divide by
zero. This can be handled by the App Inventor programmers. If it isn’t
handled, a Notification is generated to the end-user. If the numerator
is non-zero, +-INTEGER_MAX (2147483647) is returned. If the numerator is
0, then a 0 is returned.

Change-Id: Ib323c692528fd331c33fcd64de5caa24c2ff9126
parent 5ac4f709
......@@ -1043,6 +1043,13 @@
;; (android-log "signal-runtime-error ")
(primitive-throw (make YailRuntimeError message error-type)))
(define (signal-runtime-form-error function-name error-number message)
;; this is like signal-runtime-error, but it generates an error in
;; the current Screen that can be modified by the Screen.ErrorOccurred handler
(*:runtimeFormErrorOccurredEvent *this-form* function-name error-number message)
)
;;; Kludge based on Kawa compilation issues with 'not'
(define (yail-not foo) (not foo))
......@@ -1456,27 +1463,40 @@
(lambda (x)
(max lowest (min x highest)))))
(define-alias errorMessages <com.google.appinventor.components.runtime.util.ErrorMessages>)
(define ERROR_DIVISION_BY_ZERO errorMessages:ERROR_DIVISION_BY_ZERO)
;;; This codes around the complexity (or Kawa bug?) that
;;; inexact infinity is different from exact infinity. For example
;;; (floor (/ 1 0)) gives an error, while floor (/ 1 0.0) is +inf.
;;; Also (/ 0 0) gives an error, while (/ 0 0.0) gives Nan.
;;; We could make division by zero always signal a runtime error,
;;; but it seems better to minimize runtime errors, even though that
;;; makes Nan and =/- infinity visible to users. Maybe we should avoid Nan
;;; by making (/ 0 0) and (/ 0 0.0) be runtime errors, even though we keep
;;; infinity.
(define (yail-divide n d)
(if (= d 0)
(/ n 0.0)
;; force inexactness so that integer division does not produce
;; rationals, which is simpler for App Inventor users.
;; In most cases, rationals are converted to decimals anyway at higher levels
;; of the system, so that the forcing to inexact would be unnecessary. But
;; there are places where the conversion doesn't happen. For example, if we
;; inserted the result of dividing 2 by 3 into a ListView or a picker,
;; which would appear as the string "2/3" if the division produced a rational.
(exact->inexact (/ n d))))
;; For divide by 0 exceptions, we show a notification to the user, but still return
;; a result. The app developer can
;; change the error action using the Screen.ErrorOccurred event handler.
(cond ((and (= d 0) (= n 0))
;; Treat 0/0 as a special case, returning 0.
;; We do this because Kawa throws an exception of its own if you divide
;; 0 by 0. Whereas it returns "1/0" or +-Inf.0 if the numerator is non-zero.
(begin (signal-runtime-form-error "Division" ERROR_DIVISION_BY_ZERO n)
;; return 0 in this case. The zero was chosen arbitrarily.
n))
((= d 0)
(begin
;; If numerator is not zero, but we're deviding by 0, we show the warning, and
;; Let Kawa do the dvision and return the result, which will be plus or minus infinity.
;; Note that division by zero does not produce a Kawa exception.
;; We also convert the result to inexact, to code around the complexity (or Kawa bug?) that
;; inexact infinity is different from exact infinity. For example
;; (floor (/ 1 0)) gives an error, while floor (/ 1 0.0) is +inf.
(signal-runtime-form-error "Division" ERROR_DIVISION_BY_ZERO n)
(exact->inexact (/ n d))))
(else
;; Otherise, return the result of the Kawa devision.
;; We force inexactness so that integer division does not produce
;; rationals, which is simpler for App Inventor users.
;; In most cases, rationals are converted to decimals anyway at higher levels
;; of the system, so that the forcing to inexact would be unnecessary. But
;; there are places where the conversion doesn't happen. For example, if we
;; were to insert the result of dividing 2 by 3 into a ListView or a picker,
;; which would appear as the string "2/3" if the division produced a rational.
(exact->inexact (/ n d)))))
;;; Trigonometric functions
(define *pi* 3.14159265)
......
......@@ -809,9 +809,9 @@ public class Form extends Activity
});
}
// This is like dispatchErrorOccurred, except that it defaults to showing
// This is like dispatchErrorOccurredEvent, except that it defaults to showing
// a message dialog rather than an alert. The app writer can override either of these behaviors,
// but using the event dialog version frees the app writer of the need to explicitly override
// but using the event dialog version frees the app writer from the need to explicitly override
// the alert behavior in the case
// where a message dialog is what's generally needed.
public void dispatchErrorOccurredEventDialog(final Component component, final String functionName,
......@@ -830,7 +830,18 @@ public class Form extends Activity
});
}
// This runtimeFormErrorOccurred can be called from runtime.scm in
// the case of a runtime error. The event is always signaled in the
// active form. It triggers the normal Form error system which fires
// the ErrorOccurred event. This can be handled by the App Inventor
// programmer. If it isn't a Notifier (toast) is displayed showing
// the error.
public void runtimeFormErrorOccurredEvent(String functionName, int errorNumber, String message) {
Log.d("FORM_RUNTIME_ERROR", "functionName is " + functionName);
Log.d("FORM_RUNTIME_ERROR", "errorNumber is " + errorNumber);
Log.d("FORM_RUNTIME_ERROR", "message is " + message);
dispatchErrorOccurredEvent((Component) activeForm, functionName, errorNumber, message);
}
/**
* Scrollable property getter method.
......
......@@ -200,7 +200,10 @@ public final class ErrorMessages {
public static final int ERROR_EV3_ILLEGAL_MOTOR_PORT = 3104;
public static final int ERROR_EV3_ILLEGAL_SENSOR_PORT = 3105;
// Start the next group of errors at 3200
// Form errors that are signalled in runtime.scm
public static final int ERROR_DIVISION_BY_ZERO = 3200;
// Start the next group of errors at 3300
// Mapping of error numbers to error message format strings.
private static final Map<Integer, String> errorMessages;
......@@ -496,6 +499,11 @@ public final class ErrorMessages {
// Image errors
errorMessages.put(ERROR_IMAGE_CANNOT_ROTATE,
"The version of Android on this device does not support image rotation.");
// Form errors signaled in runtime.scm. The error number used in runtime.scm to call
// signal-runtime-form-error must match the error number used here.
errorMessages.put(ERROR_DIVISION_BY_ZERO,
"Trying to divide %s by 0. The result might not be valid.");
}
private ErrorMessages() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment