Replace GADTs to normal datatypes
This commit is contained in:
		
							parent
							
								
									472cf4bebe
								
							
						
					
					
						commit
						4e0d4dd9ac
					
				
					 5 changed files with 45 additions and 36 deletions
				
			
		
							
								
								
									
										27
									
								
								ast.ml
									
										
									
									
									
								
							
							
						
						
									
										27
									
								
								ast.ml
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,27 +1,24 @@
 | 
			
		|||
type _ typ =
 | 
			
		||||
  | Int : int -> int typ
 | 
			
		||||
  | Unit : unit typ
 | 
			
		||||
type typ =
 | 
			
		||||
  | Int of int
 | 
			
		||||
  | Unit
 | 
			
		||||
 | 
			
		||||
let typ_to_string : type a. a typ -> string = function
 | 
			
		||||
let typ_to_string = function
 | 
			
		||||
  | Int n -> Printf.sprintf "%d" n
 | 
			
		||||
  | Unit -> "()"
 | 
			
		||||
 | 
			
		||||
type (_, _) binop =
 | 
			
		||||
  | Add : (int, int) binop
 | 
			
		||||
  | Sub : (int, int) binop
 | 
			
		||||
  | Mul : (int, int) binop
 | 
			
		||||
  | Div : (int, int) binop
 | 
			
		||||
type binop =
 | 
			
		||||
  | Add | Sub | Mul | Div
 | 
			
		||||
 | 
			
		||||
let binop_to_string : type a b. (a, b) binop -> string = function
 | 
			
		||||
let binop_to_string = function
 | 
			
		||||
  | Add -> "+"
 | 
			
		||||
  | Sub -> "-"
 | 
			
		||||
  | Mul -> "*"
 | 
			
		||||
  | Div -> "/"
 | 
			
		||||
 | 
			
		||||
type _ t =
 | 
			
		||||
  | Value : 'a typ -> 'a t
 | 
			
		||||
  | Binop : 'a t * ('a, 'b) binop * 'a t -> 'b t
 | 
			
		||||
  | Set_binop_pre : ('a, 'b) binop * int t -> unit t
 | 
			
		||||
type t =
 | 
			
		||||
  | Value of typ
 | 
			
		||||
  | Binop of t * binop * t
 | 
			
		||||
  | Set_binop_pre of binop * t
 | 
			
		||||
 | 
			
		||||
let value v = Value v
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +32,7 @@ let set_binop_pre op pre =
 | 
			
		|||
let print ast =
 | 
			
		||||
  let pr = Printf.printf in
 | 
			
		||||
  let pv v = pr "%s" @@ typ_to_string v in
 | 
			
		||||
  let rec aux : type a. a t -> unit = function
 | 
			
		||||
  let rec aux = function
 | 
			
		||||
    | Value n -> pv n
 | 
			
		||||
    | Binop (left, op, right) -> begin
 | 
			
		||||
        pr "(%s " @@ binop_to_string op;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										26
									
								
								eval.ml
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								eval.ml
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,18 +1,22 @@
 | 
			
		|||
open Ast
 | 
			
		||||
 | 
			
		||||
let binop_to_func : type a b. (a, b) Ast.binop -> (a -> a -> b) = function
 | 
			
		||||
  | Add -> Int.add
 | 
			
		||||
  | Sub -> Int.sub
 | 
			
		||||
  | Mul -> Int.mul
 | 
			
		||||
  | Div -> Int.div
 | 
			
		||||
  | Eq -> (=)
 | 
			
		||||
let intop f a b =
 | 
			
		||||
  match a, b with
 | 
			
		||||
  | Int a, Int b -> Int (f a b)
 | 
			
		||||
  | _ -> failwith "typecheck failed"
 | 
			
		||||
 | 
			
		||||
let rec eval : type a. a Ast.t -> a = function
 | 
			
		||||
  | Value (Int t) -> t
 | 
			
		||||
  | Value Unit -> ()
 | 
			
		||||
let binop_to_func = function
 | 
			
		||||
  | Add -> intop Int.add
 | 
			
		||||
  | Sub -> intop Int.sub
 | 
			
		||||
  | Mul -> intop Int.mul
 | 
			
		||||
  | Div -> intop Int.div
 | 
			
		||||
 | 
			
		||||
let rec eval = function
 | 
			
		||||
  | Value v -> v
 | 
			
		||||
  | Binop (l, op, r) ->
 | 
			
		||||
    let f = binop_to_func op in
 | 
			
		||||
    f (eval l) (eval r)
 | 
			
		||||
  | Set_binop_pre (op, l) ->
 | 
			
		||||
    Hashtbl.replace Parser.precedence
 | 
			
		||||
      (Ast.binop_to_string op) (eval l)
 | 
			
		||||
    let l = match eval l with Int n -> n | _ -> failwith "not int" in 
 | 
			
		||||
    Hashtbl.replace Parser.precedence (Ast.binop_to_string op) l;
 | 
			
		||||
    Unit
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								lex.ml
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								lex.ml
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -15,7 +15,7 @@ let is_whitespace = function
 | 
			
		|||
  | _ -> false
 | 
			
		||||
 | 
			
		||||
let is_alpha c =
 | 
			
		||||
  'A' <= c && c <= 'Z' && 'a' <= c && c <= 'z'
 | 
			
		||||
  ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')
 | 
			
		||||
 | 
			
		||||
let is_ident_start =
 | 
			
		||||
  either is_alpha ((=) '_')
 | 
			
		||||
| 
						 | 
				
			
			@ -48,9 +48,11 @@ let tokenize (str : string) : tokens =
 | 
			
		|||
        let n = String.of_seq @@ Seq.cons x n in
 | 
			
		||||
        Seq.cons (of_string n) (aux s)
 | 
			
		||||
      else if is_ident_start x then
 | 
			
		||||
        let id, s = partition_while is_ident s in
 | 
			
		||||
        let id = String.of_seq @@ Seq.cons x id in
 | 
			
		||||
        Seq.cons (Ident id) (aux s)
 | 
			
		||||
        begin
 | 
			
		||||
          let id, s = partition_while is_ident s in
 | 
			
		||||
          let id = String.of_seq @@ Seq.cons x id in
 | 
			
		||||
          Seq.cons (Ident id) (aux s)
 | 
			
		||||
        end
 | 
			
		||||
      else
 | 
			
		||||
        Seq.cons (of_char x) (aux s)
 | 
			
		||||
  in
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								main.ml
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								main.ml
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -7,7 +7,8 @@ let rec repl () : unit =
 | 
			
		|||
    |> Lex.tokenize
 | 
			
		||||
    |> Parser.parse
 | 
			
		||||
    |> Eval.eval
 | 
			
		||||
    |> Printf.printf "%d\n";
 | 
			
		||||
    |> Ast.typ_to_string
 | 
			
		||||
    |> Printf.printf "%s\n";
 | 
			
		||||
    repl ()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										15
									
								
								parser.ml
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								parser.ml
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -9,6 +9,10 @@ let expected t =
 | 
			
		|||
let unexpected_token t =
 | 
			
		||||
  raise @@ Unexpected_token (Token.to_string t)
 | 
			
		||||
 | 
			
		||||
(* precedence table.
 | 
			
		||||
 * my first thought was using some sort of partially-ordered graph for
 | 
			
		||||
 * precedency, but infering precedence relation from the graph is hard
 | 
			
		||||
 * and the graph can be made to have loops, I just used plain table. *)
 | 
			
		||||
let precedence = [
 | 
			
		||||
  "+", 10;
 | 
			
		||||
  "-", 10;
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +23,9 @@ let precedence = [
 | 
			
		|||
let precedence_of op =
 | 
			
		||||
  Hashtbl.find precedence (Ast.binop_to_string op)
 | 
			
		||||
 | 
			
		||||
let is_left_to_right = function
 | 
			
		||||
  | Add | Sub | Mul | Div -> true
 | 
			
		||||
 | 
			
		||||
let token_to_op = function
 | 
			
		||||
  | Token.Plus -> Add
 | 
			
		||||
  | Minus -> Sub
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +33,7 @@ let token_to_op = function
 | 
			
		|||
  | Slash -> Div
 | 
			
		||||
  | _ -> failwith "Parser.token_to_op"
 | 
			
		||||
 | 
			
		||||
let parse : type a. Token.t Seq.t -> a Ast.t = fun ts ->
 | 
			
		||||
let parse ts =
 | 
			
		||||
  (* value := int | ( expr ) *)
 | 
			
		||||
  let rec value seq =
 | 
			
		||||
    match seq () with
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +82,7 @@ let parse : type a. Token.t Seq.t -> a Ast.t = fun ts ->
 | 
			
		|||
 | 
			
		||||
  and expr seq =
 | 
			
		||||
    match seq () with
 | 
			
		||||
    | Seq.Nil -> Value Unit (* nop *)
 | 
			
		||||
    | Seq.Nil -> Value Unit, Seq.empty (* nop *)
 | 
			
		||||
    | Seq.Cons (x, s) -> begin match x with
 | 
			
		||||
        | Ident "set" -> set_conf s
 | 
			
		||||
        | _ ->
 | 
			
		||||
| 
						 | 
				
			
			@ -83,8 +90,6 @@ let parse : type a. Token.t Seq.t -> a Ast.t = fun ts ->
 | 
			
		|||
          binop ~-1 left seq
 | 
			
		||||
      end
 | 
			
		||||
  in
 | 
			
		||||
  let ast, _ = expr ts in
 | 
			
		||||
  (*
 | 
			
		||||
  let ast, rest = expr ts in
 | 
			
		||||
  if rest () <> Seq.Nil then failwith "Parser.parse";
 | 
			
		||||
     *)
 | 
			
		||||
  ast
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue