Use Cases
Most of these tools (including the compiler itself) benefit from occasional annotations to locally modify the behavior out of the default. Comments are currently used for this purpose (or coarser-grained command-line options or, in the case of mascot, a separate configuration file that annotates precise locations with information).
let f x =
match List.map foo [x; a x; b x] with
| [y1; y2; y3] -> tata
| _ -> (*BISECT-VISIT*) assert false
(*BISECT-IGNORE-BEGIN*)
let unused = ()
(*BISECT-IGNORE-END*)
Of course, ocamldoc could also seen as such a tool. The way it attaches documentation comments to specific part of code right now is not robust enough and a source of problems for pre-processed code, so having a formal annotation mechanism where meaningful documentation comments are semantically attached to the relevant AST nodes would be a huge plus.
val stats : ('a, 'b) t -> statistics
(** [Hashtbl.stats tbl] returns statistics about the table [tbl]:
number of buckets, size of the biggest bucket, distribution of
buckets by size.
@since 4.00.0 *)
(** {6 Functorial interface} *)
module type HashedType =
sig
type t
(** The type of the hashtable keys. *)
val equal : t -> t -> bool
(** The equality predicate used to compare keys. *)
end
BARISTA_ERROR =
| O -> "o"
| A of (x : int) -> Printf.sprintf "%d" x
| B of (y : float) * (z : string) * (t : char)-> Printf.sprintf "%f %S %C" y z t
type-conv (bin_prot, sexplib...)
deriving
type t = {
x : int with default(42);
y : int with default(3), sexp_drop_default;
z : int with default(3), sexp_drop_if(z_test);
} with sexp
type r1 = {
r1_l1 : int;
r1_l2 : int;
} deriving (Dump, Eq, Show, Typeable, Pickle, Functor)
Lexifi's attribute system
type my_type @@ [with_xml] =
| A of int
| B of string @@ {xml=base64}
| C @@ {xml=ignore}
Camlp4 map/fold generators
type variable = string
and term =
| Var of variable
| Lam of variable * term
| App of term * term
class map = Camlp4Filters.GenerateMap.generated
Code generation based on module signatures: ocaml-rpc
(* Example IDL *)
type return_record = {
result : string;
metadata : (int * int) list;
}
type variant =
| Foo of string list
| Bar
| Baz of float
external rpc1 : arg1:string -> int -> return_record = ""
external rpc2 : ?opt:string -> variant -> unit = ""
external rpc3 : int64 -> int64 = ""
module SubModule = struct
external rpc4 : int64 -> int64 = ""
end
local open (now in the language)
let open M in foo
perform
a <-- [1; 2; 3];
b <-- [3; 4; 5];
return (a + b)
lwt x = start_thread foo in
and y = start_other_thread foo in
try_lwt
for_lwt (x, y) in waiting_threads do
compute blah
done
with Killed -> bar
let funct n =
LOG "funct(%d)" n LEVEL DEBUG;
for i = 1 to n do
print_endline "..."
done
let r = {| x = 1; y = ref None |} (* x and y are immutable, but y is a ref which is mutable *)
let () = r..y <- Some 2 (* update the ref at y *)
"variable123"
|! $/^[0-9]+$/ as v -> `Int (int_of_string v#_0)
| $/^[a-z][A-Za-z0-9_]*$/ as v -> `Variable v#_0
| _ -> failwith "parse error";;
let bits = Bitstring.bitstring_of_file "/bin/ls" in
bitmatch bits with
| { 0x7f : 8; "ELF" : 24 : string; (* ELF magic number *)
e_ident : 12*8 : bitstring; (* ELF identifier *)
e_type : 16 : littleendian; (* object file type *)
e_machine : 16 : littleendian (* architecture *)
} ->
printf "This is an ELF binary, type %d, arch %d\n"
e_type e_machine;
let '0'..'9' as digit = SEDLEX.regexp
let (Plus digit) as number = SEDLEX.regexp
let rec token buf =
let ('a'..'z'|'A'..'Z') as letter = SEDLEX.regexp in
match SEDLEX buf with
| number -> Printf.printf "Number %s\n" (Sedlexing.Latin1.lexeme buf); token buf
| letter, Star ('A'..'Z' | 'a'..'z' | digit) -> Printf.printf "Ident %s\n" (Sedlexing.Latin1.lexeme buf); token buf
| Plus xml_blank -> token buf
| Plus (Chars "+*-/") -> Printf.printf "Op %s\n" (Sedlexing.Latin1.lexeme buf); token buf
| Range(128,255) -> print_endline "Non ASCII"
| eof -> print_endline "EOF"
| _ -> failwith "Unexpected character"
modified sedlex (imaginary, following as per the wg-camlp4 discussions)
let rec token buf =
(:sedlex
let%regexp letter = ('a'..'z'|'A'..'Z') in
match%lexer buf with
| number -> Printf.printf "Number %s\n" (Sedlexing.Latin1.lexeme buf); token buf
| letter, Star ('A'..'Z' | 'a'..'z' | digit) -> Printf.printf "Ident %s\n" (Sedlexing.Latin1.lexeme buf); token buf
| Plus xml_blank -> token buf
| Plus (Chars "+*-/") -> Printf.printf "Op %s\n" (Sedlexing.Latin1.lexeme buf); token buf
| Range(128,255) -> print_endline "Non ASCII"
| eof -> print_endline "EOF"
| _ -> failwith "Unexpected character"
)
#ifdef DEBUG
#define debug(s) Printf.eprintf "[%S %i] %s\n%!" __FILE__ __LINE__ s
#else
#define debug(s) ()
#endif
debug("test")
# RE pair = "(" space* (digit+ as x : int) space* ","
space* (digit+ as y : int) space* ")";;
# let get_objlist = COLLECTOBJ pair;;
val get_objlist : ?pos:int -> string -> < x : int; y : int > list = <fun>
# let objlist = get_objlist "(123,456): (a,2) ( 5, 34) (0, 0)";;
val objlist : < x : int; y : int > list = [<obj>; <obj>; <obj>]
let fetch_users dbh =
PGSQL(dbh) "select id, name from users"
let names view = <:view< {name = t.name} | t in $view$ >>
let listing = display
let todo x = "{par}{huge "{textbf "TODO:"} {x}"}{par}"
let doc = ("
{tableofcontents}
{newpage}
")
let button = <:css<
.button {
$Css.gradient ~low:color2 ~high:color1$;
color: white;
$Css.top_rounded$;
>>
Camlp4/Fan
<:patt< Func($str:x$, $t$) >>
Quotation in Fan
Quotations in Fan mainly refer to
- Delimited Language Extensions
- QuasiQuotation (the same as Lisp)
Examples: First class lexer(toplevel support)
let rec token enc = {:lex|
"<utf8>" -> begin enc := Ulexing.Utf8; token enc lexbuf end
| "<latin1>" -> begin enc := Ulexing.Latin1; token enc lexbuf end
| xml_letter+ -> Printf.sprintf "word(%s)" (Ulexing.utf8_lexeme lexbuf)
| number -> "number"
| eof -> exit 0
| [1234-1246] -> "bla"
| "(" -> begin
Ulexing.rollback lexbuf; (* Puts the lexeme back into the buffer *)
{| "(" [^ '(']* ")" -> Ulexing.utf8_lexeme lexbuf |} lexbuf
(* Note the use of an inline lexer *)
end
| "(*" -> begin comment lexbuf; "comment" end
| ' ' -> "whitespace"
| _ -> "???" |}
and comment = {:lex|
"*)" -> ()
| eof -> failwith "comment"
| _ -> let _lexeme = Ulexing.lexeme lexbuf in
comment lexbuf |}
First class Grammar
{:extend.create|Gram expr_eoi expr|};
{:extend|
expr:
{"minus" LA
[S{x};"-";S{y} -> x -. y
|S{x};"+";S{y} -> x +. y]
"times" LA
[S{x};"*";S{y} -> x *. y
|S{x};"/";S{y} -> x /. y]
"power" RA
[S{x};"**";S{y} -> x ** y]
"simple"
["("; S{x}; ")" -> x
| `INT(x,_) -> float_of_int x ] }
expr_eoi: [expr{x};`EOI -> x ]
|}
First class program as data
(* namespace Fan.Lang.Meta *)
{:expr|
let a = b + c
|}
deriving mechanism in Fan
{:ocaml|
type u = A of int
|}
(*namespace Fan.Lang.Derive*)
{:derive| (Print,Eq,OPrint,OEq,MetaExpr,MetaPatt)|}
let rec fac n =
Num.(if n = 0 then 1 else n * fac(n-1))
Int64.(float(q * of_int n - (s * s) lsr 3)) /. float n
Complex.(log(z + 2I) = I / u)