fix(compiler): refactor and fix the duration division operator evaluation

This commit is contained in:
EmileRolley 2021-05-31 10:42:20 +02:00
parent 74bf3cf93d
commit be90d61dc1
4 changed files with 44 additions and 16 deletions

View File

@ -38,6 +38,8 @@ let log_indent = ref 0
let rec evaluate_operator (ctx : Ast.decl_ctx) (op : A.operator Pos.marked)
(args : A.expr Pos.marked list) : A.expr Pos.marked =
(* Try to apply [div] and if a [Division_by_zero] exceptions is catched, use [op] to raise
multispanned errors. *)
let apply_div_or_raise_err (div : unit -> A.expr) (op : A.operator Pos.marked) : A.expr =
try div ()
with Division_by_zero ->
@ -47,6 +49,8 @@ let rec evaluate_operator (ctx : Ast.decl_ctx) (op : A.operator Pos.marked)
(Some "The null denominator:", Pos.get_position (List.nth args 1));
]
in
(* Try to apply [cmp] and if a [UncomparableDurations] exceptions is catched, use [args] to raise
multispanned errors. *)
let apply_cmp_or_raise_err (cmp : unit -> A.expr) (args : (A.expr * Pos.t) list) : A.expr =
try cmp ()
with Runtime.UncomparableDurations ->
@ -91,21 +95,18 @@ let rec evaluate_operator (ctx : Ast.decl_ctx) (op : A.operator Pos.marked)
A.ELit (LDuration Runtime.(i1 -@ i2))
| A.Binop (A.Add KDate), [ ELit (LDate i1); ELit (LDuration i2) ] ->
A.ELit (LDate Runtime.(i1 +@ i2))
| A.Binop (A.Div KDuration), [ ELit (LDuration i1); ELit (LDuration i2) ] -> (
try A.ELit (LRat Runtime.(i1 /^ i2)) with
| Division_by_zero ->
Errors.raise_multispanned_error "division by zero at runtime"
[
(Some "The division operator:", Pos.get_position op);
(Some "The null denominator:", Pos.get_position (List.nth args 1));
]
| Runtime.IndivisableDurations ->
Errors.raise_multispanned_error
"Cannot divide durations that cannot be converted to a precise number of days"
[
(None, Pos.get_position (List.nth args 0));
(None, Pos.get_position (List.nth args 1));
])
| A.Binop (A.Div KDuration), [ ELit (LDuration i1); ELit (LDuration i2) ] ->
apply_div_or_raise_err
(fun _ ->
try A.ELit (LRat Runtime.(i1 /^ i2))
with Runtime.IndivisableDurations ->
Errors.raise_multispanned_error
"Cannot divide durations that cannot be converted to a precise number of days"
[
(None, Pos.get_position (List.nth args 0));
(None, Pos.get_position (List.nth args 1));
])
op
| A.Binop (A.Lt KInt), [ ELit (LInt i1); ELit (LInt i2) ] -> A.ELit (LBool Runtime.(i1 <! i2))
| A.Binop (A.Lte KInt), [ ELit (LInt i1); ELit (LInt i2) ] -> A.ELit (LBool Runtime.(i1 <=! i2))
| A.Binop (A.Gt KInt), [ ELit (LInt i1); ELit (LInt i2) ] -> A.ELit (LBool Runtime.(i1 >! i2))

View File

@ -267,7 +267,7 @@ let ( /^ ) (d1 : duration) (d2 : duration) : decimal =
try
let nb_day1 = CalendarLib.Date.Period.nb_days d1 in
let nb_day2 = CalendarLib.Date.Period.nb_days d2 in
if 0 = nb_day1 then raise Division_by_zero else Q.(nb_day1 // nb_day2)
if 0 = nb_day2 then raise Division_by_zero else Q.(nb_day1 // nb_day2)
with CalendarLib.Date.Period.Not_computable -> raise IndivisableDurations
let ( <=$ ) (m1 : money) (m2 : money) : bool = Z.compare m1 m2 <= 0

View File

@ -29,3 +29,13 @@ declaration scope Money:
scope Money:
definition i equals $10.0 /$ $0.0
```
### with duration
```catala
declaration scope Duration:
context i content decimal
scope Duration:
definition i equals 10 day /^ 0 day
```

View File

@ -0,0 +1,17 @@
[ERROR] division by zero at runtime
[ERROR]
[ERROR] The division operator:
[ERROR] --> test_arithmetic/bad/division_by_zero.catala_en
[ERROR] |
[ERROR] 40 | definition i equals 10 day /^ 0 day
[ERROR] | ^^
[ERROR] + `Division_by_zero` exception management
[ERROR] +-+ with duration
[ERROR]
[ERROR] The null denominator:
[ERROR] --> test_arithmetic/bad/division_by_zero.catala_en
[ERROR] |
[ERROR] 40 | definition i equals 10 day /^ 0 day
[ERROR] | ^^^^^
[ERROR] + `Division_by_zero` exception management
[ERROR] +-+ with duration