Setepenre pushed to branch master at Stefan / Typer
Commits: 642376ae by Pierre Delaunay at 2016-06-25T18:16:01-04:00 Context accessors and Monad handling. modified travis script
Changes to be committed: *.travis.yml * src/debruijn.ml: - new function (get_attribute) - new function (has_attribute) - modify calling convention of (add_attribute) (better consistency) * btl/types.typer - added builtin context accessors (decltype) and (declexpr) * src/eval.ml - fix monad handling * src/lparse.ml - added context accessor as builtin macro
- - - - -
9 changed files:
- − - - .travis.yml - btl/types.typer - src/builtin.ml - src/debruijn.ml - src/env.ml - src/eval.ml - src/lparse.ml - − w_file
Changes:
===================================== - deleted ===================================== --- a/- +++ /dev/null
===================================== .travis.yml ===================================== --- a/.travis.yml +++ b/.travis.yml @@ -3,16 +3,11 @@ language: ocaml env: - OCAML_VERSION=4.02
-addons: - apt: - packages: - - opam - -before_script: - - opam config setup -a - - opam config env +sudo: true
before_script: + - sudo apt-get -qq update + - sudo apt-get install opam - opam config setup -a - opam config env
===================================== btl/types.typer ===================================== --- a/btl/types.typer +++ b/btl/types.typer @@ -27,6 +27,7 @@ %* %* Description: %* Define builtin types and functions +%* This file MUST be correctly typed %* %* ---------------------------------------------------------------------------
@@ -34,12 +35,14 @@ % Base Types % -----------------------------------------------------
-Type = Built-in "Type"; -Int = Built-in "Int"; -Float = Built-in "Float"; -String = Built-in "String"; -Sexp = Built-in "Sexp"; -Unit = Built-in "Unit"; +Type = Built-in "Type"; +Int = Built-in "Int"; +Float = Built-in "Float"; +String = Built-in "String"; +Sexp = Built-in "Sexp"; + +Unit = Built-in "Unit"; % Nothing +Context = Built-in "Context"; % Lexp Context
% Basic operators _+_ = Built-in "_+_" (Int -> Int -> Int); @@ -151,12 +154,17 @@ Attribute = Built-in "Attribute"; new-attribute = Built-in "new-attribute" (Type -> Attribute);
add-attribute = Built-in "add-attribute" (Sexp -> Sexp -> Sexp -> List Sexp); +attribute = Macro_ add-attribute;
+get-attribute = Built-in "get-attribute" (String -> Attribute); +has-attribute = Built-in "has-attribute" (String -> Attribute -> Bool);
+% ----------------------------------------------------- +% Context Accessors +% -----------------------------------------------------
- - - +decltype = Built-in "decltype" Macro; +declexpr = Built-in "declexpr" Macro;
===================================== src/builtin.ml ===================================== --- a/src/builtin.ml +++ b/src/builtin.ml @@ -243,12 +243,12 @@ let open_impl loc args_val ctx = | [Vstring(file_name); Vstring(mode)] -> file_name, mode | _ -> builtin_error loc "open expects 2 strings" in
- (* open file *) (* return a file handle *) - match mode with - | "r" -> Vin(open_in file) - | "w" -> Vout(open_out file) - | _ -> builtin_error loc "wrong open mode" - + (* open file *) (* return a file handle *) + Vcommand(fun () -> + match mode with + | "r" -> Vin(open_in file) + | "w" -> Vout(open_out file) + | _ -> builtin_error loc "wrong open mode")
let read_impl loc args_val ctx =
@@ -256,7 +256,7 @@ let read_impl loc args_val ctx = | [Vin(c); _] -> c | _ -> List.iter (fun v -> value_print v; print_string "\n") args_val; - builtin_error loc "read expects a in_channel" in + builtin_error loc "read expects an in_channel" in
let line = input_line channel in Vstring(line) @@ -267,15 +267,11 @@ let write_impl loc args_val ctx = | [Vout(c); Vstring(msg)] -> c, msg | _ -> List.iter (fun v -> value_print v) args_val; - builtin_error loc "read expects a out_channel" in + builtin_error loc "read expects an out_channel" in
fprintf channel "%s" msg; Vdummy
-let new_attribute loc args_val ctx = - builtin_warning loc "new-attributes to be implemented"; - Vdummy -
(* * Should we have a function that
===================================== src/debruijn.ml ===================================== --- a/src/debruijn.ml +++ b/src/debruijn.ml @@ -158,7 +158,7 @@ let _env_lookup ctx (v: vref): env_elem = let env_lookup_type ctx (v : vref): lexp = let (_, idx) = v in let (_, _, _, ltp) = _env_lookup ctx v in - mkSusp ltp (S.shift (idx + 1)) + mkSusp ltp (S.shift (idx + 0))
let env_lookup_expr ctx (v : vref): lexp = let (_, idx) = v in @@ -208,7 +208,7 @@ let replace_by ctx name by = (* -------------------------------------------------------------------------- *)
-let add_property ctx (var_n, var_i) (att_n, att_i) (prop: lexp) +let add_property ctx (var_i, var_n) (att_i, att_n) (prop: lexp) : lexp_context =
let (a, b, property_map) = ctx in @@ -226,6 +226,31 @@ let add_property ctx (var_n, var_i) (att_n, att_i) (prop: lexp)
(a, b, property_map)
+let get_property ctx (var_i, var_n) (att_i, att_n): lexp = + let (a, b, property_map) = ctx in + let n = get_size ctx in + + (* /!\ input index are reversed or not ? I think not so I shift them *) + let pmap = try PropertyMap.find (n - var_i, var_n) property_map + with Not_found -> + debruijn_error dummy_location ("Variable "" ^ var_n ^ "" does not have any properties") in + + let prop = try PropertyMap.find (n - att_i, att_n) pmap + with Not_found -> + debruijn_error dummy_location ("Property "" ^ att_n ^ "" not found") in + mkSusp prop (S.shift (var_i + 1)) + + +let has_property ctx (var_i, var_n) (att_i, att_n): bool = + let (a, b, property_map) = ctx in + let n = get_size ctx in + + try + let pmap = PropertyMap.find (n - var_i, var_n) property_map in + let prop = PropertyMap.find (n - att_i, att_n) pmap in + true + with Not_found -> false +
let dump_properties ctx = let (a, b, property_map) = ctx in
===================================== src/env.ml ===================================== --- a/src/env.ml +++ b/src/env.ml @@ -49,6 +49,7 @@ let env_error loc msg =
let str_idx idx = "[" ^ (string_of_int idx) ^ "]"
+ type value_type = | Vint of int | Vstring of string @@ -61,7 +62,8 @@ type value_type = | Vdummy | Vin of in_channel | Vout of out_channel - | Vbind of elexp list + | Vcommand of (unit -> value_type) +
let rec value_print (vtp: value_type) = match vtp with @@ -81,11 +83,7 @@ let rec value_print (vtp: value_type) = | Vdummy -> print_string "value_print_dummy" | Vin _ -> print_string "in_channel" | Vout _ -> print_string "out_channel" - | Vbind [a; b] -> print_string "bind ("; - elexp_print a; print_string ") ("; - elexp_print b; print_string ")"; - - | Vbind _ -> print_string "bind" + | Vcommand _ -> print_string "command" (* | _ -> print_string "debug print" *)
let value_location (vtp: value_type) = @@ -108,7 +106,7 @@ let value_name v = | Vdummy -> "Vdummy" | Vin _ -> "Vin" | Vout _ -> "Vout" - | Vbind _ -> "Vbind" + | Vcommand _ -> "Vcommand"
(* Runtime Environ *) type env_cell = (string option * value_type) ref
===================================== src/eval.ml ===================================== --- a/src/eval.ml +++ b/src/eval.ml @@ -102,7 +102,7 @@ let rec _eval lxp ctx i: (value_type) = -> (eval_case ctx i loc target pat dflt)
| _ -> print_string "debug catch-all eval: "; - elexp_print lxp; print_string "\n"; Vstring("eval Not Implemented") + elexp_print lxp; print_string "\n"; Vdummy
and get_predef_eval name ctx = @@ -144,12 +144,8 @@ and eval_call ctx i lname eargs = eval_error loc "Cannot eval function" in
(* eval function here *) - match f with - (* Does not eval args *) - | Vbuiltin ("bind") -> Vbind eargs - | _ -> - let args = List.map (fun e -> _eval e ctx (i + 1)) eargs in - eval_call f args ctx + let args = List.map (fun e -> _eval e ctx (i + 1)) eargs in + eval_call f args ctx
and eval_case ctx i loc target pat dflt = (* Eval target *) @@ -249,30 +245,42 @@ and bind_impl loc args_val ctx = | [io; callback] -> io, callback | _ -> builtin_error loc "bind expects two arguments" in
+ (* build Vcommand from io function *) + let cmd = match io with + | Vcommand (cmd) -> cmd + | _ -> builtin_error loc "bind first arguments must be a monad" in + + (* bind return another Vcommand *) + Vcommand (fun () -> (* get callback *) - let body, ctx = match cb with - | Closure(_, body, ctx) -> body, ctx - | _ -> builtin_error loc "A Closure was expected" in + let body, ctx = match cb with + | Closure(_, body, ctx) -> body, ctx + | _ -> builtin_error loc "A Closure was expected" in + + (* run given command *) + let underlying = cmd () in
(* add evaluated IO to arg list *) - let nctx = add_rte_variable None io ctx in + let nctx = add_rte_variable None underlying ctx in
(* eval callback *) - _eval body nctx 0 + _eval body nctx 0)
and run_io loc args_val ctx =
- let io, callback = match args_val with - | [Vbind([io; callback])] -> io, callback - | _ -> builtin_error loc "run-io expects a single Vbind argument" in + let io, ltp = match args_val with + | [io; ltp] -> io, ltp + | _ -> builtin_error loc "run-io expects 2 arguments" in + + let cmd = match io with + | Vcommand (cmd) -> cmd + | _ -> builtin_error loc "run-io expects a monad as first argument" in
- (* eval args *) - let io = _eval io ctx 0 in - let callback = _eval callback ctx 0 in + (* run given command *) + let _ = cmd () in
- (* eval bind *) - let a = bind_impl loc [io; callback] ctx in - get_predef_eval "Unit" ctx + (* return given type *) + ltp
and typer_eval loc args ctx = let arg = match args with
===================================== src/lparse.ml ===================================== --- a/src/lparse.ml +++ b/src/lparse.ml @@ -513,7 +513,46 @@ and lexp_call (fun_name: pexp) (sargs: sexp list) ctx i = let new_args = List.map (fun g -> (Aexplicit, g)) largs in Call(body, new_args), ltp
- (* attribute *) + (* Context acessor *) + | Pvar(l, "decltype"), _ -> + let pargs = List.map pexp_parse sargs in + let largs = _lexp_parse_all pargs ctx i in + let (vi, vn) = match largs with + | [Var((_, vn), vi)] -> (vi, vn) + | _ -> lexp_fatal l "decltype expects one argument" in + + let ltype = env_lookup_type ctx ((dloc, vn), vi) in + (* mkSusp prop (S.shift (var_i + 1)) *) + ltype, dltype + + | Pvar(l, "declexpr"), _ -> + let pargs = List.map pexp_parse sargs in + let largs = _lexp_parse_all pargs ctx i in + let (vi, vn) = match largs with + | [Var((_, vn), vi)] -> (vi, vn) + | _ -> lexp_fatal l "declexpr expects one argument" in + + let lxp = env_lookup_expr ctx ((dloc, vn), vi) in + let ltp = env_lookup_type ctx ((dloc, vn), vi) in + lxp, ltp + + (* attributes are special case they does not exist after lexp_parsing + * in that respect they are quite similar to macros *) + | Pvar(l, "get-attribute"), _ -> + let pargs = List.map pexp_parse sargs in + let largs = _lexp_parse_all pargs ctx i in + let (vi, vn), (ai, an) = match largs with + | [Var((_, vn), vi); Var((_, an), ai)] -> (vi, vn), (ai, an) + | _ -> lexp_fatal l "get-attribute expects two arguments" in + + let lxp = get_property ctx (vi, vn) (ai, an) in + let ltype = env_lookup_expr ctx ((dloc, an), ai) in + lxp, ltype + + (* + | Pvar(l, "has-attribute"), _ -> *) + + | Pvar(l, "new-attribute"), _ -> let pargs = List.map pexp_parse sargs in let largs = _lexp_parse_all pargs ctx i in @@ -660,7 +699,7 @@ and lexp_decls_macro (loc, mname) sargs ctx: (pdecl list * lexp_context) =
(* extract info *) let var, att, fn = match largs with - | [Var((_, vn), vi); Var((_, an), ai); fn] -> (vn, vi), (an, ai), fn + | [Var((_, vn), vi); Var((_, an), ai); fn] -> (vi, vn), (ai, an), fn | _ -> lexp_fatal loc "add-attribute expects 3 args" in
let ctx = add_property ctx var att fn in
===================================== w_file deleted ===================================== --- a/w_file +++ /dev/null
View it on GitLab: https://gitlab.com/monnier/typer/commit/642376aeff2e3cf8d5fc0d8685406009f6d8...
Afficher les réponses par date
(* Context acessor *)
| Pvar(l, "decltype"), _ ->
Les "context accessors" devraient être des fonctions, donc ils ne devraient pas affecter Pexp ou parse_lexp.
new calling convention for builtin functions (location -> int -> value_type list -> runtime_env -> value_type)
Pourquoi une fonction builtin pourrait-elle avoir besoin de runtime_env (ou de "location" ou de (depth) "int")?
Stefan
loc est utilisé si une erreur a lieu. Mauvais nombre d'argument/Mauvais type, normalement le système de type devrait pouvoir nous assurer qu'aucune erreur ne vas avoir lieu mais pour l'instant l'information est utile pour le débogage. De plus, lorsque les arguments sont extraits ocaml imprimerait un warning "macth not exhaustive" si le cas impossible n'était pas géré.
Je pense qu'aucune fonction n'utilise le contexte en ce moment. il avait utilisé dans une ancienne implémentation des builtins lorsque les arguments des builtins étaient stockés dans le contexte.
depth est la profondeur de récursion de l'évaluateur. Il est utilisé pour imprimer la call trace de l'évaluateur. Avant lorsqu'un builtin était appelé s'il utilisais l’évaluateur la profondeur revenait à 0 ce qui rendait la calltrace moins lisible.
Pour ce qui est des accesseurs, je ne suis pas sur de comprendre.
Le code suivant:
x = 2; xtype = decltype x;
devrait être transformé (apres lexp_parse) en
x = 2; xtype : Type; xtype = Int;
si decltype est une fonction le code sera transformé en
x = 2; xtype : Type; xtype = Call(Builtin(decltype), [x]);
et la valeur de xtype ne sera connu qu'après évaluation.
loc est utilisé si une erreur a lieu. Mauvais nombre d'argument/Mauvais type, normalement le système de type devrait pouvoir nous assurer qu'aucune erreur ne vas avoir lieu mais pour l'instant l'information est utile pour le débogage. De plus, lorsque les arguments sont extraits ocaml imprimerait un warning "macth not exhaustive" si le cas impossible n'était pas géré.
Ah, je vois. Ce serait mieux que le nombre d'arguments soit testé (et l'erreur signalée) par le code d'eval, plutôt que le code de la fonction.
Je pense qu'aucune fonction n'utilise le contexte en ce moment.
Ah, OK, alors on devrait pouvoir l'enlever.
depth est la profondeur de récursion de l'évaluateur. Il est utilisé pour imprimer la call trace de l'évaluateur. Avant lorsqu'un builtin était appelé s'il utilisais l’évaluateur la profondeur revenait à 0 ce qui rendait la calltrace moins lisible.
Hmm... pourquoi ne pas passer toute la "call stack" dans ce cas, plutôt que juste le "depth"?
Pour ce qui est des accesseurs, je ne suis pas sur de comprendre.
Le code suivant:
x = 2; xtype = decltype x;
devrait être transformé (apres lexp_parse) en
x = 2; xtype : Type; xtype = Int;
si decltype est une fonction le code sera transformé en
En effet, mais decltype ne devrait justement pas être une fonction, mais une macro.
Stefan