Refactor value
This commit is contained in:
		
							parent
							
								
									20e324f4c2
								
							
						
					
					
						commit
						aba76688be
					
				
					 4 changed files with 129 additions and 64 deletions
				
			
		
							
								
								
									
										126
									
								
								ast.ml
									
										
									
									
									
								
							
							
						
						
									
										126
									
								
								ast.ml
									
										
									
									
									
								
							| 
						 | 
					@ -1,58 +1,116 @@
 | 
				
			||||||
type typ =
 | 
					module Type = struct
 | 
				
			||||||
  | Int of int
 | 
					  type t =
 | 
				
			||||||
  | Float of float
 | 
					    | Int
 | 
				
			||||||
  | Unit
 | 
					    | Float
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let typ_to_string = function
 | 
					  let to_string = function
 | 
				
			||||||
  | Int n -> Printf.sprintf "%d" n
 | 
					    | Int -> "int"
 | 
				
			||||||
  | Float n -> Printf.sprintf "%f" n
 | 
					    | Float -> "float"
 | 
				
			||||||
  | Unit -> "()"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type binop =
 | 
					  let merge a b =
 | 
				
			||||||
  | Add | Sub | Mul | Div (* arithmetics *)
 | 
					    match a, b with
 | 
				
			||||||
  | Mod (* modular operation *)
 | 
					    | Int, Float -> Float
 | 
				
			||||||
  | Exp (* exponentation *)
 | 
					    | Float, Int -> Float
 | 
				
			||||||
 | 
					    | a, b when a = b -> a
 | 
				
			||||||
 | 
					    | _ -> failwith "Type.merge"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let binop_to_string = function
 | 
					end
 | 
				
			||||||
  | Add -> "+"
 | 
					
 | 
				
			||||||
  | Sub -> "-"
 | 
					exception Invalid_type of Type.t
 | 
				
			||||||
  | Mul -> "*"
 | 
					
 | 
				
			||||||
  | Div -> "/"
 | 
					module Value = struct
 | 
				
			||||||
  | Mod -> "%"
 | 
					  type t =
 | 
				
			||||||
  | Exp -> "^"
 | 
					    | Int of int
 | 
				
			||||||
 | 
					    | Float of float
 | 
				
			||||||
 | 
					    | Nop (* return of system operations *)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let to_string = function
 | 
				
			||||||
 | 
					    | Int n -> Printf.sprintf "%d" n
 | 
				
			||||||
 | 
					    | Float n -> Printf.sprintf "%f" n
 | 
				
			||||||
 | 
					    | Nop -> "nop"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let typeof = function
 | 
				
			||||||
 | 
					    | Int _ -> Type.Int
 | 
				
			||||||
 | 
					    | Float _ -> Type.Float
 | 
				
			||||||
 | 
					    | Nop -> failwith "Value.typeof"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let promote = function
 | 
				
			||||||
 | 
					    | Int n -> Float (float n)
 | 
				
			||||||
 | 
					    | Float n -> Float n
 | 
				
			||||||
 | 
					    | _ -> failwith "Value.promote"
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* binary operator *)
 | 
				
			||||||
 | 
					module Binop = struct
 | 
				
			||||||
 | 
					  type t =
 | 
				
			||||||
 | 
					    | Add | Sub | Mul | Div (* arithmetics *)
 | 
				
			||||||
 | 
					    | Mod (* modular operation *)
 | 
				
			||||||
 | 
					    | Exp (* exponentation *)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let to_string = function
 | 
				
			||||||
 | 
					    | Add -> "+"
 | 
				
			||||||
 | 
					    | Sub -> "-"
 | 
				
			||||||
 | 
					    | Mul -> "*"
 | 
				
			||||||
 | 
					    | Div -> "/"
 | 
				
			||||||
 | 
					    | Mod -> "%"
 | 
				
			||||||
 | 
					    | Exp -> "^"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let vi f a b =
 | 
				
			||||||
 | 
					    let open Value in
 | 
				
			||||||
 | 
					    match a, b with
 | 
				
			||||||
 | 
					    | Int a, Int b -> Int (f a b)
 | 
				
			||||||
 | 
					    | _ -> raise @@ Invalid_type Int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let vf f a b =
 | 
				
			||||||
 | 
					    let open Value in
 | 
				
			||||||
 | 
					    match a, b with
 | 
				
			||||||
 | 
					    | Float a, Float b -> Float (f a b)
 | 
				
			||||||
 | 
					    | _ -> raise @@ Invalid_type Float
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let operators =
 | 
				
			||||||
 | 
					    let open Type in
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					      Add, [Int, vi Int.add; Float, vf Float.add];
 | 
				
			||||||
 | 
					      Sub, [Int, vi Int.sub; Float, vf Float.sub];
 | 
				
			||||||
 | 
					      Mul, [Int, vi Int.mul; Float, vf Float.mul];
 | 
				
			||||||
 | 
					      Div, [Int, vi Int.div; Float, vf Float.div];
 | 
				
			||||||
 | 
					      Mod, [Int, vi Int.rem; Float, vf Float.rem];
 | 
				
			||||||
 | 
					      Exp, [Float, vf Float.pow];
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    |> List.to_seq
 | 
				
			||||||
 | 
					    |> Hashtbl.of_seq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let get op typ =
 | 
				
			||||||
 | 
					    Hashtbl.find operators op
 | 
				
			||||||
 | 
					    |> List.assoc_opt typ
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type t =
 | 
					type t =
 | 
				
			||||||
  | Value of typ
 | 
					  | Value of Value.t
 | 
				
			||||||
  | Binop of t * binop * t
 | 
					  | Binop of t * Binop.t * t
 | 
				
			||||||
  | Set_binop_pre of binop * t
 | 
					  | Set_binop_pre of Binop.t * t
 | 
				
			||||||
  | Get_binop_pre of binop
 | 
					  | Get_binop_pre of Binop.t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let value v = Value v
 | 
					let value v = Value v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let binop left op right =
 | 
					let binop left op right =
 | 
				
			||||||
  Binop (left, op, right)
 | 
					  Binop (left, op, right)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let set_binop_pre op pre =
 | 
					 | 
				
			||||||
  Set_binop_pre (op, pre)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(* print ast LISP style. *)
 | 
					(* print ast LISP style. *)
 | 
				
			||||||
let print ast =
 | 
					let print ast =
 | 
				
			||||||
  let pr = Printf.printf in
 | 
					  let pr = Printf.printf in
 | 
				
			||||||
  let pv v = pr "%s" @@ typ_to_string v in
 | 
					  let pv v = pr "%s" @@ Value.to_string v in
 | 
				
			||||||
  let rec aux = function
 | 
					  let rec aux = function
 | 
				
			||||||
    | Value n -> pv n
 | 
					    | Value n -> pv n
 | 
				
			||||||
    | Binop (left, op, right) -> begin
 | 
					    | Binop (left, op, right) -> begin
 | 
				
			||||||
        pr "(%s " @@ binop_to_string op;
 | 
					        let op = Binop.to_string op in
 | 
				
			||||||
        aux left;
 | 
					        pr "(%s " op; aux left; pr " "; aux right; pr ")";
 | 
				
			||||||
        pr " ";
 | 
					 | 
				
			||||||
        aux right;
 | 
					 | 
				
			||||||
        pr ")";
 | 
					 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    | Set_binop_pre (op, pre) ->
 | 
					    | Set_binop_pre (op, pre) ->
 | 
				
			||||||
      pr "(set_pre %s " (binop_to_string op);
 | 
					      pr "(set_pre %s " (Binop.to_string op);
 | 
				
			||||||
      aux pre;
 | 
					      aux pre;
 | 
				
			||||||
      pr ")"
 | 
					      pr ")"
 | 
				
			||||||
    | Get_binop_pre op ->
 | 
					    | Get_binop_pre op ->
 | 
				
			||||||
      pr "(get_pre %s)" (binop_to_string op)
 | 
					      pr "(get_pre %s)" (Binop.to_string op)
 | 
				
			||||||
  in
 | 
					  in
 | 
				
			||||||
  aux ast; pr "\n"
 | 
					  aux ast; pr "\n"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										47
									
								
								eval.ml
									
										
									
									
									
								
							
							
						
						
									
										47
									
								
								eval.ml
									
										
									
									
									
								
							| 
						 | 
					@ -1,34 +1,37 @@
 | 
				
			||||||
open Ast
 | 
					open Ast
 | 
				
			||||||
 | 
					open Ast.Value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exception Invalid_type
 | 
					exception No_operation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let arith intf floatf a b =
 | 
					let rec binop op l r =
 | 
				
			||||||
  match a, b with
 | 
					  let tl = typeof l and tr = typeof r in
 | 
				
			||||||
  | Int a, Int b -> begin
 | 
					  let ty = Type.merge tl tr in
 | 
				
			||||||
      try Int (intf a b)
 | 
					  let rec promote_until t x =
 | 
				
			||||||
      with Exit -> Float (floatf (float a) (float b))
 | 
					    if typeof x = t
 | 
				
			||||||
 | 
					    then x
 | 
				
			||||||
 | 
					    else promote_until t (promote x)
 | 
				
			||||||
 | 
					  in
 | 
				
			||||||
 | 
					  let l = promote_until ty l
 | 
				
			||||||
 | 
					  and r = promote_until ty r in
 | 
				
			||||||
 | 
					  match Binop.get op ty with
 | 
				
			||||||
 | 
					  | None -> begin
 | 
				
			||||||
 | 
					      try binop op (promote l) (promote r)
 | 
				
			||||||
 | 
					      with _ -> raise No_operation
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  | Float a, Int b -> Float (floatf a (float b))
 | 
					  | Some f -> f l r
 | 
				
			||||||
  | 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 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
 | 
					let rec eval = function
 | 
				
			||||||
  | Value v -> v
 | 
					  | Value v -> v
 | 
				
			||||||
  | Binop (l, op, r) ->
 | 
					  | Binop (l, op, r) ->
 | 
				
			||||||
    let f = binop_to_func op in
 | 
					    let l = eval l and r = eval r in
 | 
				
			||||||
    f (eval l) (eval r)
 | 
					    binop op l r
 | 
				
			||||||
  | Set_binop_pre (op, l) ->
 | 
					  | Set_binop_pre (op, l) ->
 | 
				
			||||||
    let l = match eval l with Int n -> n | _ -> raise Invalid_type in
 | 
					    let l =
 | 
				
			||||||
 | 
					      match eval l with
 | 
				
			||||||
 | 
					      | Int n -> n
 | 
				
			||||||
 | 
					      | v -> raise @@ Invalid_type (typeof v)
 | 
				
			||||||
 | 
					    in
 | 
				
			||||||
    Hashtbl.replace Parser.precedence op l;
 | 
					    Hashtbl.replace Parser.precedence op l;
 | 
				
			||||||
    Unit
 | 
					    Nop
 | 
				
			||||||
  | Get_binop_pre op ->
 | 
					  | Get_binop_pre op ->
 | 
				
			||||||
    Int (Hashtbl.find Parser.precedence op)
 | 
					    Int (Hashtbl.find Parser.precedence op)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								main.ml
									
										
									
									
									
								
							
							
						
						
									
										17
									
								
								main.ml
									
										
									
									
									
								
							| 
						 | 
					@ -9,7 +9,7 @@ let error_to_string e =
 | 
				
			||||||
  | Lex.Token_not_found -> sprintf "invalid token"
 | 
					  | Lex.Token_not_found -> sprintf "invalid token"
 | 
				
			||||||
  | Parser.Expected t -> sprintf "expected %s" t
 | 
					  | Parser.Expected t -> sprintf "expected %s" t
 | 
				
			||||||
  | Parser.Unexpected_token t -> sprintf "unexpected token \"%s\"" t
 | 
					  | Parser.Unexpected_token t -> sprintf "unexpected token \"%s\"" t
 | 
				
			||||||
  | Eval.Invalid_type -> "invalid type"
 | 
					  | Ast.Invalid_type t -> sprintf "invalid type %s" (Ast.Type.to_string t)
 | 
				
			||||||
  | Failure f -> sprintf "error on %s" f
 | 
					  | Failure f -> sprintf "error on %s" f
 | 
				
			||||||
  | Division_by_zero -> "cannot divide by zero"
 | 
					  | Division_by_zero -> "cannot divide by zero"
 | 
				
			||||||
  | _ -> raise e
 | 
					  | _ -> raise e
 | 
				
			||||||
| 
						 | 
					@ -22,12 +22,15 @@ let rep () : unit =
 | 
				
			||||||
  printf "> ";
 | 
					  printf "> ";
 | 
				
			||||||
  let line = read_line () in
 | 
					  let line = read_line () in
 | 
				
			||||||
  if line = "quit" then raise Exit;
 | 
					  if line = "quit" then raise Exit;
 | 
				
			||||||
  line
 | 
					  let ans =
 | 
				
			||||||
  |> Lex.tokenize
 | 
					    line
 | 
				
			||||||
  |> Parser.parse
 | 
					    |> Lex.tokenize
 | 
				
			||||||
  |> Eval.eval
 | 
					    |> Parser.parse
 | 
				
			||||||
  |> Ast.typ_to_string
 | 
					    |> Eval.eval
 | 
				
			||||||
  |> printf "%s\n"
 | 
					  in
 | 
				
			||||||
 | 
					  match ans with
 | 
				
			||||||
 | 
					  | Nop -> ()
 | 
				
			||||||
 | 
					  | _ -> printf "%s\n" @@ Ast.Value.to_string ans
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let init_repl () =
 | 
					let init_repl () =
 | 
				
			||||||
  let sigintf _ = raise Reset_line in
 | 
					  let sigintf _ = raise Reset_line in
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
open Ast
 | 
					open Ast
 | 
				
			||||||
 | 
					open Ast.Binop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module S = Set.Make(String)
 | 
					module S = Set.Make(String)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +7,7 @@ exception Expected of string
 | 
				
			||||||
exception Unexpected_token of string
 | 
					exception Unexpected_token of string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let expected t =
 | 
					let expected t =
 | 
				
			||||||
  raise (Expected t)
 | 
					  raise @@ Expected t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let unexpected_token t =
 | 
					let unexpected_token t =
 | 
				
			||||||
  raise @@ Unexpected_token (Token.to_string t)
 | 
					  raise @@ Unexpected_token (Token.to_string t)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue