From 4efb65c5cd823c35bf93cf6ddcb69fa61ba6e0cf Mon Sep 17 00:00:00 2001
From: Hyeonung Baek <wiserlix@gmail.com>
Date: Tue, 18 Jan 2022 15:33:56 +0900
Subject: [PATCH] Add float

---
 ast.ml    |  2 ++
 eval.ml   | 22 ++++++++++++++--------
 lex.ml    | 12 +++++++++---
 parser.ml |  1 +
 token.ml  |  4 +++-
 5 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/ast.ml b/ast.ml
index 3ce2e25..2af8f17 100644
--- a/ast.ml
+++ b/ast.ml
@@ -1,9 +1,11 @@
 type typ =
   | Int of int
+  | Float of float
   | Unit
 
 let typ_to_string = function
   | Int n -> Printf.sprintf "%d" n
+  | Float n -> Printf.sprintf "%f" n
   | Unit -> "()"
 
 type binop =
diff --git a/eval.ml b/eval.ml
index 5cb692c..baf2b2f 100644
--- a/eval.ml
+++ b/eval.ml
@@ -2,18 +2,24 @@ open Ast
 
 exception Invalid_type
 
-let arith intf a b =
+let arith intf floatf a b =
   match a, b with
-  | Int a, Int b -> Int (intf a b)
+  | Int a, Int b -> begin
+      try Int (intf a b)
+      with Exit -> Float (floatf (float a) (float b))
+    end
+  | Float a, Int b -> Float (floatf a (float b))
+  | Int a, Float b -> Float (floatf (float a) b)
+  | Float a, Float b -> Float (floatf a b)
   | _ -> raise Invalid_type
 
 let binop_to_func = function
-  | Add -> arith Int.add
-  | Sub -> arith Int.sub
-  | Mul -> arith Int.mul
-  | Div -> arith Int.div
-  | Mod -> arith Int.rem
-  | _ -> assert false
+  | Add -> arith Int.add Float.add
+  | Sub -> arith Int.sub Float.sub
+  | Mul -> arith Int.mul Float.mul
+  | Div -> arith Int.div Float.div
+  | Mod -> arith Int.rem Float.rem
+  | Exp -> arith (fun _ _ -> raise Exit) Float.pow
 
 let rec eval = function
   | Value v -> v
diff --git a/lex.ml b/lex.ml
index 9b54735..4afdf46 100644
--- a/lex.ml
+++ b/lex.ml
@@ -10,6 +10,7 @@ let is_digit c =
 
 let is_num = function
   | 'x' -> true
+  | '.' -> true
   | c -> is_digit c
 
 let is_whitespace = function
@@ -46,9 +47,14 @@ let tokenize (str : string) : tokens =
       if is_whitespace x then
         aux s () (* skip whitespace *)
       else if is_digit x then
-        let n, s = partition_while is_num seq in
-        let n = int_of_string @@ String.of_seq n in
-        Seq.Cons (Int n, aux s)
+        let n, s = partition_while is_num s in
+        let n = String.of_seq @@ Seq.cons x n in
+        let n =
+          if String.contains n '.' (* float *)
+          then Float (float_of_string n)
+          else Int (int_of_string n)
+        in
+        Seq.Cons (n, aux s)
       else if is_ident_start x then
         let id, s = partition_while is_ident seq in
         let id = String.of_seq id in
diff --git a/parser.ml b/parser.ml
index 1714b9a..a68b223 100644
--- a/parser.ml
+++ b/parser.ml
@@ -80,6 +80,7 @@ let parse ts =
     | Seq.Nil -> assert false
     | Seq.Cons (x, seq) -> begin match x with
         | Token.Int n -> Value (Int n), seq
+        | Token.Float n -> Value (Float n), seq
         | LParen -> expr seq
         | _ -> unexpected_token x
       end
diff --git a/token.ml b/token.ml
index ac5394b..9a3e14c 100644
--- a/token.ml
+++ b/token.ml
@@ -1,5 +1,6 @@
 type t =
   | Int of int
+  | Float of float
   | Ident of string
   | Plus
   | Minus
@@ -37,7 +38,8 @@ let find_token seq =
     (fun (s, t) -> expect_token s t seq)
 
 let to_string = function
-  | Int n -> string_of_int n
+  | Int n -> Printf.sprintf "[int: %d]" n
+  | Float n -> Printf.sprintf "[float: %f]" n
   | Ident s -> s
   | t ->
     begin match List.find_opt (fun (_, tok) -> t = tok) !tokens with