This commit is contained in:
Galfour 2019-03-20 14:53:34 +00:00
parent fa4b570950
commit 1918bc00d1
64 changed files with 795 additions and 1003 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@ __pycache__
*.pyc *.pyc
/_build /_build
*/_build
/_opam /_opam
/_docker_build /_docker_build
/docs/_build /docs/_build

View File

@ -0,0 +1,85 @@
module SMap = Ligo_helpers.X_map.String
type name = string
type type_name = string
type 'a name_map = 'a SMap.t
type 'a type_name_map = 'a SMap.t
type program = declaration list
and declaration =
| Type_declaration of named_type_expression
| Constant_declaration of named_expression
(* | Macro_declaration of macro_declaration *)
and annotated_expression = {
expression: expression ;
type_annotation: te option ;
}
and named_expression = {
name: name ;
annotated_expression: ae ;
}
and named_type_expression = {
type_name: type_name ;
type_expression: type_expression ;
}
and te = type_expression
and ae = annotated_expression
and te_map = type_expression type_name_map
and e_map = expression name_map
and type_expression =
| Type_tuple of te list
| Type_sum of te_map
| Type_record of te_map
| Type_variable of type_name
| Type_constant of type_name * te list
and expression =
| Literal of literal
| Constant of name * ae list (* For language constants, like (Cons hd tl) or (plus i j) *)
| Variable of name
| Tuple of ae list
| Constructor of name * ae list (* For user defined constructors *)
| Lambda of {
binder: name ;
input_type: type_expression ;
output_type: type_expression ;
body: block ;
}
and literal =
| Bool of bool
| Number of int
| String of string
| Bytes of bytes
and block = instruction list
and b = block
and instruction =
| Assignment of named_expression
| Matching of matching
| Loop of ae * b
| Skip
| Fail of ae
and matching =
| Match_bool of {
match_true : b ;
match_false : b ;
}
| Match_list of {
match_nil : b ;
match_cons : name * name * b ;
}
| Match_option of {
match_none : b ;
match_some : name * b ;
}
| Match_tuple of (name * b) list

137
src/ligo/ast_typed.ml Normal file
View File

@ -0,0 +1,137 @@
module SMap = Ligo_helpers.X_map.String
let list_of_smap (s:'a SMap.t) : (string * 'a) list =
List.rev @@ SMap.fold (fun k v p -> (k, v) :: p) s []
type name = string
type type_name = string
type 'a name_map = 'a SMap.t
type 'a type_name_map = 'a SMap.t
type program = declaration list
and declaration =
| Constant_declaration of named_expression
(* | Macro_declaration of macro_declaration *)
and annotated_expression = {
expression: expression ;
type_annotation: tv ;
}
and named_expression = {
name: name ;
annotated_expression: ae ;
}
and tv = type_value
and ae = annotated_expression
and tv_map = type_value type_name_map
and e_map = expression name_map
and type_value =
| Type_tuple of tv list
| Type_sum of tv_map
| Type_record of tv_map
| Type_constant of type_name * tv list
and expression =
| Literal of literal
| Constant of name * ae list (* For language constants, like (Cons hd tl) or (plus i j) *)
| Variable of name
| Tuple of ae list
| Constructor of name * ae list (* For user defined constructors *)
| Lambda of {
binder: name ;
input_type: type_value ;
output_type: type_value ;
body: block ;
}
and literal =
| Bool of bool
| Number of int
| String of string
| Bytes of bytes
and block = instruction list
and b = block
and instruction =
| Assignment of named_expression
| Matching of matching
| Loop of ae * b
| Skip
| Fail of ae
and matching =
| Match_bool of {
match_true : b ;
match_false : b ;
}
| Match_list of {
match_nil : b ;
match_cons : name * name * b ;
}
| Match_option of {
match_none : b ;
match_some : name * b ;
}
| Match_tuple of (name * b) list
open Ligo_helpers.Trace
let rec type_value_eq (ab: (type_value * type_value)) : unit result = match ab with
| Type_tuple a, Type_tuple b -> (
let%bind _ =
Assert.assert_true ~msg:"tuples with different sizes"
@@ List.(length a = length b) in
bind_list_iter type_value_eq (List.combine a b)
)
| Type_constant (a, a'), Type_constant (b, b') -> (
let%bind _ =
Assert.assert_true ~msg:"constants with different sizes"
@@ List.(length a' = length b') in
let%bind _ =
Assert.assert_true ~msg:"constants with different names"
@@ (a = b) in
trace (simple_error "constant sub-expression")
@@ bind_list_iter type_value_eq (List.combine a' b')
)
| Type_sum a, Type_sum b -> (
let a' = list_of_smap a in
let b' = list_of_smap b in
let aux ((ka, va), (kb, vb)) =
let%bind _ =
Assert.assert_true ~msg:"different keys in sum types"
@@ (ka = kb) in
type_value_eq (va, vb)
in
trace (simple_error "sum type")
@@ bind_list_iter aux (List.combine a' b')
)
| Type_record a, Type_record b -> (
let a' = list_of_smap a in
let b' = list_of_smap b in
let aux ((ka, va), (kb, vb)) =
let%bind _ =
Assert.assert_true ~msg:"different keys in record types"
@@ (ka = kb) in
type_value_eq (va, vb)
in
trace (simple_error "record type")
@@ bind_list_iter aux (List.combine a' b')
)
| _ -> simple_fail "Different kinds of types"
let merge_annotation (a:type_value option) (b:type_value option) : type_value option result =
match a, b with
| None, None -> ok None
| Some a, None -> ok (Some a)
| None, Some b -> ok (Some b)
| Some a, Some b ->
let%bind _ = type_value_eq (a, b) in
ok (Some a)

View File

@ -1 +1 @@
let () = print_int 42 let () = ()

View File

@ -1,9 +1,3 @@
(ocamllex
(modules lexer))
(menhir
(modules parser))
(library (library
(name ligo) (name ligo)
(public_name ligo) (public_name ligo)
@ -17,5 +11,5 @@
(preprocess (preprocess
(pps ppx_let) (pps ppx_let)
) )
(flags (:standard -w +1..62-4-9-44-40-42@39@33 )) (flags (:standard -w +1..62-4-9-44-40-42-48@39@33 ))
) )

View File

@ -1,76 +0,0 @@
{
open Parser
exception Error of string
exception Unexpected_character of string
}
(* This rule analyzes a single line and turns it into a stream of
tokens. *)
rule token = parse
(*
| "//" ([^ '\n']* ) (['\n' '\r']+)
{ Lexing.new_line lexbuf ; token lexbuf }
*)
| ('\r'? '\n' '\r'?)
{ Lexing.new_line lexbuf; token lexbuf }
| [' ' '\t']
{ token lexbuf }
| '"' ( [^ '"' '\\'] | ( '\\' [^ '"'] ) ) as s '"'
{ STRING s }
| "let" { LET }
| "if" { IF }
(* | "then" { THEN } *)
| "elseif" { ELSEIF }
| "else" { ELSE }
(* | "in" { IN } *)
| "type" { TYPE }
| "function" { FUNCTION }
| "while"
{ WHILE }
| "foreach"
{ FOREACH }
| "of"
{ OF }
| (['a'-'z']['a'-'z''A'-'Z''0'-'9''_']+) as v
{ VAR_NAME v }
| (['A'-'Z']['a'-'z''A'-'Z''0'-'9''_']+) as t
{ TYPE_NAME t }
(* | ['0'-'9']+'.'['0'-'9']* as i { FLOAT (float_of_string i) } *)
| ['0'-'9']+ as i
{ INT (int_of_string i) }
(*
| '+' { PLUS }
| '-' { MINUS }
| '*' { TIMES }
| '/' { DIV }
| ";;" { DOUBLE_SEMICOLON }
*)
| '=' { EQUAL }
| ',' { COMMA }
| ';' { SEMICOLON }
| ':' { COLON }
| '&'
{ AND }
| '|'
{ AND }
| '.'
{ DOT }
| '@'
{ AT }
| '('
{ LPAREN }
| ')'
{ RPAREN }
(*
| '[' { LSQUARE }
| ']' { RSQUARE }
*)
| '{'
{ LBRACKET }
| '}'
{ RBRACKET }
| eof { EOF }
| _
{ raise (Unexpected_character (Printf.sprintf "At offset %d: unexpected character.\n" (Lexing.lexeme_start lexbuf))) }

View File

@ -50,6 +50,17 @@ let rec bind_list = function
ok @@ hd :: tl ok @@ hd :: tl
) )
let bind_fold_list f init lst =
let aux x y =
x >>? fun x ->
f x y
in
List.fold_left aux (ok init) lst
let bind_list_iter f lst =
let aux () y = f y in
bind_fold_list aux () lst
let bind_or (a, b) = let bind_or (a, b) =
match a with match a with
| Ok x -> ok x | Ok x -> ok x

View File

@ -0,0 +1 @@
module String = Map.Make(String)

View File

@ -7,15 +7,13 @@ open Region
module SMap = Map.Make(String) module SMap = Map.Make(String)
module O = struct module O = struct
type asttodo = [`TODO] type asttodo = [`TODO] (* occurrences of asttodo will point to some part of the original parser AST *)
type name_and_region = {name: string; orig: Region.t} type name_and_region = {name: string; orig: Region.t}
type type_name = name_and_region type type_name = name_and_region
type var_name = name_and_region type var_name = name_and_region
type field_name = name_and_region type field_name = name_and_region
type record_key = [`Field of field_name | `Component of int]
type pattern = type pattern =
PVar of var_name PVar of var_name
| PWild | PWild
@ -29,9 +27,7 @@ module O = struct
| PSome of pattern | PSome of pattern
| PCons of pattern * pattern | PCons of pattern * pattern
| PNull | PNull
| PRecord of record_key precord | PRecord of (field_name * pattern) SMap.t
and 'key precord = ('key * pattern) list
type type_constructor = type type_constructor =
Option Option
@ -40,8 +36,8 @@ module O = struct
| Map | Map
type type_expr_case = type type_expr_case =
Sum of (type_name * type_expr) list Sum of (type_name * type_expr) SMap.t
| Record of record_key type_record | Record of (field_name * type_expr) SMap.t
| TypeApp of type_constructor * (type_expr list) | TypeApp of type_constructor * (type_expr list)
| Function of { arg: type_expr; ret: type_expr } | Function of { arg: type_expr; ret: type_expr }
| Ref of type_expr | Ref of type_expr
@ -49,18 +45,18 @@ module O = struct
| Int | Int
| Unit | Unit
| Bool | Bool
and 'key type_record = ('key * type_expr) list
and type_expr = { type_expr: type_expr_case; name: type_name option; orig: Region.t } and type_expr = { type_expr: type_expr_case; name: type_name option; orig: Region.t }
type typed_var = { name:var_name; ty:type_expr } type typed_var = { name:var_name; ty:type_expr; orig: asttodo }
type type_decl = { name:type_name; ty:type_expr } type type_decl = { name:type_name; ty:type_expr; orig: asttodo }
type expr = type expr =
App of { operator: operator; arguments: expr list } App of { operator: operator; arguments: expr list }
| Var of var_name | Var of var_name
| Constant of constant | Constant of constant
| Record of (field_name * expr) list
| Lambda of lambda | Lambda of lambda
and decl = { name:var_name; ty:type_expr; value: expr } and decl = { name:var_name; ty:type_expr; value: expr }
@ -73,33 +69,36 @@ module O = struct
} }
and operator = and operator =
Function of var_name Function of var_name
| Construcor of var_name | Constructor of var_name
| UpdateField of record_key | UpdateField of field_name
| GetField of record_key | GetField of field_name
| Or | And | Lt | Leq | Gt | Geq | Equal | Neq | Cat | Cons | Add | Sub | Mult | Div | Mod | Or | And | Lt | Leq | Gt | Geq | Equal | Neq | Cat | Cons | Add | Sub | Mult | Div | Mod
| Neg | Not | Neg | Not
| Tuple | Set | List | Set | List
| MapLookup | MapLookup
and constant = and constant =
Unit | Int of Z.t | String of string | Bytes of MBytes.t | False | True Unit
| Null of type_expr | EmptySet of type_expr | CNone of type_expr | Int of Z.t | String of string | Bytes of MBytes.t
| False | True
| Null of type_expr
| EmptySet of type_expr
| CNone of type_expr
and instr = and instr =
Assignment of { name: var_name; value: expr } Assignment of { name: var_name; value: expr; orig: asttodo }
| While of { condition: expr; body: instr list } | While of { condition: expr; body: instr list; orig: asttodo }
| ForCollection of { list: expr; key: var_name; value: var_name option; body: instr list } | ForCollection of { list: expr; var: var_name; body: instr list; orig: asttodo }
| If of { condition: expr; ifso: instr list; ifnot: instr list } | Match of { expr: expr; cases: (pattern * instr list) list; orig: asttodo }
| Match of { expr: expr; cases: (pattern * instr list) list } | ProcedureCall of { expr: expr; orig: asttodo } (* expr returns unit, drop the result. Similar to OCaml's ";". *)
| DropUnit of expr (* expr returns unit, drop the result. *) | Fail of { expr: expr; orig: asttodo }
| Fail of { expr: expr }
type ast = { type ast = {
types : type_decl list; types : type_decl list;
storage_decl : typed_var; storage_decl : typed_var;
operations_decl : typed_var;
declarations : decl list; declarations : decl list;
orig : AST.t
} }
end end
@ -126,6 +125,8 @@ let fold_map f a l =
(* Simplify the AST *) (* Simplify the AST *)
let name_and_region_of_int i = O.{name = string_of_int i; orig = Region.ghost}
let s_nsepseq : ('a,'sep) Utils.nsepseq -> 'a list = let s_nsepseq : ('a,'sep) Utils.nsepseq -> 'a list =
fun (first, rest) -> first :: (map snd rest) fun (first, rest) -> first :: (map snd rest)
@ -155,17 +156,26 @@ let s_type_constructor {value=name;region} : O.type_constructor =
(* TODO: escape the name, prevent any \x1b and other weird characters from appearing in the output *) (* TODO: escape the name, prevent any \x1b and other weird characters from appearing in the output *)
| _ -> failwith ("Unknown type constructor: " ^ name) | _ -> failwith ("Unknown type constructor: " ^ name)
let named_list_to_map (l : (O.name_and_region * 'a) list) : (O.name_and_region * 'a) SMap.t =
List.fold_left
(fun m ((x,_) as p) ->
let {name;_} : O.name_and_region = x in
SMap.add name p m)
SMap.empty
l
let rec s_cartesian {value=sequence; region} : O.type_expr = let rec s_cartesian {value=sequence; region} : O.type_expr =
let () = ignore (region) in let () = ignore (region) in
s_nsepseq sequence s_nsepseq sequence
|>map s_type_expr |>map s_type_expr
|> mapi (fun i p -> `Component i, p) |> mapi (fun i p -> name_and_region_of_int i, p)
|> named_list_to_map
|> (fun x -> (Record x : O.type_expr_case)) |> (fun x -> (Record x : O.type_expr_case))
|> type_expr region |> type_expr region
and s_sum_type {value=sequence; region} : O.type_expr = and s_sum_type {value=sequence; region} : O.type_expr =
let () = ignore (region) in let () = ignore (region) in
type_expr region (Sum (map s_variant (s_nsepseq sequence))) type_expr region (Sum (map s_variant (s_nsepseq sequence) |> named_list_to_map))
and s_variant {value=(constr, kwd_of, cartesian); region} = and s_variant {value=(constr, kwd_of, cartesian); region} =
let () = ignore (kwd_of,region) in let () = ignore (kwd_of,region) in
@ -173,11 +183,11 @@ and s_variant {value=(constr, kwd_of, cartesian); region} =
and s_record_type {value=(kwd_record, field_decls, kwd_end); region} : O.type_expr = and s_record_type {value=(kwd_record, field_decls, kwd_end); region} : O.type_expr =
let () = ignore (kwd_record,region,kwd_end) in let () = ignore (kwd_record,region,kwd_end) in
type_expr region (Record (map s_field_decl (s_nsepseq field_decls))) type_expr region (Record (map s_field_decl (s_nsepseq field_decls) |> named_list_to_map) : O.type_expr_case)
and s_field_decl {value=(var, colon, type_expr); region} = and s_field_decl {value=(var, colon, type_expr); region} : O.type_name * O.type_expr =
let () = ignore (colon,region) in let () = ignore (colon,region) in
(`Field (s_name var), s_type_expr type_expr) ((s_name var), (s_type_expr type_expr))
and s_type_app {value=(type_name,type_tuple); region} : O.type_expr = and s_type_app {value=(type_name,type_tuple); region} : O.type_expr =
let () = ignore (region) in let () = ignore (region) in
@ -208,15 +218,15 @@ and s_type_expr (orig : I.type_expr) : O.type_expr = match orig with
let s_type_decl I.{value={kwd_type;name;kwd_is;type_expr;terminator}; region} : O.type_decl = let s_type_decl I.{value={kwd_type;name;kwd_is;type_expr;terminator}; region} : O.type_decl =
let () = ignore (kwd_type,kwd_is,terminator,region) in let () = ignore (kwd_type,kwd_is,terminator,region) in
let ty = s_type_expr type_expr in let ty = s_type_expr type_expr in
O.{ name = s_name name; ty = { ty with name = Some (s_name name) } } O.{ name = s_name name; ty = { ty with name = Some (s_name name) }; orig = `TODO }
let s_storage_decl I.{value={kwd_storage; name; colon; store_type; terminator}; region} : O.typed_var = let s_storage_decl I.{value={kwd_storage; name; colon; store_type; terminator}; region} : O.typed_var =
let () = ignore (kwd_storage,colon,terminator,region) in let () = ignore (kwd_storage,colon,terminator,region) in
O.{ name = s_name name; ty = s_type_expr store_type } O.{ name = s_name name; ty = s_type_expr store_type; orig = `TODO }
let s_operations_decl I.{value={kwd_operations;name;colon;op_type;terminator}; region} : O.typed_var = let s_operations_decl I.{value={kwd_operations;name;colon;op_type;terminator}; region} : O.typed_var =
let () = ignore (kwd_operations,colon,terminator,region) in let () = ignore (kwd_operations,colon,terminator,region) in
O.{ name = s_name name; ty = s_type_expr op_type } O.{ name = s_name name; ty = s_type_expr op_type; orig = `TODO }
let s_empty_list {value=(l, (lbracket, rbracket, colon, type_expr), r); region} : O.expr = let s_empty_list {value=(l, (lbracket, rbracket, colon, type_expr), r); region} : O.expr =
let () = ignore (l, lbracket, rbracket, colon, r, region) in let () = ignore (l, lbracket, rbracket, colon, r, region) in
@ -232,13 +242,15 @@ let s_none {value=(l, (c_None, colon, type_expr), r); region} : O.expr =
let parameters_to_tuple (parameters : (string * O.type_expr) list) : O.type_expr = let parameters_to_tuple (parameters : (string * O.type_expr) list) : O.type_expr =
(* TODO: use records with named fields to have named arguments. *) (* TODO: use records with named fields to have named arguments. *)
let parameter_tuple = O.Record (mapi (fun i (_name,ty) -> `Component i, ty) parameters) in let parameter_tuple : O.type_expr_case =
Record (mapi (fun i (_name,ty) -> name_and_region_of_int i, ty) parameters |> named_list_to_map) in
O.{ type_expr = parameter_tuple; name = None; orig = Region.ghost } O.{ type_expr = parameter_tuple; name = None; orig = Region.ghost }
and parameters_to_decls singleparam (parameters : (string * O.type_expr) list) : O.decl list = and parameters_to_decls singleparam (parameters : (string * O.type_expr) list) : O.decl list =
let f i (name,ty) = let f i (name,ty) =
O.{ name = {name; orig=Region.ghost}; O.{ name = {name; orig=Region.ghost};
ty = ty; ty = ty;
value = App { operator = O.GetField (`Component i); value = App { operator = O.GetField (name_and_region_of_int i);
arguments = [Var singleparam] } } arguments = [Var singleparam] } }
in mapi f parameters in mapi f parameters
@ -270,7 +282,7 @@ and s_expr : I.expr -> O.expr =
| False c_False -> let () = ignore (c_False) in Constant (False) | False c_False -> let () = ignore (c_False) in Constant (False)
| True c_True -> let () = ignore (c_True) in Constant (True) | True c_True -> let () = ignore (c_True) in Constant (True)
| Unit c_Unit -> let () = ignore (c_Unit) in Constant (Unit) | Unit c_Unit -> let () = ignore (c_Unit) in Constant (Unit)
| Tuple {value=(l,tuple,r); region} -> let () = ignore (l,r,region) in App { operator = Tuple; arguments = map s_expr (s_nsepseq tuple)} | Tuple {value=(l,tuple,r); region} -> let () = ignore (l,r,region) in s_tuple_expr (tuple |> s_nsepseq |> map s_expr)
| List list -> s_list list | List list -> s_list list
| EmptyList empty_list -> s_empty_list empty_list | EmptyList empty_list -> s_empty_list empty_list
| Set set -> s_set set | Set set -> s_set set
@ -282,6 +294,9 @@ and s_expr : I.expr -> O.expr =
| MapLookUp map_lookup -> s_map_lookup map_lookup | MapLookUp map_lookup -> s_map_lookup map_lookup
| ParExpr {value=(lpar,expr,rpar); region} -> let () = ignore (lpar,rpar,region) in s_expr expr | ParExpr {value=(lpar,expr,rpar); region} -> let () = ignore (lpar,rpar,region) in s_expr expr
and s_tuple_expr tuple : O.expr =
Record (mapi (fun i e -> name_and_region_of_int i, e) tuple)
and s_map_lookup I.{value = {map_name; selector; index}; region} : O.expr = and s_map_lookup I.{value = {map_name; selector; index}; region} : O.expr =
let {value = lbracket, index_expr, rbracket; region=region2} = index in let {value = lbracket, index_expr, rbracket; region=region2} = index in
let () = ignore (selector, lbracket, rbracket, region2, region) in let () = ignore (selector, lbracket, rbracket, region2, region) in
@ -292,7 +307,7 @@ and s_some_app {value=(c_Some, {value=(l,arguments,r); region=region2}); region}
match s_nsepseq arguments with match s_nsepseq arguments with
[] -> failwith "tuple cannot be empty" [] -> failwith "tuple cannot be empty"
| [a] -> s_expr a | [a] -> s_expr a
| l -> App { operator = Tuple; arguments = map s_expr l } | l -> s_tuple_expr (map s_expr l)
and s_list {value=(l, list, r); region} : O.expr = and s_list {value=(l, list, r); region} : O.expr =
let () = ignore (l, r, region) in let () = ignore (l, r, region) in
@ -347,8 +362,8 @@ and s_ptuple {value=(lpar, sequence, rpar); region} =
let () = ignore (lpar, rpar, region) in let () = ignore (lpar, rpar, region) in
s_nsepseq sequence s_nsepseq sequence
|> map s_core_pattern |> map s_core_pattern
|> mapi (fun i p -> `Component i, p) |> mapi (fun i p -> name_and_region_of_int i, p)
|> fun x -> O.PRecord x |> fun x -> O.PRecord (x |> named_list_to_map)
and s_psome {value=(c_Some,{value=(l,psome,r);region=region2});region} : O.pattern = and s_psome {value=(c_Some,{value=(l,psome,r);region=region2});region} : O.pattern =
let () = ignore (c_Some,l,r,region2,region) in let () = ignore (c_Some,l,r,region2,region) in
@ -398,20 +413,27 @@ and s_instruction : I.instruction -> O.instr list = function
and s_conditional I.{kwd_if;test;kwd_then;ifso;kwd_else;ifnot} : O.instr = and s_conditional I.{kwd_if;test;kwd_then;ifso;kwd_else;ifnot} : O.instr =
let () = ignore (kwd_if,kwd_then,kwd_else) in let () = ignore (kwd_if,kwd_then,kwd_else) in
If { condition = s_expr test; ifso = s_instruction ifso; ifnot = s_instruction ifnot } let test = s_expr test in
let ifso = O.PTrue, s_instruction ifso in
let ifnot = O.PFalse, s_instruction ifnot in
Match {
expr = test;
cases = [ifso; ifnot];
orig = `TODO
}
and s_match_instr I.{kwd_match;expr;kwd_with;lead_vbar;cases;kwd_end} : O.instr = and s_match_instr I.{kwd_match;expr;kwd_with;lead_vbar;cases;kwd_end} : O.instr =
let {value=cases;region} = cases in let {value=cases;region} = cases in
let () = ignore (kwd_match,kwd_with,lead_vbar,kwd_end,region) in let () = ignore (kwd_match,kwd_with,lead_vbar,kwd_end,region) in
Match { expr = s_expr expr; cases = map s_case (s_nsepseq cases) } Match { expr = s_expr expr; cases = map s_case (s_nsepseq cases); orig = `TODO }
and s_ass_instr {value=(variable,ass,expr); region} : O.instr = and s_ass_instr {value=(variable,ass,expr); region} : O.instr =
let () = ignore (ass,region) in let () = ignore (ass,region) in
Assignment { name = s_name variable; value = s_expr expr } Assignment { name = s_name variable; value = s_expr expr; orig = `TODO }
and s_while_loop {value=(kwd_while, expr, block); region} : O.instr list = and s_while_loop {value=(kwd_while, expr, block); region} : O.instr list =
let () = ignore (kwd_while,region) in let () = ignore (kwd_while,region) in
[While {condition = s_expr expr; body = s_block block}] [While {condition = s_expr expr; body = s_block block; orig = `TODO}]
and s_for_loop : I.for_loop -> O.instr list = function and s_for_loop : I.for_loop -> O.instr list = function
ForInt for_int -> s_for_int for_int ForInt for_int -> s_for_int for_int
@ -425,28 +447,34 @@ and s_for_int ({value={kwd_for;ass;down;kwd_to;bound;step;block}; region} : I.fo
| None -> O.Lt, O.Add in | None -> O.Lt, O.Add in
let step = s_step step let step = s_step step
in [ in [
Assignment { name; value = s_expr expr }; Assignment { name; value = s_expr expr; orig = `TODO };
(* TODO: lift the declaration of the variable, to avoid creating a nested scope here. *) (* TODO: lift the declaration of the variable, to avoid creating a nested scope here. *)
While { While {
condition = App { operator = condition; condition = App { operator = condition;
arguments = [Var name; s_expr bound] }; arguments = [Var name; s_expr bound]};
body = append (s_block block) body = append (s_block block)
[O.Assignment { name; [O.Assignment { name;
value = App { operator; value = App { operator;
arguments = [Var name; step]}}] arguments = [Var name; step]};
orig = `TODO }];
orig = `TODO
} }
] ]
and s_for_collect ({value={kwd_for;var;bind_to;kwd_in;expr;block}; _} : I.for_collect reg) : O.instr list = and s_for_collect ({value={kwd_for;var;bind_to;kwd_in;expr;block}; _} : I.for_collect reg) : O.instr list =
let () = ignore (kwd_for,kwd_in) in let () = ignore (kwd_for,kwd_in) in
[ let for_instr =
O.ForCollection { match s_bind_to bind_to with
list = s_expr expr; Some _ ->
key = s_name var; failwith "TODO: For on maps is not supported yet!"
value = s_bind_to bind_to; | None ->
body = s_block block O.ForCollection {
} list = s_expr expr;
] var = s_name var;
body = s_block block;
orig = `TODO
}
in [for_instr]
and s_step : (I.kwd_step * I.expr) option -> O.expr = function and s_step : (I.kwd_step * I.expr) option -> O.expr = function
Some (kwd_step, expr) -> let () = ignore (kwd_step) in s_expr expr Some (kwd_step, expr) -> let () = ignore (kwd_step) in s_expr expr
@ -462,7 +490,13 @@ and s_loop : I.loop -> O.instr list = function
and s_fun_call {value=(fun_name, arguments); region} : O.expr = and s_fun_call {value=(fun_name, arguments); region} : O.expr =
let () = ignore (region) in let () = ignore (region) in
App { operator = Function (s_name fun_name); arguments = s_arguments arguments } let {value=fun_name_string;_} = fun_name in
let firstchar = String.sub fun_name_string 0 1 in
(* If it starts with a capital letter, then it is a constructor *)
if String.equal firstchar (String.uppercase_ascii firstchar) then
App { operator = Constructor (s_name fun_name); arguments = s_arguments arguments }
else
App { operator = Function (s_name fun_name); arguments = s_arguments arguments }
and s_constr_app {value=(constr, arguments); region} : O.expr = and s_constr_app {value=(constr, arguments); region} : O.expr =
let () = ignore (region) in let () = ignore (region) in
@ -474,11 +508,11 @@ and s_arguments {value=(lpar, sequence, rpar); region} : O.expr list =
match map s_expr (s_nsepseq sequence) with match map s_expr (s_nsepseq sequence) with
[] -> [Constant Unit] [] -> [Constant Unit]
| [single_argument] -> [single_argument] | [single_argument] -> [single_argument]
| args -> [App { operator = Tuple; arguments = args }] ; | args -> [s_tuple_expr args] ;
and s_fail ((kwd_fail, expr) : (I.kwd_fail * I.expr)) : O.instr = and s_fail ((kwd_fail, expr) : (I.kwd_fail * I.expr)) : O.instr =
let () = ignore (kwd_fail) in let () = ignore (kwd_fail) in
Fail { expr = s_expr expr } Fail { expr = s_expr expr; orig = `TODO }
@ -488,7 +522,7 @@ and s_single_instr : I.single_instr -> O.instr list = function
| Match {value; _} -> [s_match_instr value] | Match {value; _} -> [s_match_instr value]
| Ass instr -> [s_ass_instr instr] | Ass instr -> [s_ass_instr instr]
| Loop loop -> s_loop loop | Loop loop -> s_loop loop
| ProcCall fun_call -> [DropUnit (s_fun_call fun_call)] | ProcCall fun_call -> [ProcedureCall { expr = s_fun_call fun_call; orig = `TODO }]
| Null kwd_null -> let () = ignore (kwd_null) in | Null kwd_null -> let () = ignore (kwd_null) in
[] []
| Fail {value; _} -> [s_fail value] | Fail {value; _} -> [s_fail value]
@ -502,13 +536,13 @@ and gensym =
fun ty -> fun ty ->
i := !i + 1; i := !i + 1;
(* TODO: Region.ghost *) (* TODO: Region.ghost *)
({name = {name=(string_of_int !i) ^ "gensym"; orig = Region.ghost}; ty} : O.typed_var) ({name = {name=(string_of_int !i) ^ "gensym"; orig = Region.ghost}; ty; orig = `TODO} : O.typed_var)
and s_fun_decl I.{value={kwd_function;name;param;colon;ret_type;kwd_is;local_decls;block;kwd_with;return;terminator}; region} : O.decl = and s_fun_decl I.{value={kwd_function;name;param;colon;ret_type;kwd_is;local_decls;block;kwd_with;return;terminator}; region} : O.decl =
let () = ignore (kwd_function,colon,kwd_is,kwd_with,terminator,region) in let () = ignore (kwd_function,colon,kwd_is,kwd_with,terminator,region) in
let tuple_type = s_parameters param |> parameters_to_tuple in let tuple_type = s_parameters param |> parameters_to_tuple in
let single_argument = gensym tuple_type in let single_argument = gensym tuple_type in
let ({name = single_argument_xxx; ty = _} : O.typed_var) = single_argument in let ({name = single_argument_xxx; ty = _; orig = `TODO} : O.typed_var) = single_argument in
O.{ O.{
name = s_name name; name = s_name name;
ty = type_expr region (Function { arg = tuple_type; ty = type_expr region (Function { arg = tuple_type;
@ -527,7 +561,7 @@ and s_proc_decl I.{value={kwd_procedure;name;param;kwd_is;local_decls;block;term
let () = ignore (kwd_procedure,kwd_is,terminator,region) in let () = ignore (kwd_procedure,kwd_is,terminator,region) in
let tuple_type = s_parameters param |> parameters_to_tuple in let tuple_type = s_parameters param |> parameters_to_tuple in
let single_argument = gensym tuple_type in let single_argument = gensym tuple_type in
let ({name = single_argument_xxx; ty = _} : O.typed_var) = single_argument in let ({name = single_argument_xxx; ty = _; orig = `TODO} : O.typed_var) = single_argument in
O.{ O.{
name = s_name name; name = s_name name;
ty = type_expr region (Function { arg = tuple_type; ty = type_expr region (Function { arg = tuple_type;
@ -546,7 +580,7 @@ and s_entry_decl I.{value={kwd_entrypoint;name;param;kwd_is;local_decls;block;te
let () = ignore (kwd_entrypoint,kwd_is,terminator,region) in let () = ignore (kwd_entrypoint,kwd_is,terminator,region) in
let tuple_type = s_parameters param |> parameters_to_tuple in let tuple_type = s_parameters param |> parameters_to_tuple in
let single_argument = gensym tuple_type in let single_argument = gensym tuple_type in
let ({name = single_argument_xxx; ty = _} : O.typed_var) = single_argument in let ({name = single_argument_xxx; ty = _; orig = `TODO} : O.typed_var) = single_argument in
O.{ O.{
name = s_name name; name = s_name name;
ty = type_expr region (Function { arg = tuple_type; ty = type_expr region (Function { arg = tuple_type;
@ -594,10 +628,10 @@ let s_ast (ast : I.ast) : O.ast =
let storage_decl = match storage_decl with let storage_decl = match storage_decl with
Some x -> x Some x -> x
| None -> failwith "Missing storage declaration" in | None -> failwith "Missing storage declaration" in
let operations_decl = match operations_decl with let () = match operations_decl with
Some x -> x Some _ -> failwith "Operations declaration is not allowed anymore TODO"
| None -> failwith "Missing storage declaration" | None -> ()
in {types; storage_decl; operations_decl; declarations} in {types; storage_decl; declarations; orig = ast}

View File

@ -34,12 +34,40 @@ let lib_path =
in List.fold_right mk_I libs "" in List.fold_right mk_I libs ""
*) *)
(* Preprocessing the input source and opening the input channels *)
let prefix =
match EvalOpt.input with
None | Some "-" -> "temp"
| Some file -> Filename.(file |> basename |> remove_extension)
let suffix = ".pp.li"
let pp_input =
if Utils.String.Set.mem "cpp" EvalOpt.verbose
then prefix ^ suffix
else let pp_input, pp_out = Filename.open_temp_file prefix suffix
in close_out pp_out; pp_input
let cpp_cmd =
match EvalOpt.input with
None | Some "-" ->
Printf.sprintf "cpp -traditional-cpp - -o %s" pp_input
| Some file ->
Printf.sprintf "cpp -traditional-cpp %s -o %s" file pp_input
let () =
if Utils.String.Set.mem "cpp" EvalOpt.verbose
then Printf.eprintf "%s\n%!" cpp_cmd;
if Sys.command cpp_cmd <> 0 then
external_ (Printf.sprintf "the command \"%s\" failed." cpp_cmd)
(* Instanciating the lexer *) (* Instanciating the lexer *)
module Lexer = Lexer.Make (LexToken) module Lexer = Lexer.Make (LexToken)
let Lexer.{read; buffer; get_pos; get_last; close} = let Lexer.{read; buffer; get_pos; get_last; close} =
Lexer.open_token_stream EvalOpt.input Lexer.open_token_stream (Some pp_input)
and cout = stdout and cout = stdout
@ -78,6 +106,8 @@ let () =
(* Temporary: force dune to build AST2.ml *) (* Temporary: force dune to build AST2.ml *)
let () = let () =
let open Typecheck2 in if false then
let _ = temporary_force_dune in let _ = Typecheck2.annotate in
() ()
else
()

View File

@ -1,7 +1,11 @@
[@@@warning "-27"] (* TODO *)
[@@@warning "-32"] (* TODO *)
[@@@warning "-30"] [@@@warning "-30"]
module SMap = Map.Make(String) module SMap = Map.Make(String)
module I = AST2.O
module O = struct module O = struct
type asttodo = [`TODO] (* occurrences of asttodo will point to some part of the original parser AST *) type asttodo = [`TODO] (* occurrences of asttodo will point to some part of the original parser AST *)
@ -23,7 +27,7 @@ module O = struct
| PSome of pattern | PSome of pattern
| PCons of pattern * pattern | PCons of pattern * pattern
| PNull | PNull
| PRecord of (field_name * pattern) list | PRecord of (field_name * pattern) SMap.t
type type_constructor = type type_constructor =
Option Option
@ -32,8 +36,8 @@ module O = struct
| Map | Map
type type_expr_case = type type_expr_case =
Sum of (type_name * type_expr) list Sum of (type_name * type_expr) SMap.t
| Record of (field_name * type_expr) list | Record of (field_name * type_expr) SMap.t
| TypeApp of type_constructor * (type_expr list) | TypeApp of type_constructor * (type_expr list)
| Function of { arg: type_expr; ret: type_expr } | Function of { arg: type_expr; ret: type_expr }
| Ref of type_expr | Ref of type_expr
@ -42,7 +46,7 @@ module O = struct
| Unit | Unit
| Bool | Bool
and type_expr = { type_expr: type_expr_case; name: string option; orig: AST.type_expr } and type_expr = { type_expr: type_expr_case; name: string option; orig: Region.t }
type typed_var = { name:var_name; ty:type_expr; orig: asttodo } type typed_var = { name:var_name; ty:type_expr; orig: asttodo }
@ -68,7 +72,7 @@ module O = struct
and operator_case = and operator_case =
Function of var_name Function of var_name
| Construcor of var_name | Constructor of var_name
| UpdateField of field_name | UpdateField of field_name
| GetField of field_name | GetField of field_name
| Or | And | Lt | Leq | Gt | Geq | Equal | Neq | Cat | Cons | Add | Sub | Mult | Div | Mod | Or | And | Lt | Leq | Gt | Geq | Equal | Neq | Cat | Cons | Add | Sub | Mult | Div | Mod
@ -98,8 +102,61 @@ module O = struct
types : type_decl list; types : type_decl list;
storage_decl : typed_var; storage_decl : typed_var;
declarations : decl list; declarations : decl list;
orig: AST.t orig : AST.t
} }
end end
let temporary_force_dune = 123 type te = O.type_expr list SMap.t
type ve = O.type_expr list SMap.t
type tve = te * ve
let fold_map f a l =
let f (acc, l) elem =
let acc', elem' = f acc elem
in acc', (elem' :: l) in
let last_acc, last_l = List.fold_left f (a, []) l
in last_acc, List.rev last_l
let a_type_constructor (tve : tve) : I.type_constructor -> O.type_constructor = function
Option -> failwith "TODO"
| List -> failwith "TODO"
| Set -> failwith "TODO"
| Map -> failwith "TODO"
let a_type_expr_case (tve : tve) : I.type_expr_case -> O.type_expr_case = function
Sum l -> failwith "TODO"
| Record l -> failwith "TODO"
| TypeApp (tc, args) -> failwith "TODO"
| Function {arg;ret} -> failwith "TODO"
| Ref t -> failwith "TODO"
| String -> failwith "TODO"
| Int -> failwith "TODO"
| Unit -> failwith "TODO"
| Bool -> failwith "TODO"
let a_type_expr (tve : tve) ({type_expr;name;orig} : I.type_expr) : O.type_expr =
failwith "TODO"
let a_type (tve : tve) ({name;ty;orig} : I.type_decl) : tve * O.type_decl =
failwith "TODO"
let a_types (tve : tve) (l : I.type_decl list) : tve * O.type_decl list =
fold_map a_type tve l
let a_storage_decl : tve -> I.typed_var -> tve * O.typed_var =
failwith "TODO"
let a_declarations : tve -> I.decl list -> tve * O.decl list =
failwith "TODO"
let a_ast I.{types; storage_decl; declarations; orig} =
let tve = SMap.empty, SMap.empty in
let tve, types = a_types tve types in
let tve, storage_decl = a_storage_decl tve storage_decl in
let tve, declarations = a_declarations tve declarations in
let _ = tve in
O.{types; storage_decl; declarations; orig}
let annotate : I.ast -> O.ast = a_ast

View File

@ -2,6 +2,8 @@
module SMap : Map.S with type key = string module SMap : Map.S with type key = string
module I = AST2.O
module O : sig module O : sig
type asttodo = [`TODO] (* occurrences of asttodo will point to some part of the original parser AST *) type asttodo = [`TODO] (* occurrences of asttodo will point to some part of the original parser AST *)
@ -23,7 +25,7 @@ module O : sig
| PSome of pattern | PSome of pattern
| PCons of pattern * pattern | PCons of pattern * pattern
| PNull | PNull
| PRecord of (field_name * pattern) list | PRecord of (field_name * pattern) SMap.t
type type_constructor = type type_constructor =
Option Option
@ -32,8 +34,8 @@ module O : sig
| Map | Map
type type_expr_case = type type_expr_case =
Sum of (type_name * type_expr) list Sum of (type_name * type_expr) SMap.t
| Record of (field_name * type_expr) list | Record of (field_name * type_expr) SMap.t
| TypeApp of type_constructor * (type_expr list) | TypeApp of type_constructor * (type_expr list)
| Function of { arg: type_expr; ret: type_expr } | Function of { arg: type_expr; ret: type_expr }
| Ref of type_expr | Ref of type_expr
@ -42,7 +44,7 @@ module O : sig
| Unit | Unit
| Bool | Bool
and type_expr = { type_expr: type_expr_case; name: string option; orig: AST.type_expr } and type_expr = { type_expr: type_expr_case; name: string option; orig: Region.t }
type typed_var = { name:var_name; ty:type_expr; orig: asttodo } type typed_var = { name:var_name; ty:type_expr; orig: asttodo }
@ -68,7 +70,7 @@ module O : sig
and operator_case = and operator_case =
Function of var_name Function of var_name
| Construcor of var_name | Constructor of var_name
| UpdateField of field_name | UpdateField of field_name
| GetField of field_name | GetField of field_name
| Or | And | Lt | Leq | Gt | Geq | Equal | Neq | Cat | Cons | Add | Sub | Mult | Div | Mod | Or | And | Lt | Leq | Gt | Geq | Equal | Neq | Cat | Cons | Add | Sub | Mult | Div | Mod
@ -98,8 +100,8 @@ module O : sig
types : type_decl list; types : type_decl list;
storage_decl : typed_var; storage_decl : typed_var;
declarations : decl list; declarations : decl list;
orig: AST.t orig : AST.t
} }
end end
val temporary_force_dune : int val annotate : I.ast -> O.ast

View File

@ -0,0 +1,7 @@
module Parser = Parser
module Lexer = Lexer.Make(LexToken)
module AST = AST
module AST2 = AST2
module Typed = Typecheck2
let ast_to_typed_ast ast = ast |> AST2.s_ast |> Typed.annotate

View File

@ -1,5 +1,53 @@
include Main open Ligo_parser
module Mini_c = Mini_c
module Parser = Parser module Parser = Parser
module Lexer = Lexer module Lexer = Lexer
module CST = AST
module AST = AST2
module Typed = Typed
module Mini_c = Mini_c
open Ligo_helpers.Trace
let parse_file (source:string) : CST.t result =
let channel = open_in source in
let lexbuf = Lexing.from_channel channel in
let Lexer.{read ; _} =
Lexer.open_token_stream None in
specific_try (function
| Parser.Error -> (
let start = Lexing.lexeme_start_p lexbuf in
let end_ = Lexing.lexeme_end_p lexbuf in
let str = Format.sprintf
"Parse error at \"%s\" from (%d, %d) to (%d, %d)\n"
(Lexing.lexeme lexbuf)
start.pos_lnum (start.pos_cnum - start.pos_bol)
end_.pos_lnum (end_.pos_cnum - end_.pos_bol) in
simple_error str
)
| _ -> simple_error "unrecognized parse_ error"
) @@ (fun () -> Parser.program read lexbuf) >>? fun program_cst ->
ok program_cst
let parse (s:string) : CST.t result =
let lexbuf = Lexing.from_string s in
let Lexer.{read ; _} =
Lexer.open_token_stream None in
specific_try (function
| Parser.Error -> (
let start = Lexing.lexeme_start_p lexbuf in
let end_ = Lexing.lexeme_end_p lexbuf in
let str = Format.sprintf
"Parse error at \"%s\" from (%d, %d) to (%d, %d)\n"
(Lexing.lexeme lexbuf)
start.pos_lnum (start.pos_cnum - start.pos_bol)
end_.pos_lnum (end_.pos_cnum - end_.pos_bol) in
simple_error str
)
| _ -> simple_error "unrecognized parse_ error"
) @@ (fun () -> Parser.program read lexbuf) >>? fun program_cst ->
ok program_cst
let abstract (cst:CST.t) : AST.O.ast result = ok @@ AST.s_ast cst
let annotate_types (ast:AST.O.ast) = ok @@ Typed.annotate ast

View File

@ -1,461 +0,0 @@
(* -*- compile-command: "cd .. ; dune build -p ligo" -*- *)
open Ligo_helpers
open Trace
module Untyped = struct
module WrapLocation = Wrap.Location
let wrap = Wrap.Location.make
module Type = struct
type name = string
type base = [
| `Unit
| `Bool
| `Int
| `Nat
]
let unit : base = `Unit
let bool : base = `Bool
let int : base = `Int
let nat : base = `Nat
type 'a node = [
| `Pair of 'a * 'a
| `Or of 'a * 'a
]
type expression_ast = [
| expression node
| base
| `Name of name
]
and expression = expression_ast WrapLocation.t
let pair ~loc a b : expression = wrap ~loc (`Pair(a,b))
let union ~loc a b : expression = wrap ~loc (`Or(a,b))
let name ~loc s : expression =
wrap ~loc (match s with
| "Unit" -> (unit :> expression_ast)
| "Bool" -> (bool :> expression_ast)
| "Int" -> (int :> expression_ast)
| "Nat" -> (nat :> expression_ast)
| s -> `Name s)
end
module Value = struct
type name = string
type function_name = string
type constant = [
| `Int of int
]
type expression = [
| `Variable of name
| `Pair of expression * expression
| `Application of expression * expression
| `Constant of constant
] WrapLocation.t
type assignment = [
| `Let of name * expression
| `Type of Type.name * Type.expression
| `Function of function_name * Type.expression * block
] WrapLocation.t
and statement = [
| `Assignment of assignment
| `ForEach of name * expression * block
| `While of expression * block
| `Condition of expression * block * (expression * block) list * block option
] WrapLocation.t
and block = statement list WrapLocation.t
and program = assignment list WrapLocation.t
type 'a wrapper = loc:Location.t -> 'a -> 'a WrapLocation.t
let int = (WrapLocation.make_f (fun a -> `Constant (`Int a)) : loc:_ -> _ -> expression)
let constatn = (WrapLocation.make_f (fun a -> `Constant a) : loc:_ -> _ -> expression)
let variable = (WrapLocation.make_f (fun a -> `Variable a) : loc:_ -> _ -> expression)
let pair = (WrapLocation.make_f (fun a -> `Pair a) : loc:_ -> _ -> expression)
let application = (WrapLocation.make_f (fun a -> `Application a) : loc:_ -> _ -> expression)
let let_ = (WrapLocation.make_f (fun a -> `Let a) : loc:_ -> _ -> assignment)
let type_ = (WrapLocation.make_f (fun a -> `Type a) : loc:_ -> _ -> assignment)
let fun_ = (WrapLocation.make_f (fun a -> `Function a) : loc:_ -> _ -> assignment)
let assignment = (WrapLocation.make_f (fun a -> `Assignment a) : loc:_ -> _ -> statement)
let foreach = (WrapLocation.make_f (fun a -> `ForEach a) : loc:_ -> _ -> statement)
let while_ = (WrapLocation.make_f (fun a -> `While a) : loc:_ -> _ -> statement)
let elseif x : (expression * block) = x
let else_ x : block = x
let if_ = (WrapLocation.make_f (fun a -> `Condition a) : loc:_ -> _ -> statement)
let block = (WrapLocation.make : loc:_ -> _ -> block)
let program = (WrapLocation.make : loc:_ -> _ -> program)
end
end
module Typed = struct
module Type = struct
module WrapLocation = Wrap.Location
let wrap = WrapLocation.make
type name = string
type base = [
| `Unit
| `Bool
| `Int
| `Nat
]
let unit : base = `Unit
let bool : base = `Bool
let int : base = `Int
let nat : base = `Nat
type 'a node = [
| `Pair of 'a * 'a
| `Or of 'a * 'a
]
type value = [
| value node
| base
]
type expression_ast = [
| expression node
| base
| `Name of name
]
and expression = expression_ast
let rec of_untyped (x:Untyped.Type.expression) : expression = match x.value with
| `Pair(a, b) -> `Pair(of_untyped a, of_untyped b)
| `Or(a, b) -> `Or(of_untyped a, of_untyped b)
| `Int as s -> s
| `Unit as s -> s
| `Nat as s -> s
| `Bool as s -> s
| `Name _ as s -> s
let pair_v a b : value = `Pair(a,b)
let union_v a b : value = `Or(a,b)
let pair_e a b : expression = `Pair(a,b)
let union_e a b : expression = `Or(a,b)
let name : string -> expression = function
| "Unit" -> (unit :> expression_ast)
| "Bool" -> (bool :> expression_ast)
| "Int" -> (int :> expression_ast)
| "Nat" -> (nat :> expression_ast)
| s -> `Name s
module Environment = Environment.Make(val (
Environment.parameter () :
(module Environment.PARAMETER
with type key = name
and type value = value)))
let rec eval (env:Environment.t) : expression -> value result = function
| `Name x -> (
trace_option (simple_error "name doesn't exist in environment") @@
Environment.get_opt env x
)
| `Pair (a, b) -> (
eval env a >>? fun a ->
eval env b >>? fun b ->
ok (`Pair (a, b))
)
| `Or (a, b) -> (
eval env a >>? fun a ->
eval env b >>? fun b ->
ok (`Or (a, b))
)
| `Bool as x -> ok x
| `Unit as x -> ok x
| `Nat as x -> ok x
| `Int as x -> ok x
end
module Value = struct
module WrapLocation = Wrap.Location
let wrap = WrapLocation.make
module WrapTypeLocation = Wrap.Make(struct type meta = (Type.value * Location.t) end)
let wrap_tl = WrapTypeLocation.make
let type_of (x:'a WrapTypeLocation.t) : Type.value = fst x.meta
type name = string
type function_name = string
type constant = [
| `Int of int
]
type 'a node = [
| `Constant of constant
| `Pair of 'a * 'a
]
let int n = `Constant (`Int n)
type value = value node
type expression = [
| expression node
| `Variable of name
] WrapTypeLocation.t
let variable n = `Variable n
let pair a b = `Pair (a, b)
type assignment = [
| `Let of name * expression
| `Type of Type.name * Type.value
| `Function of function_name * Type.value * block * Type.value
] WrapLocation.t
and statement = assignment
and block = statement list
and toplevel_statement = assignment
and program = toplevel_statement list
module Environment = Environment.Make(val (
Environment.parameter () :
(module Environment.PARAMETER
with type key = name
and type value = Type.value)))
end
module Environment = struct
type type_environment = Type.Environment.t
type value_environment = Value.Environment.t
type t = {
type_environment : type_environment ;
value_environment : value_environment ;
}
let empty = {
type_environment = Type.Environment.empty ;
value_environment = Value.Environment.empty ;
}
let add_type env
name type_value =
{ env with
type_environment =
Type.Environment.set env.type_environment name type_value }
let add_variable env
name type_value =
{ env with
value_environment =
Value.Environment.set env.value_environment name type_value }
end
end
module Typecheck = struct
module UV = Untyped.Value
module UT = Untyped.Type
module TV = Typed.Value
module TT = Typed.Type
type env = Typed.Environment.t
type ty = Typed.Type.value
let typecheck_constant (constant:UV.constant) : _ = match constant with
| `Int n -> (`Int, `Int n)
let rec typecheck_expression (env:env) (e:UV.expression) : (TV.expression) result =
match e.value with
| `Constant c -> (
let (ty, value) = typecheck_constant c in
ok (TV.wrap_tl (ty, e.meta) (`Constant value))
)
| `Variable n -> (
trace_option (simple_error "variable doesn't exist in env")
@@ TV.Environment.get_opt env.value_environment n >>? fun ty ->
ok (TV.wrap_tl (ty, e.meta) (TV.variable n))
)
| `Pair(a, b) -> (
typecheck_expression env a >>? fun a ->
typecheck_expression env b >>? fun b ->
let ty = TT.pair_v (TV.type_of a) (TV.type_of b) in
ok (TV.wrap_tl (ty, e.meta) (TV.pair a b))
)
| `Application _ -> simple_fail "Application isn't supported yet"
let rec typecheck_assignment (env:env) (u:UV.assignment) : (env * TV.assignment) result =
match u.value with
| `Let(name, expression) -> (
typecheck_expression env expression >>? fun expression ->
let ass : TV.assignment = TV.wrap ~loc:u.meta (`Let(name, expression)) in
let env = Typed.Environment.add_variable env name (TV.type_of expression) in
ok (env, ass)
)
| `Type(name, expression) -> (
TT.eval env.type_environment (TT.of_untyped expression) >>? fun value ->
let env = Typed.Environment.add_type env name value in
let ass : TV.assignment = TV.wrap ~loc:u.meta (`Type(name, value)) in
ok (env, ass)
)
| `Function(name, type_expression, block) -> (
TT.eval env.type_environment (TT.of_untyped type_expression) >>? fun type_value ->
let env = Typed.Environment.add_variable env "input" type_value in
typecheck_block env block >>? fun (env, block) ->
let ty =
match TV.Environment.get_opt env.value_environment "output" with
| None -> `Unit
| Some x -> x in
let ass : TV.assignment = TV.wrap ~loc:u.meta (`Function(name, type_value, block, ty)) in
ok (env, ass)
)
and typecheck_statement (env:env) (s:Untyped.Value.statement) : (env * Typed.Value.statement) result =
match s.value with
| `Assignment a -> typecheck_assignment env a
| `Condition (_bool_expr, _block, _elseifs, _else_opt) -> simple_fail "conditions aren't supported yet"
| `ForEach _ -> simple_fail "foreach is not supported yet"
| `While _ -> simple_fail "while is not supported yet"
and typecheck_block (env:env) (b:Untyped.Value.block) : (env * Typed.Value.block) result =
let rec aux env = function
| [] -> ok (env, [])
| hd :: tl -> (
typecheck_statement env hd >>? fun (env, hd) ->
aux env tl >>? fun (env, tl) ->
ok (env, hd :: tl)
) in
aux env b.value
let typecheck_program ?(env=Typed.Environment.empty) (u:Untyped.Value.program) : Typed.Value.program result =
let rec aux env = function
| [] -> ok []
| hd :: tl -> (
typecheck_assignment env hd >>? fun (env, hd) ->
aux env tl >>? fun tl ->
ok (hd :: tl)
) in
aux env u.value
end
module Transpile = struct
open Mini_c
open Typed
let rec translate_type : Type.value -> Mini_c.type_value result = function
| `Bool -> ok (`Base Bool)
| `Int -> ok (`Base Int)
| `Nat -> ok (`Base Nat)
| `Unit -> ok (`Base Unit)
| `Pair(a, b) -> (
translate_type a >>? fun a ->
translate_type b >>? fun b ->
ok (`Pair(a, b))
)
| `Or(a, b) -> (
translate_type a >>? fun a ->
translate_type b >>? fun b ->
ok (`Or(a, b))
)
let rec translate_expression (e:Value.expression) : Mini_c.expression result =
let%bind (e' : Mini_c.expression') = match e.value with
| `Constant (`Int n) -> ok (Literal (`Int n))
| `Variable n -> ok (Var n)
| `Pair (a, b) -> (
translate_expression a >>? fun a ->
translate_expression b >>? fun b ->
ok (Predicate("Pair", [a ; b]))
) in
let%bind (t : Mini_c.type_value) = translate_type @@ fst e.meta in
ok (e', t)
let rec translate_assignment (ass:Value.assignment)
: Mini_c.assignment option result = match ass.value with
| `Let(x, expr) -> (
translate_expression expr >>? fun expr ->
ok (Some (Variable(x, expr)))
)
| `Function(name, input_ty, body, output_ty) -> (
translate_type input_ty >>? fun input ->
translate_type output_ty >>? fun output ->
block body >>? fun body ->
let ass = Fun(name, {input ; output ; body}) in
ok (Some ass)
)
| `Type _ -> ok None
and statement (st:Value.statement)
: Mini_c.statement option result =
translate_assignment st >>? fun a ->
let ass = match a with
| Some a -> Some (Assignment a)
| None -> None in
ok ass
and block : Value.block -> Mini_c.block result = function
| [] -> ok []
| hd :: tl -> (
statement hd >>? fun st_opt ->
let sts = match st_opt with
| Some x -> [x]
| None -> [] in
block tl >>? fun (new_sts) ->
ok (sts @ new_sts)
)
let translate_toplevel_statement = translate_assignment
let rec program : Value.program -> Mini_c.program result = function
| [] -> ok []
| hd :: tl -> (
translate_assignment hd >>? fun ass_opt ->
let asss = match ass_opt with
| Some x -> [x]
| None -> [] in
program tl >>? fun (new_asss) ->
ok (asss @ new_asss)
)
let of_mini_c : Mini_c.value -> Value.value result = function
| `Int n -> ok (Value.int n)
| _ -> simple_fail "unknown value"
let to_mini_c : Value.value -> Mini_c.value result = function
| `Constant (`Int n) -> ok (`Int n)
| _ -> simple_fail "unknown value"
let program_to_michelson (p:Value.program) =
let%bind program_mini_c = program p in
let%bind program = Mini_c.Translate_program.translate program_mini_c in
ok program.body
end
module Run = struct
open Typed.Value
let run (program : program) (input : value) : value result =
Transpile.program program >>? fun program_mini_c ->
Transpile.to_mini_c input >>? fun input_mini_c ->
(* Format.printf "%a\n" Mini_c.PP.program program_mini_c ; *)
Mini_c.Run.run program_mini_c input_mini_c >>? fun output_mini_c ->
Transpile.of_mini_c output_mini_c >>? fun output ->
ok output
end

View File

@ -1042,14 +1042,16 @@ module Translate_AST = struct
List.map (rename_declaration src dst) decls List.map (rename_declaration src dst) decls
end end
let list_of_map m = List.rev @@ SMap.fold (fun _ v prev -> v :: prev) m []
let rec translate_type : AST.type_expr -> type_value result = fun {type_expr} -> let rec translate_type : AST.type_expr -> type_value result = fun {type_expr} ->
match type_expr with match type_expr with
| Unit -> ok (`Base Unit) | Unit -> ok (`Base Unit)
| Int -> ok (`Base Int) | Int -> ok (`Base Int)
| String -> ok (`Base String) | String -> ok (`Base String)
| Bool -> ok (`Base Bool) | Bool -> ok (`Base Bool)
| Sum lst -> | Sum m ->
let node = Append_tree.of_list @@ List.map snd lst in let node = Append_tree.of_list @@ List.map snd @@ list_of_map m in
let aux a b : type_value result = let aux a b : type_value result =
let%bind a = a in let%bind a = a in
let%bind b = b in let%bind b = b in
@ -1057,7 +1059,7 @@ module Translate_AST = struct
in in
Append_tree.fold_ne translate_type aux node Append_tree.fold_ne translate_type aux node
| Record r -> | Record r ->
let node = Append_tree.of_list @@ List.map snd r in let node = Append_tree.of_list @@ List.map snd @@ list_of_map r in
let aux a b : type_value result = let aux a b : type_value result =
let%bind a = a in let%bind a = a in
let%bind b = b in let%bind b = b in
@ -1150,8 +1152,8 @@ module Translate_AST = struct
let rec to_mini_c_value' : (AST.expr_case * AST.type_expr) -> value result = function let rec to_mini_c_value' : (AST.expr_case * AST.type_expr) -> value result = function
| Constant c, _ -> translate_constant c | Constant c, _ -> translate_constant c
| App {arguments;operator = {operator = Construcor c ; ty = {type_expr = Sum lst}}}, _ -> | App {arguments;operator = {operator = Constructor c ; ty = {type_expr = Sum lst}}}, _ ->
let node = Append_tree.of_list @@ List.map fst lst in let node = Append_tree.of_list @@ List.map fst @@ list_of_map lst in
let%bind lst = let%bind lst =
trace_option (simple_error "Not constructor of variant type") @@ trace_option (simple_error "Not constructor of variant type") @@
Append_tree.exists_path (fun (x:AST.name_and_region) -> x.name = c.name) node in Append_tree.exists_path (fun (x:AST.name_and_region) -> x.name = c.name) node in

View File

@ -1,200 +0,0 @@
%{
module Location = Ligo_helpers.Location
open Main.Untyped
open Value
%}
%token EOF
%token <int> INT
//%token <float> FLOAT
%token <string> STRING
%token <string> VAR_NAME
%token <string> FUNCTION_NAME
%token <string> TYPE_NAME
//%token PLUS MINUS TIMES DIV
%token COLON SEMICOLON /* DOUBLE_SEMICOLON */ COMMA AT EQUAL DOT
%token OR AND
%token LPAREN RPAREN
%token LBRACKET RBRACKET
%token IF ELSEIF ELSE // THEN
%token FOREACH OF WHILE
%token LET TYPE FUNCTION
// toto.tata @ 3 + 4 = 2 ; printf (lel)
//%left COLON
%left COMMA
%left AT
%left OR
%left AND
//%left EQUAL
//%left PLUS MINUS /* lowest precedence */
//%left TIMES DIV /* medium precedence */
%left DOT
%start <Main.Untyped.Value.program> main
%%
main:
| sts = assignment+ EOF
{
let loc = Location.make $startpos $endpos in
program ~loc sts
}
assignment:
| LET v = VAR_NAME EQUAL e = expr SEMICOLON
{
let loc = Location.make $startpos $endpos in
let_ ~loc (v, e)
}
| FUNCTION f = VAR_NAME COLON t = type_expr EQUAL b = block SEMICOLON
{
let loc = Location.make $startpos $endpos in
fun_ ~loc (f, t, b)
}
| TYPE n = TYPE_NAME EQUAL t = type_expr SEMICOLON
{
let loc = Location.make $startpos $endpos in
type_ ~loc (n, t)
}
statement:
| ass = assignment
{
let loc = Location.make $startpos $endpos in
assignment ~loc ass
}
| FOREACH var = VAR_NAME OF iterator = expr body = block
{
let loc = Location.make $startpos $endpos in
foreach ~loc (var, iterator, body)
}
| WHILE cond = expr body = block
{
let loc = Location.make $startpos $endpos in
while_ ~loc (cond, body)
}
| IF e = expr b = block eis = else_if* eo = else_?
{
let loc = Location.make $startpos $endpos in
if_ ~loc (e, b, eis, eo)
}
else_if:
| ELSEIF LPAREN cond = expr RPAREN body = block
{
elseif (cond, body)
}
else_:
| ELSE body = block
{
else_ body
}
block:
| LBRACKET sts = statement+ RBRACKET
{
let loc = Location.make $startpos $endpos in
block ~loc sts
}
expr:
| i = INT
{
let loc = Location.make $startpos $endpos in
Value.int ~loc i
}
(*
| f = FLOAT
{
let loc = Location.make $startpos $endpos in
make ~loc @@ literal @@ Float f
}
| s = STRING
{
let loc = Location.make $startpos $endpos in
make ~loc @@ literal @@ String s
}
*)
| v = VAR_NAME
{
let loc = Location.make $startpos $endpos in
variable ~loc v
}
| LPAREN e = expr RPAREN
{
let loc = Location.make $startpos $endpos in
WrapLocation.update_location ~loc e
}
| e1 = expr COMMA e2 = expr
{
let loc = Location.make $startpos $endpos in
Value.pair ~loc (e1, e2)
}
| e1 = expr AT e2 = expr
{
let loc = Location.make $startpos $endpos in
application ~loc (e1, e2)
}
| e1 = expr DOT e2 = expr
{
let loc = Location.make $startpos $endpos in
application ~loc (e2, e1)
}
(*
| e = expr COLON t = type_expr
{
let loc = Location.make $startpos $endpos in
make ~loc @@ cast e t
}
| e1 = expr PLUS e2 = expr
{
let loc = Location.make $startpos $endpos in
make ~loc @@ primitive Plus [e1 ; e2]
}
| e1 = expr MINUS e2 = expr
{
let loc = Location.make $startpos $endpos in
make ~loc @@ primitive Minus [e1 ; e2]
}
| e1 = expr TIMES e2 = expr
{
let loc = Location.make $startpos $endpos in
make ~loc @@ primitive Times [e1 ; e2]
}
| e1 = expr DIV e2 = expr
{
let loc = Location.make $startpos $endpos in
make ~loc @@ primitive Div [e1 ; e2]
}
| e1 = expr EQUAL e2 = expr
{
let loc = Location.make $startpos $endpos in
make ~loc @@ primitive Equal [e1 ; e2]
}
| e = expr DOT v = VAR_NAME
{
let loc = Location.make $startpos $endpos in
make ~loc @@ dot e v
}
*)
type_expr:
| t = TYPE_NAME
{
let loc = Location.make $startpos $endpos in
Type.(name ~loc t)
}
| t1 = type_expr AND t2 = type_expr
{
let loc = Location.make $startpos $endpos in
Type.(pair ~loc t1 t2)
}
| t1 = type_expr OR t2 = type_expr
{
let loc = Location.make $startpos $endpos in
Type.(union ~loc t1 t2)
}

View File

@ -1 +0,0 @@
module Typed = Typecheck2

View File

@ -8,175 +8,158 @@ let test name f =
match f () with match f () with
| Ok () -> () | Ok () -> ()
| Errors errs -> | Errors errs ->
Format.printf "Errors : {\n%a}\n%!" errors_pp errs ; Format.printf "Errors : {\n%a}\n%!" errors_pp errs ;
raise Alcotest.Test_error raise Alcotest.Test_error
open Mini_c open Mini_c
open Combinators open Combinators
let simple_int_program body : program = [ module Mini_c = struct
Fun("main", function_int body)
]
let run_int program n = let simple_int_program body : program = [
Run.run program (`Int n) >>? function Fun("main", function_int body)
| `Int n -> ok n
| _ -> simple_fail "run_int : output not int"
let neg () =
let program : program = simple_int_program [
assign_variable "output" @@ neg_int (var_int "input") ;
assign_variable "output" @@ neg_int (var_int "output") ;
assign_variable "output" @@ neg_int (var_int "output") ;
] in
run_int program 42 >>? fun output ->
Assert.assert_equal_int (-42) output >>? fun () ->
ok ()
let multiple_variables () =
let program = simple_int_program [
assign_variable "a" @@ neg_int (var_int "input") ;
assign_variable "b" @@ neg_int (var_int "a") ;
assign_variable "c" @@ neg_int (var_int "b") ;
assign_variable "d" @@ neg_int (var_int "c") ;
assign_variable "output" @@ neg_int (var_int "d") ;
] in
run_int program 42 >>? fun output ->
Assert.assert_equal_int (-42) output >>? fun () ->
ok ()
let arithmetic () =
let expression = add_int (var_int "input") (neg_int (var_int "input")) in
let program = simple_int_program [
Assignment (Variable ("a", expression)) ;
Assignment (Variable ("b", var_int "a")) ;
Assignment (Variable ("output", var_int "b")) ;
] in
let test n =
run_int program n >>? fun output ->
Assert.assert_equal_int 0 output >>? fun () ->
ok ()
in
let%bind _assert = bind_list @@ List.map test [42 ; 150 ; 0 ; -42] in
ok ()
let quote_ () =
let program = simple_int_program [
assign_function "f" @@ function_int [assign_variable "output" @@ add_int (var_int "input") (int 42)] ;
assign_function "g" @@ function_int [assign_variable "output" @@ neg_int (var_int "input")] ;
assign_variable "output" @@ apply_int (type_f_int @@ var "g") @@ apply_int (type_f_int @@ var "f") (var_int "input") ;
] in
let%bind output = run_int program 42 in
let%bind _ = Assert.assert_equal_int (-84) output in
ok ()
let function_ () =
let program = simple_int_program [
assign_variable "a" @@ int 42 ;
assign_function "f" @@ function_int [assign_variable "output" @@ add_int (var_int "input") (var_int "a")] ;
let env = Environment.Small.of_list ["a", t_int] in
assign_variable "output" @@ apply_int (type_closure_int env @@ var "f") (var_int "input") ;
] in
let%bind output = run_int program 100 in
let%bind _ = Assert.assert_equal_int 142 output in
ok ()
let functions_ () =
let program = simple_int_program [
assign_variable "a" @@ int 42 ;
assign_variable "b" @@ int 144 ;
assign_function "f" @@ function_int [
assign_variable "output" @@ add_int (var_int "input") (var_int "a")
] ;
assign_function "g" @@ function_int [
assign_variable "output" @@ add_int (var_int "input") (var_int "b")
] ;
let env_f = Environment.Small.of_list ["a", t_int] in
let env_g = Environment.Small.of_list ["b", t_int] in
assign_variable "output" @@ add_int
(apply_int (type_closure_int env_f @@ var "f") (var_int "input"))
(apply_int (type_closure_int env_g @@ var "g") (var_int "input"))
] in
let%bind output = run_int program 100 in
let%bind _ = Assert.assert_equal_int 386 output in
ok ()
let rich_function () =
let program = simple_int_program [
assign_variable "a" @@ int 42 ;
assign_variable "b" @@ int 144 ;
assign_function "f" @@ function_int [assign_variable "output" @@ add_int (var_int "a") (var_int "b")] ;
let env = Environment.Small.of_list [("a", t_int) ; ("b", t_int)] in
assign_variable "output" @@ apply_int (type_closure_int env @@ var "f") (var_int "input") ;
] in
let test n =
let%bind output = run_int program n in
let%bind _ = Assert.assert_equal_int 186 output in
ok () in
let%bind _assert = bind_list @@ List.map test [42 ; 150 ; 0 ; -42] in
ok ()
let main = "Mini_c", [
test "basic.neg" neg ;
test "basic.variables" multiple_variables ;
test "basic.arithmetic" arithmetic ;
test "basic.quote" quote_ ;
test "basic.function" function_ ;
test "basic.functions" functions_ ;
test "basic.rich_function" rich_function ;
] ]
(* module Ligo = struct let run_int program n =
* let parse_file (source:string) : Ligo.Untyped.Value.program result = Run.run program (`Int n) >>? function
* let channel = open_in source in | `Int n -> ok n
* let lexbuf = Lexing.from_channel channel in | _ -> simple_fail "run_int : output not int"
* specific_try (function
* | Parser.Error -> ( let neg () =
* let start = Lexing.lexeme_start_p lexbuf in let program : program = simple_int_program [
* let end_ = Lexing.lexeme_end_p lexbuf in assign_variable "output" @@ neg_int (var_int "input") ;
* let str = Format.sprintf assign_variable "output" @@ neg_int (var_int "output") ;
* "Parse error at \"%s\" from (%d, %d) to (%d, %d)\n" assign_variable "output" @@ neg_int (var_int "output") ;
* (Lexing.lexeme lexbuf) ] in
* start.pos_lnum (start.pos_cnum - start.pos_bol) run_int program 42 >>? fun output ->
* end_.pos_lnum (end_.pos_cnum - end_.pos_bol) in Assert.assert_equal_int (-42) output >>? fun () ->
* simple_error str ok ()
* )
* | Lexer.Unexpected_character s -> simple_error s let multiple_variables () =
* | Lexer.Error _ -> simple_error "lexer error" let program = simple_int_program [
* | _ -> simple_error "unrecognized parse_ error" assign_variable "a" @@ neg_int (var_int "input") ;
* ) @@ (fun () -> Parser.main Lexer.token lexbuf) >>? fun program_ast -> assign_variable "b" @@ neg_int (var_int "a") ;
* ok program_ast assign_variable "c" @@ neg_int (var_int "b") ;
* assign_variable "d" @@ neg_int (var_int "c") ;
* let run (source:string) (input:Ligo.Typed.Value.value) : Ligo.Typed.Value.value result = assign_variable "output" @@ neg_int (var_int "d") ;
* parse_file source >>? fun program_ast -> ] in
* Ligo.Typecheck.typecheck_program program_ast >>? fun typed_program -> run_int program 42 >>? fun output ->
* Ligo.Run.run typed_program input >>? fun output -> Assert.assert_equal_int (-42) output >>? fun () ->
* ok output ok ()
*
* let assert_value_int : Ligo.Typed.Value.value -> int result = function let arithmetic () =
* | `Constant (`Int n) -> ok n let expression = add_int (var_int "input") (neg_int (var_int "input")) in
* | _ -> simple_fail "not an int" let program = simple_int_program [
* Assignment (Variable ("a", expression)) ;
* let basic () : unit result = Assignment (Variable ("b", var_int "a")) ;
* run "./contracts/toto.ligo" (Ligo.Typed.Value.int 42) >>? fun output -> Assignment (Variable ("output", var_int "b")) ;
* assert_value_int output >>? fun output -> ] in
* Assert.assert_equal_int 42 output >>? fun () -> let test n =
* ok () run_int program n >>? fun output ->
* Assert.assert_equal_int 0 output >>? fun () ->
* let display_basic () : unit result = ok ()
* parse_file "./contracts/toto.ligo" >>? fun program_ast -> in
* Ligo.Typecheck.typecheck_program program_ast >>? fun typed_program -> let%bind _assert = bind_list @@ List.map test [42 ; 150 ; 0 ; -42] in
* Ligo.Transpile.program_to_michelson typed_program >>? fun node -> ok ()
* let node = Tezos_utils.Cast.flatten_node node in
* let str = Tezos_utils.Cast.node_to_string node in let quote_ () =
* Format.printf "Program:\n%s\n%!" str ; let program = simple_int_program [
* ok () assign_function "f" @@ function_int [assign_variable "output" @@ add_int (var_int "input") (int 42)] ;
* assign_function "g" @@ function_int [assign_variable "output" @@ neg_int (var_int "input")] ;
* let main = "Ligo", [ assign_variable "output" @@ apply_int (type_f_int @@ var "g") @@ apply_int (type_f_int @@ var "f") (var_int "input") ;
* test "basic" basic ; ] in
* test "basic.display" display_basic ; let%bind output = run_int program 42 in
* ] let%bind _ = Assert.assert_equal_int (-84) output in
* end *) ok ()
let function_ () =
let program = simple_int_program [
assign_variable "a" @@ int 42 ;
assign_function "f" @@ function_int [assign_variable "output" @@ add_int (var_int "input") (var_int "a")] ;
let env = Environment.Small.of_list ["a", t_int] in
assign_variable "output" @@ apply_int (type_closure_int env @@ var "f") (var_int "input") ;
] in
let%bind output = run_int program 100 in
let%bind _ = Assert.assert_equal_int 142 output in
ok ()
let functions_ () =
let program = simple_int_program [
assign_variable "a" @@ int 42 ;
assign_variable "b" @@ int 144 ;
assign_function "f" @@ function_int [
assign_variable "output" @@ add_int (var_int "input") (var_int "a")
] ;
assign_function "g" @@ function_int [
assign_variable "output" @@ add_int (var_int "input") (var_int "b")
] ;
let env_f = Environment.Small.of_list ["a", t_int] in
let env_g = Environment.Small.of_list ["b", t_int] in
assign_variable "output" @@ add_int
(apply_int (type_closure_int env_f @@ var "f") (var_int "input"))
(apply_int (type_closure_int env_g @@ var "g") (var_int "input"))
] in
let%bind output = run_int program 100 in
let%bind _ = Assert.assert_equal_int 386 output in
ok ()
let rich_function () =
let program = simple_int_program [
assign_variable "a" @@ int 42 ;
assign_variable "b" @@ int 144 ;
assign_function "f" @@ function_int [assign_variable "output" @@ add_int (var_int "a") (var_int "b")] ;
let env = Environment.Small.of_list [("a", t_int) ; ("b", t_int)] in
assign_variable "output" @@ apply_int (type_closure_int env @@ var "f") (var_int "input") ;
] in
let test n =
let%bind output = run_int program n in
let%bind _ = Assert.assert_equal_int 186 output in
ok () in
let%bind _assert = bind_list @@ List.map test [42 ; 150 ; 0 ; -42] in
ok ()
let main = "Mini_c", [
test "basic.neg" neg ;
test "basic.variables" multiple_variables ;
test "basic.arithmetic" arithmetic ;
test "basic.quote" quote_ ;
test "basic.function" function_ ;
test "basic.functions" functions_ ;
test "basic.rich_function" rich_function ;
]
end
module Ligo = struct
let run (source:string) (input:Ligo.Typed.O.value) : Ligo.Typed.Value.value result =
parse_file source >>? fun program_ast ->
Ligo.Typecheck.typecheck_program program_ast >>? fun typed_program ->
Ligo.Run.run typed_program input >>? fun output ->
ok output
let assert_value_int : Ligo.Typed.Value.value -> int result = function
| `Constant (`Int n) -> ok n
| _ -> simple_fail "not an int"
let basic () : unit result =
run "./contracts/toto.ligo" (Ligo.Typed.Value.int 42) >>? fun output ->
assert_value_int output >>? fun output ->
Assert.assert_equal_int 42 output >>? fun () ->
ok ()
let display_basic () : unit result =
parse_file "./contracts/toto.ligo" >>? fun program_ast ->
Ligo.Typecheck.typecheck_program program_ast >>? fun typed_program ->
Ligo.Transpile.program_to_michelson typed_program >>? fun node ->
let node = Tezos_utils.Cast.flatten_node node in
let str = Tezos_utils.Cast.node_to_string node in
Format.printf "Program:\n%s\n%!" str ;
ok ()
let main = "Ligo", [
test "basic" basic ;
test "basic.display" display_basic ;
]
end
let () = let () =
(* Printexc.record_backtrace true ; *) (* Printexc.record_backtrace true ; *)

138
src/ligo/type_ast.ml Normal file
View File

@ -0,0 +1,138 @@
open Ligo_helpers.Trace
module I = Ast_simplified
module O = Ast_typed
module SMap = O.SMap
module Environment = struct
type t = unit
let empty : t = ()
let get (():t) (_s:string) : O.type_value option = None
let add (():t) (_s:string) (_tv:O.type_value) : t = ()
let get_type (():t) (_s:string) : O.type_value option = None
let add_type (():t) (_s:string) (_tv:O.type_value) : t = ()
end
type environment = Environment.t
type environment = unit
let empty : environment = ()
let rec type_program (p:I.program) : O.program result =
let aux (e, acc:(environment * O.declaration list)) (d:I.declaration) =
let%bind (e', d') = type_declaration e d in
match d' with
| None -> ok (e', acc)
| Some d' -> ok (e', d' :: acc)
in
let%bind (_, lst) = bind_fold_list aux (empty, []) p in
ok @@ List.rev lst
and type_declaration _env : I.declaration -> (environment * O.declaration option) result = function
| Type_declaration _ -> simple_fail ""
| Constant_declaration _ -> simple_fail ""
and type_block (e:environment) (b:I.block) : O.block result =
let aux (e, acc:(environment * O.instruction list)) (i:I.instruction) =
let%bind (e', i') = type_instruction e i in
ok (e', i' :: acc)
in
let%bind (_, lst) = bind_fold_list aux (e, []) b in
ok @@ List.rev lst
and type_instruction (e:environment) : I.instruction -> (environment * O.instruction) result = function
| Skip -> ok (e, O.Skip)
| Fail x ->
let%bind expression = type_annotated_expression e x in
ok (e, O.Fail expression)
| Loop (cond, body) ->
let%bind cond = type_annotated_expression e cond in
let%bind _ =
O.type_value_eq (cond.type_annotation, (O.Type_constant ("bool", []))) in
let%bind body = type_block e body in
ok (e, O.Loop (cond, body))
| Assignment {name;annotated_expression} -> (
match annotated_expression.type_annotation, Environment.get e name with
| None, None -> simple_fail "Initial assignments need type"
| Some _, None ->
let%bind annotated_expression = type_annotated_expression e annotated_expression in
let e' = Environment.add e name annotated_expression.type_annotation in
ok (e', O.Assignment {name;annotated_expression})
| None, Some prev ->
let%bind annotated_expression = type_annotated_expression e annotated_expression in
let e' = Environment.add e name annotated_expression.type_annotation in
let%bind _ =
O.type_value_eq (annotated_expression.type_annotation, prev) in
ok (e', O.Assignment {name;annotated_expression})
| Some _, Some prev ->
let%bind annotated_expression = type_annotated_expression e annotated_expression in
let%bind _assert = trace (simple_error "Annotation doesn't match environment")
@@ O.type_value_eq (annotated_expression.type_annotation, prev) in
let e' = Environment.add e name annotated_expression.type_annotation in
ok (e', O.Assignment {name;annotated_expression})
)
| Matching m ->
let%bind m' = type_match e m in
ok (e, O.Matching m')
and type_match (e:environment) : I.matching -> O.matching result = function
| Match_bool {match_true ; match_false} ->
let%bind match_true = type_block e match_true in
let%bind match_false = type_block e match_false in
ok (O.Match_bool {match_true ; match_false})
| Match_option {match_none ; match_some} ->
let%bind match_none = type_block e match_none in
let (n, b) = match_some in
let%bind b' = type_block e b in
ok (O.Match_option {match_none ; match_some = (n, b')})
| Match_list {match_nil ; match_cons} ->
let%bind match_nil = type_block e match_nil in
let (n, m, b) = match_cons in
let%bind b' = type_block e b in
ok (O.Match_list {match_nil ; match_cons = (n, m, b')})
| Match_tuple lst ->
let aux (x, y) =
let%bind y = type_block e y in
ok (x, y) in
let%bind lst' = bind_list @@ List.map aux lst in
ok (O.Match_tuple lst')
and evaluate_type (e:environment) : I.type_expression -> O.type_value result = function
| Type_tuple lst ->
let%bind lst' = bind_list @@ List.map (evaluate_type e) lst in
ok (O.Type_tuple lst')
| Type_sum m ->
let aux k v prev =
let%bind prev' = prev in
let%bind v' = evaluate_type e v in
ok @@ SMap.add k v' prev'
in
let%bind m = SMap.fold aux m (ok SMap.empty) in
ok (O.Type_sum m)
| Type_record m ->
let aux k v prev =
let%bind prev' = prev in
let%bind v' = evaluate_type e v in
ok @@ SMap.add k v' prev'
in
let%bind m = SMap.fold aux m (ok SMap.empty) in
ok (O.Type_record m)
| Type_variable name ->
let%bind tv =
trace_option (simple_error "unbound type variable")
@@ Environment.get_type e name in
ok tv
| Type_constant (cst, lst) ->
let%bind lst' = bind_list @@ List.map (evaluate_type e) lst in
ok (O.Type_constant(cst, lst'))
and type_annotated_expression (e:environment) (ae:I.annotated_expression) : O.annotated_expression result =
match ae.expression with
| Variable name ->
let%bind tv' =
trace_option (simple_error "var not in env")
@@ Environment.get e name in
ok O.{expression = Variable name ; type_annotation = tv'}
| _ -> simple_fail "default"