modernize Prelude
[sqlgg.git] / src / gen_cxx.ml
blob23f17e7fbdf91b90aafe458a9429f66d71b3b1a1
1 (* C++ code generation *)
3 open ExtLib
4 open Prelude
5 open Printf
7 open Stmt
8 open Gen
9 open Sql
11 module Values = struct
13 let names = List.map fst
14 let join = String.concat ", "
15 let inline = join $ names
16 let to_string = join $ (List.map (fun (n,t) -> t ^ " " ^ n))
18 end
20 let rec freshname name scope =
21 match List.find_all ((=) name) scope with
22 | [] -> name
23 | _ -> freshname (name ^ "_") scope
25 let quote = String.replace_chars (function '\n' -> "\\n\\\n" | '\r' -> "" | '"' -> "\\\"" | c -> String.make 1 c)
26 let quote s = "\"" ^ quote s ^ "\""
28 let quote_comment_inline = String.replace_chars (function '\n' -> "\n// " | c -> String.make 1 c)
29 let comment () fmt = Printf.kprintf (indent_endline $ quote_comment_inline $ (^) "// ") fmt
30 let empty_line () = print_newline ()
31 let open_curly () = output "{"; inc_indent ()
32 let close_curly fmt = dec_indent (); indent "}"; print fmt
33 let start_struct name =
34 output "struct %s" name;
35 open_curly ()
36 let end_struct name =
37 close_curly "; // struct %s" name;
38 empty_line ()
39 let out_public () = dec_indent(); output "public:"; inc_indent()
40 let out_private () = dec_indent(); output "private:"; inc_indent()
42 module L = struct
43 let as_api_type = Type.to_string
44 let as_lang_type t = "typename Traits::" ^ (as_api_type t)
45 end
47 module T = Translate(L)
49 open L
50 open T
52 let column_action action attr index =
53 let typ = as_api_type attr.RA.domain in
54 let name = name_of attr index in
55 output "Traits::%s_column_%s(row, %u, %s);" action typ index name
57 let func head name args ?tail k =
58 let tail = match tail with
59 | Some s -> " " ^ s
60 | None -> ""
62 let head = match head with "" -> "" | s -> s ^ " " in
63 output "%s%s(%s)%s" head name (Values.to_string args) tail;
64 open_curly ();
65 k ();
66 close_curly ""
68 let set_param arg index param =
69 let (id,_) = param in
70 output "Traits::set_param(%s, %s, %u);"
71 (* (param_type_to_string t) *)
72 arg
73 (param_name_to_string id index)
74 index
76 let output_value_defs vals =
77 vals |> List.iter (fun (name,t) -> output "%s %s;" t name)
79 let output_schema_binder _ schema =
80 out_private ();
81 let name = "output" in
82 output "template <class T>";
83 start_struct name;
85 let vals = schema_to_values schema in
86 output_value_defs vals;
87 empty_line ();
89 output "enum { count = %u };" (List.length schema);
90 empty_line ();
92 let mthd action active =
93 func "void" action
94 (["row","typename Traits::row"] @ (if active then ["result","T"] else []))
95 (fun () ->
96 List.iteri (fun index attr -> column_action action attr index) schema;
97 if active then output "result(%s);" (Values.inline vals)
101 mthd "get" true;
102 mthd "bind" false;
104 end_struct name;
105 name
107 let output_schema_binder index schema =
108 match schema with
109 | [] -> None
110 | _ -> Some (output_schema_binder index schema)
112 let make_const_values = List.map (fun (name,t) -> name, sprintf "%s const&" t)
115 let output_schema_data index schema =
116 out_public ();
117 let name = "data" in
118 start_struct name;
119 schema |> schema_to_values |> output_value_defs;
120 end_struct name
123 let value_inits vals =
124 match vals with
125 | [] -> ""
126 | _ -> sprintf ": %s" (String.concat "," (List.map (fun (name,_) -> sprintf "%s(%s)" name name) vals))
128 let struct_params name values k =
129 start_struct name;
130 output_value_defs values;
131 empty_line ();
132 k ();
133 end_struct name
135 let struct_ctor name values k =
136 struct_params name values (fun () ->
137 func "" name values ~tail:(value_inits values) identity;
138 empty_line ();
139 k ())
141 let output_params_binder _ params =
142 out_private ();
143 let name = "params" in
144 let values = params_to_values params in
145 struct_ctor name (make_const_values values) (fun () ->
146 comment () "binding slots in a query (one param may be bound several times)";
147 output "enum { count = %u };" (List.length params);
148 empty_line ();
149 let arg = freshname "target" (name :: Values.names values) in
150 output "template <class T>";
151 func "void" "set_params" [arg,"T&"] (fun () -> List.iteri (set_param arg) params);
152 empty_line ()
154 name
156 let output_params_binder index params =
157 match params with
158 | [] -> "typename Traits::no_params"
159 | _ -> output_params_binder index params
161 type t = unit
163 let start () = ()
165 let make_stmt index stmt =
166 let name = choose_name stmt.props stmt.kind index in
167 let sql = quote (get_sql stmt) in
168 struct_params name ["stmt","typename Traits::statement"] (fun () ->
169 func "" name ["db","typename Traits::connection"] ~tail:(sprintf ": stmt(db,SQLGG_STR(%s))" sql) identity;
170 let schema_binder_name = output_schema_binder index stmt.schema in
171 let params_binder_name = output_params_binder index stmt.params in
172 (* if (Option.is_some schema_binder_name) then output_schema_data index stmt.schema; *)
173 out_public ();
174 if (Option.is_some schema_binder_name) then output "template<class T>";
175 let values = params_to_values stmt.params in
176 let result = match schema_binder_name with None -> [] | Some _ -> ["result","T"] in
177 let all_params = (make_const_values values) @ result in
178 let inline_params = Values.inline (make_const_values values) in
179 func "bool" "operator()" all_params (fun () ->
180 begin match schema_binder_name with
181 | None -> output "return stmt.execute(%s(%s));" params_binder_name inline_params
182 | Some schema_name -> output "return stmt.select(result,%s<T>(),%s(%s));"
183 schema_name params_binder_name inline_params
184 end);
186 name
188 let make_all name names =
189 List.iter (fun name -> output "%s %s;" name name) names;
190 empty_line ();
191 let tail = match names with
192 | [] -> ""
193 | _ -> ": " ^ (String.concat ", " (List.map (fun name -> sprintf "%s(db)" name) names))
195 func "" name ["db","typename Traits::connection"] ~tail identity
197 let generate () name stmts =
198 output "#pragma once";
199 empty_line ();
200 output "template <class Traits>";
201 start_struct name;
202 let stmts = List.of_enum stmts in
203 let names = List.mapi make_stmt stmts in
204 make_all name names;
205 end_struct name