Fix decimal parsing

This commit is contained in:
Denis Merigoux 2022-04-22 14:26:28 +02:00
parent b20b2f97be
commit 1c86c8298b
No known key found for this signature in database
GPG Key ID: EE99DCFA365C3EE3
7 changed files with 37 additions and 46 deletions

View File

@ -328,8 +328,8 @@ type literal_date = {
}]
type literal_number =
| Int of (Runtime.integer[@opaque])
| Dec of (Runtime.integer[@opaque]) * (Runtime.integer[@opaque])
| Int of (string[@opaque])
| Dec of (string[@opaque]) * (string[@opaque])
[@@deriving
visitors { variety = "map"; name = "literal_number_map"; nude = true },
visitors { variety = "iter"; name = "literal_number_iter"; nude = true }]
@ -340,8 +340,8 @@ type literal_unit = Percent | Year | Month | Day
visitors { variety = "iter"; name = "literal_unit_iter"; nude = true }]
type money_amount = {
money_amount_units : (Runtime.integer[@opaque]);
money_amount_cents : (Runtime.integer[@opaque]);
money_amount_units : (string[@opaque]);
money_amount_cents : (string[@opaque]);
}
[@@deriving
visitors { variety = "map"; name = "money_amount_map"; nude = true },

View File

@ -181,65 +181,41 @@ let rec translate_expr
| Literal l ->
let untyped_term =
match l with
| LNumber ((Int i, _), None) -> Desugared.Ast.ELit (Dcalc.Ast.LInt i)
| LNumber ((Int i, _), None) ->
Desugared.Ast.ELit (Dcalc.Ast.LInt (Runtime.integer_of_string i))
| LNumber ((Int i, _), Some (Percent, _)) ->
Desugared.Ast.ELit
(Dcalc.Ast.LRat
Runtime.(decimal_of_integer i /& decimal_of_string "100"))
Runtime.(decimal_of_string i /& decimal_of_string "100"))
| LNumber ((Dec (i, f), _), None) ->
let digits_f =
try
int_of_float
(ceil
(float_of_int (Runtime.integer_log2 f)
*. log 2.0 /. log 10.0))
with Invalid_argument _ -> 0
in
Desugared.Ast.ELit
(Dcalc.Ast.LRat
Runtime.(
decimal_of_integer i
+& decimal_of_integer f
/& decimal_of_integer
(integer_exponentiation (integer_of_int 10) digits_f)))
(Dcalc.Ast.LRat Runtime.(decimal_of_string (i ^ "." ^ f)))
| LNumber ((Dec (i, f), _), Some (Percent, _)) ->
let digits_f =
try
int_of_float
(ceil
(float_of_int (Runtime.integer_log2 f)
*. log 2.0 /. log 10.0))
with Invalid_argument _ -> 0
in
Desugared.Ast.ELit
(Dcalc.Ast.LRat
Runtime.(
(decimal_of_integer i
+& decimal_of_integer f
/& decimal_of_integer
(integer_exponentiation (integer_of_int 10) digits_f)
)
/& decimal_of_string "100"))
decimal_of_string (i ^ "." ^ f) /& decimal_of_string "100"))
| LBool b -> Desugared.Ast.ELit (Dcalc.Ast.LBool b)
| LMoneyAmount i ->
Desugared.Ast.ELit
(Dcalc.Ast.LMoney
Runtime.(
money_of_cents_integer
((i.money_amount_units *! integer_of_int 100)
+! i.money_amount_cents)))
(integer_of_string i.money_amount_units
*! integer_of_int 100
+! integer_of_string i.money_amount_cents)))
| LNumber ((Int i, _), Some (Year, _)) ->
Desugared.Ast.ELit
(Dcalc.Ast.LDuration
(Runtime.duration_of_numbers (Runtime.integer_to_int i) 0 0))
(Runtime.duration_of_numbers (int_of_string i) 0 0))
| LNumber ((Int i, _), Some (Month, _)) ->
Desugared.Ast.ELit
(Dcalc.Ast.LDuration
(Runtime.duration_of_numbers 0 (Runtime.integer_to_int i) 0))
(Runtime.duration_of_numbers 0 (int_of_string i) 0))
| LNumber ((Int i, _), Some (Day, _)) ->
Desugared.Ast.ELit
(Dcalc.Ast.LDuration
(Runtime.duration_of_numbers 0 0 (Runtime.integer_to_int i)))
(Runtime.duration_of_numbers 0 0 (int_of_string i)))
| LNumber ((Dec (_, _), _), Some ((Year | Month | Day), _)) ->
Errors.raise_spanned_error pos
"Impossible to specify decimal amounts of days, months or years"

View File

@ -564,7 +564,7 @@ let rec lex_code (lexbuf : lexbuf) : token =
| _ -> ()
done;
L.update_acc lexbuf;
MONEY_AMOUNT (Runtime.integer_of_string (Buffer.contents units), Runtime.integer_of_string (Buffer.contents cents))
MONEY_AMOUNT (Buffer.contents units, Buffer.contents cents)
| Plus digit, MC_DECIMAL_SEPARATOR, Star digit ->
let rex =
Re.(compile @@ whole_string @@ seq [
@ -575,7 +575,7 @@ let rec lex_code (lexbuf : lexbuf) : token =
let dec_parts = R.get_substring (R.exec ~rex (Utf8.lexeme lexbuf)) in
L.update_acc lexbuf;
DECIMAL_LITERAL
(Runtime.integer_of_string (dec_parts 1), Runtime.integer_of_string (dec_parts 2))
(dec_parts 1, dec_parts 2)
| "<=@" ->
L.update_acc lexbuf;
LESSER_EQUAL_DATE
@ -743,7 +743,7 @@ let rec lex_code (lexbuf : lexbuf) : token =
| Plus digit ->
(* Integer literal*)
L.update_acc lexbuf;
INT_LITERAL (Runtime.integer_of_string (Utf8.lexeme lexbuf))
INT_LITERAL (Utf8.lexeme lexbuf)
| _ -> L.raise_lexer_error (Pos.from_lpos prev_pos) prev_lexeme
let rec lex_directive_args (lexbuf : lexbuf) : token =

View File

@ -127,7 +127,7 @@ unit_literal:
| DAY { (Day, Pos.from_lpos $sloc) }
date_int:
| d = INT_LITERAL { (Runtime.integer_to_int d, Pos.from_lpos $sloc) }
| d = INT_LITERAL { (int_of_string d, Pos.from_lpos $sloc) }
literal:
| l = num_literal u = option(unit_literal) {

View File

@ -31,10 +31,10 @@
%token<string> LAW_TEXT
%token<string> CONSTRUCTOR IDENT
%token<string> END_CODE
%token<Runtime.integer> INT_LITERAL
%token<string> INT_LITERAL
%token TRUE FALSE
%token<Runtime.integer * Runtime.integer> DECIMAL_LITERAL
%token<Runtime.integer * Runtime.integer> MONEY_AMOUNT
%token<string * string> DECIMAL_LITERAL
%token<string * string> MONEY_AMOUNT
%token BEGIN_CODE TEXT
%token COLON ALT DATA VERTICAL
%token OF INTEGER COLLECTION

View File

@ -0,0 +1,3 @@
[RESULT] Computation successful! Results:
[RESULT] x = 4.
[RESULT] y = 1.04

View File

@ -0,0 +1,12 @@
## Article
```catala
declaration scope A:
context output x content decimal
context output y content decimal
scope A:
definition x equals 4.0
definition y equals 1.0 +. (x /. 100.0)
assertion y = 1.04
```