blob: 9fd1686240e245033b9eb72e2746a5c14070bdae [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
iproctorff8eb922007-07-25 19:06:13 +000019
David Reiss42e6d512008-03-27 21:40:20 +000020#include <string>
21#include <fstream>
22#include <iostream>
23#include <vector>
24
iproctorff8eb922007-07-25 19:06:13 +000025#include <stdlib.h>
26#include <sys/stat.h>
27#include <sys/types.h>
28#include <sstream>
Christian Lavoie600a88c2010-11-07 18:37:11 +000029
David Reiss42e6d512008-03-27 21:40:20 +000030#include "t_oop_generator.h"
David Reiss204420f2008-01-11 20:59:03 +000031#include "platform.h"
Roger Meier08d46812011-04-12 19:08:21 +000032#include "version.h"
iproctorff8eb922007-07-25 19:06:13 +000033
Christian Lavoie600a88c2010-11-07 18:37:11 +000034using namespace std;
David Reiss42e6d512008-03-27 21:40:20 +000035
36/**
37 * Haskell code generator.
38 *
David Reiss42e6d512008-03-27 21:40:20 +000039 */
40class t_hs_generator : public t_oop_generator {
41 public:
Christian Lavoie600a88c2010-11-07 18:37:11 +000042 t_hs_generator(t_program* program,
43 const map<string, string>& parsed_options,
44 const string& option_string)
David Reiss42e6d512008-03-27 21:40:20 +000045 : t_oop_generator(program)
46 {
Roger Meier3b771a12010-11-17 22:11:26 +000047 (void) parsed_options;
48 (void) option_string;
David Reiss42e6d512008-03-27 21:40:20 +000049 out_dir_base_ = "gen-hs";
50 }
51
52 /**
53 * Init and close methods
54 */
55
56 void init_generator();
57 void close_generator();
58
59 /**
60 * Program-level generation functions
61 */
David Reiss42e6d512008-03-27 21:40:20 +000062 void generate_typedef (t_typedef* ttypedef);
63 void generate_enum (t_enum* tenum);
64 void generate_const (t_const* tconst);
65 void generate_struct (t_struct* tstruct);
66 void generate_xception (t_struct* txception);
67 void generate_service (t_service* tservice);
68
Christian Lavoie600a88c2010-11-07 18:37:11 +000069 string render_const_value(t_type* type, t_const_value* value);
David Reiss42e6d512008-03-27 21:40:20 +000070
71 /**
72 * Struct generation code
73 */
74
Christian Lavoie600a88c2010-11-07 18:37:11 +000075 void generate_hs_struct (t_struct* tstruct,
76 bool is_exception);
77
78 void generate_hs_struct_definition (ofstream &out,
79 t_struct* tstruct,
80 bool is_xception = false,
81 bool helper = false);
82
83 void generate_hs_struct_reader (ofstream& out,
84 t_struct* tstruct);
85
86 void generate_hs_struct_writer (ofstream& out,
87 t_struct* tstruct);
88
89 void generate_hs_function_helpers (t_function* tfunction);
David Reiss42e6d512008-03-27 21:40:20 +000090
91 /**
92 * Service-level generation functions
93 */
94
Christian Lavoie600a88c2010-11-07 18:37:11 +000095 void generate_service_helpers (t_service* tservice);
David Reiss42e6d512008-03-27 21:40:20 +000096 void generate_service_interface (t_service* tservice);
97 void generate_service_client (t_service* tservice);
98 void generate_service_server (t_service* tservice);
Christian Lavoie600a88c2010-11-07 18:37:11 +000099 void generate_process_function (t_service* tservice,
100 t_function* tfunction);
David Reiss42e6d512008-03-27 21:40:20 +0000101
102 /**
103 * Serialization constructs
104 */
105
Christian Lavoie600a88c2010-11-07 18:37:11 +0000106 void generate_deserialize_field (ofstream &out,
107 t_field* tfield,
108 string prefix);
David Reiss42e6d512008-03-27 21:40:20 +0000109
Christian Lavoie600a88c2010-11-07 18:37:11 +0000110 void generate_deserialize_struct (ofstream &out,
111 t_struct* tstruct);
David Reiss42e6d512008-03-27 21:40:20 +0000112
Christian Lavoie600a88c2010-11-07 18:37:11 +0000113 void generate_deserialize_container (ofstream &out,
114 t_type* ttype);
David Reiss42e6d512008-03-27 21:40:20 +0000115
Christian Lavoie600a88c2010-11-07 18:37:11 +0000116 void generate_deserialize_set_element (ofstream &out,
117 t_set* tset);
David Reiss42e6d512008-03-27 21:40:20 +0000118
119
Christian Lavoie600a88c2010-11-07 18:37:11 +0000120 void generate_deserialize_list_element (ofstream &out,
121 t_list* tlist,
122 string prefix = "");
123
124 void generate_deserialize_type (ofstream &out,
David Reiss42e6d512008-03-27 21:40:20 +0000125 t_type* type);
126
Christian Lavoie600a88c2010-11-07 18:37:11 +0000127 void generate_serialize_field (ofstream &out,
128 t_field* tfield,
129 string name = "");
David Reiss42e6d512008-03-27 21:40:20 +0000130
Christian Lavoie600a88c2010-11-07 18:37:11 +0000131 void generate_serialize_struct (ofstream &out,
132 t_struct* tstruct,
133 string prefix = "");
David Reiss42e6d512008-03-27 21:40:20 +0000134
Christian Lavoie600a88c2010-11-07 18:37:11 +0000135 void generate_serialize_container (ofstream &out,
136 t_type* ttype,
137 string prefix = "");
David Reiss42e6d512008-03-27 21:40:20 +0000138
Christian Lavoie600a88c2010-11-07 18:37:11 +0000139 void generate_serialize_map_element (ofstream &out,
140 t_map* tmap,
141 string kiter,
142 string viter);
David Reiss42e6d512008-03-27 21:40:20 +0000143
Christian Lavoie600a88c2010-11-07 18:37:11 +0000144 void generate_serialize_set_element (ofstream &out,
145 t_set* tmap,
146 string iter);
David Reiss42e6d512008-03-27 21:40:20 +0000147
Christian Lavoie600a88c2010-11-07 18:37:11 +0000148 void generate_serialize_list_element (ofstream &out,
149 t_list* tlist,
150 string iter);
David Reiss42e6d512008-03-27 21:40:20 +0000151
152 /**
153 * Helper rendering functions
154 */
155
Christian Lavoie600a88c2010-11-07 18:37:11 +0000156 string hs_autogen_comment();
157 string hs_language_pragma();
158 string hs_imports();
David Reiss42e6d512008-03-27 21:40:20 +0000159
Christian Lavoie600a88c2010-11-07 18:37:11 +0000160 string type_name(t_type* ttype,
161 string function_prefix = "");
162
163 string function_type(t_function* tfunc,
164 bool options = false,
165 bool io = false,
166 bool method = false);
167
168 string type_to_enum(t_type* ttype);
169
170 string render_hs_type(t_type* type,
171 bool needs_parens = true);
David Reiss42e6d512008-03-27 21:40:20 +0000172
173 private:
Christian Lavoie600a88c2010-11-07 18:37:11 +0000174 ofstream f_types_;
175 ofstream f_consts_;
176 ofstream f_service_;
177 ofstream f_iface_;
178 ofstream f_client_;
David Reiss42e6d512008-03-27 21:40:20 +0000179};
180
iproctorff8eb922007-07-25 19:06:13 +0000181/**
182 * Prepares for file generation by opening up the necessary file output
183 * streams.
184 *
185 * @param tprogram The program to generate
186 */
187void t_hs_generator::init_generator() {
188 // Make output directory
David Reiss204420f2008-01-11 20:59:03 +0000189 MKDIR(get_out_dir().c_str());
iproctorff8eb922007-07-25 19:06:13 +0000190
191 // Make output file
iproctorff8eb922007-07-25 19:06:13 +0000192 string pname = capitalize(program_name_);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000193 string f_types_name = get_out_dir() + pname + "_Types.hs";
iproctorff8eb922007-07-25 19:06:13 +0000194 f_types_.open(f_types_name.c_str());
195
Christian Lavoie600a88c2010-11-07 18:37:11 +0000196 string f_consts_name = get_out_dir() + pname + "_Consts.hs";
iproctorff8eb922007-07-25 19:06:13 +0000197 f_consts_.open(f_consts_name.c_str());
198
199 // Print header
Christian Lavoie600a88c2010-11-07 18:37:11 +0000200 f_types_ << hs_language_pragma() << endl;
201 f_types_ << hs_autogen_comment() << endl;
202 f_types_ << "module " << pname << "_Types where" << endl;
203 f_types_ << hs_imports() << endl;
iproctorff8eb922007-07-25 19:06:13 +0000204
Christian Lavoie600a88c2010-11-07 18:37:11 +0000205 f_consts_ << hs_language_pragma() << endl;
206 f_consts_ << hs_autogen_comment() << endl;
207 f_consts_ << "module " << pname << "_Consts where" << endl;
208 f_consts_ << hs_imports() << endl;
209 f_consts_ << "import " << pname << "_Types" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000210}
211
David Reiss752529e2010-01-11 19:12:56 +0000212string t_hs_generator::hs_language_pragma() {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000213 return string("{-# LANGUAGE DeriveDataTypeable #-}\n"
214 "{-# OPTIONS_GHC -fno-warn-missing-fields #-}\n"
215 "{-# OPTIONS_GHC -fno-warn-missing-signatures #-}\n"
216 "{-# OPTIONS_GHC -fno-warn-name-shadowing #-}\n"
217 "{-# OPTIONS_GHC -fno-warn-unused-imports #-}\n"
218 "{-# OPTIONS_GHC -fno-warn-unused-matches #-}\n");
David Reiss752529e2010-01-11 19:12:56 +0000219}
iproctorff8eb922007-07-25 19:06:13 +0000220
221/**
222 * Autogen'd comment
223 */
224string t_hs_generator::hs_autogen_comment() {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000225 return string("-----------------------------------------------------------------\n") +
Roger Meier08d46812011-04-12 19:08:21 +0000226 "-- Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ") --\n" +
Christian Lavoie600a88c2010-11-07 18:37:11 +0000227 "-- --\n" +
228 "-- DO NOT EDIT UNLESS YOU ARE SURE YOU KNOW WHAT YOU ARE DOING --\n" +
229 "-----------------------------------------------------------------\n";
iproctorff8eb922007-07-25 19:06:13 +0000230}
231
232/**
233 * Prints standard thrift imports
234 */
235string t_hs_generator::hs_imports() {
David Reiss752529e2010-01-11 19:12:56 +0000236 const vector<t_program*>& includes = program_->get_includes();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000237 string result = string(
238 "import Prelude ( Bool(..), Enum, Double, String, Maybe(..),\n"
239 " Eq, Show, Ord,\n"
240 " return, length, IO, fromIntegral, fromEnum, toEnum,\n"
241 " (&&), (||), (==), (++), ($), (-) )\n"
242 "\n"
243 "import Control.Exception\n"
244 "import Data.ByteString.Lazy\n"
245 "import Data.Int\n"
246 "import Data.Typeable ( Typeable )\n"
247 "import qualified Data.Map as Map\n"
248 "import qualified Data.Set as Set\n"
249 "\n"
250 "import Thrift\n"
251 "\n");
David Reiss752529e2010-01-11 19:12:56 +0000252
Christian Lavoie600a88c2010-11-07 18:37:11 +0000253 for (size_t i = 0; i < includes.size(); ++i)
254 result += "import qualified " + capitalize(includes[i]->get_name()) + "_Types\n";
255
256 if (includes.size() > 0)
257 result += "\n";
258
David Reiss752529e2010-01-11 19:12:56 +0000259 return result;
iproctorff8eb922007-07-25 19:06:13 +0000260}
261
262/**
263 * Closes the type files
264 */
265void t_hs_generator::close_generator() {
266 // Close types file
267 f_types_.close();
268 f_consts_.close();
269}
David Reiss0c90f6f2008-02-06 22:18:40 +0000270
iproctorff8eb922007-07-25 19:06:13 +0000271/**
272 * Generates a typedef. Ez.
273 *
274 * @param ttypedef The type definition
275 */
276void t_hs_generator::generate_typedef(t_typedef* ttypedef) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000277 string tname = capitalize(ttypedef->get_symbolic());
278 string tdef = render_hs_type(ttypedef->get_type(), false);
279 indent(f_types_) << "type " << tname << " = " << tdef << endl;
280 f_types_ << endl;
iproctorff8eb922007-07-25 19:06:13 +0000281}
282
283/**
David Reiss0c90f6f2008-02-06 22:18:40 +0000284 * Generates code for an enumerated type.
iproctorff8eb922007-07-25 19:06:13 +0000285 * the values.
286 *
287 * @param tenum The enumeration
288 */
289void t_hs_generator::generate_enum(t_enum* tenum) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000290 indent(f_types_) << "data " << capitalize(tenum->get_name()) << " = ";
iproctorff8eb922007-07-25 19:06:13 +0000291 indent_up();
292 vector<t_enum_value*> constants = tenum->get_constants();
293 vector<t_enum_value*>::iterator c_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000294
iproctorff8eb922007-07-25 19:06:13 +0000295 bool first = true;
296 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
297 string name = capitalize((*c_iter)->get_name());
Christian Lavoie600a88c2010-11-07 18:37:11 +0000298 f_types_ << (first ? "" : "|");
iproctorff8eb922007-07-25 19:06:13 +0000299 f_types_ << name;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000300 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000301 }
Bryan Duxbury0781f2b2009-04-07 23:29:42 +0000302 indent(f_types_) << "deriving (Show,Eq, Typeable, Ord)" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000303 indent_down();
304
Christian Lavoie600a88c2010-11-07 18:37:11 +0000305 string ename = capitalize(tenum->get_name());
306 indent(f_types_) << "instance Enum " << ename << " where" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000307 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000308
iproctorff8eb922007-07-25 19:06:13 +0000309 indent(f_types_) << "fromEnum t = case t of" << endl;
310 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000311
iproctorff8eb922007-07-25 19:06:13 +0000312 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
Bryan Duxburya406b902010-09-27 23:37:44 +0000313 int value = (*c_iter)->get_value();
iproctorff8eb922007-07-25 19:06:13 +0000314 string name = capitalize((*c_iter)->get_name());
Bryan Duxburya406b902010-09-27 23:37:44 +0000315 indent(f_types_) << name << " -> " << value << endl;
iproctorff8eb922007-07-25 19:06:13 +0000316 }
317 indent_down();
318
319 indent(f_types_) << "toEnum t = case t of" << endl;
320 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000321
iproctorff8eb922007-07-25 19:06:13 +0000322 for(c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
Bryan Duxburya406b902010-09-27 23:37:44 +0000323 int value = (*c_iter)->get_value();
iproctorff8eb922007-07-25 19:06:13 +0000324 string name = capitalize((*c_iter)->get_name());
Bryan Duxburya406b902010-09-27 23:37:44 +0000325 indent(f_types_) << value << " -> " << name << endl;
iproctorff8eb922007-07-25 19:06:13 +0000326 }
Bryan Duxbury0781f2b2009-04-07 23:29:42 +0000327 indent(f_types_) << "_ -> throw ThriftException" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000328 indent_down();
329 indent_down();
330}
331
332/**
333 * Generate a constant value
334 */
335void t_hs_generator::generate_const(t_const* tconst) {
336 t_type* type = tconst->get_type();
337 string name = decapitalize(tconst->get_name());
Christian Lavoie600a88c2010-11-07 18:37:11 +0000338
iproctorff8eb922007-07-25 19:06:13 +0000339 t_const_value* value = tconst->get_value();
340
Kevin Clark4798a7a2009-03-24 15:56:19 +0000341 indent(f_consts_) << name << " :: " << render_hs_type(type, false) << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000342 indent(f_consts_) << name << " = " << render_const_value(type, value) << endl;
343 f_consts_ << endl;
iproctorff8eb922007-07-25 19:06:13 +0000344}
345
346/**
347 * Prints the value of a constant with the given type. Note that type checking
348 * is NOT performed in this function as it is always run beforehand using the
349 * validate_types method in main.cc
350 */
351string t_hs_generator::render_const_value(t_type* type, t_const_value* value) {
David Reiss9a4edfa2008-05-01 05:52:50 +0000352 type = get_true_type(type);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000353 ostringstream out;
354
iproctorff8eb922007-07-25 19:06:13 +0000355 if (type->is_base_type()) {
356 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
357 switch (tbase) {
Bryan Duxbury75a33e82010-09-22 00:48:56 +0000358
iproctorff8eb922007-07-25 19:06:13 +0000359 case t_base_type::TYPE_STRING:
David Reiss82e6fc02009-03-26 23:32:36 +0000360 out << '"' << get_escaped_string(value) << '"';
iproctorff8eb922007-07-25 19:06:13 +0000361 break;
Bryan Duxbury75a33e82010-09-22 00:48:56 +0000362
iproctorff8eb922007-07-25 19:06:13 +0000363 case t_base_type::TYPE_BOOL:
364 out << (value->get_integer() > 0 ? "True" : "False");
365 break;
Bryan Duxbury75a33e82010-09-22 00:48:56 +0000366
iproctorff8eb922007-07-25 19:06:13 +0000367 case t_base_type::TYPE_BYTE:
Christian Lavoieae7f7fa2010-11-02 21:42:53 +0000368 out << "(" << value->get_integer() << " :: Int8)";
iproctorff8eb922007-07-25 19:06:13 +0000369 break;
Bryan Duxbury75a33e82010-09-22 00:48:56 +0000370
371 case t_base_type::TYPE_I16:
372 out << "(" << value->get_integer() << " :: Int16)";
373 break;
374
375 case t_base_type::TYPE_I32:
376 out << "(" << value->get_integer() << " :: Int32)";
377 break;
378
379 case t_base_type::TYPE_I64:
380 out << "(" << value->get_integer() << " :: Int64)";
381 break;
382
iproctorff8eb922007-07-25 19:06:13 +0000383 case t_base_type::TYPE_DOUBLE:
384 if (value->get_type() == t_const_value::CV_INTEGER) {
385 out << value->get_integer();
386 } else {
387 out << value->get_double();
388 }
389 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000390
iproctorff8eb922007-07-25 19:06:13 +0000391 default:
David Reissdd7796f2007-08-28 21:09:06 +0000392 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
iproctorff8eb922007-07-25 19:06:13 +0000393 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000394
iproctorff8eb922007-07-25 19:06:13 +0000395 } else if (type->is_enum()) {
396 t_enum* tenum = (t_enum*)type;
397 vector<t_enum_value*> constants = tenum->get_constants();
398 vector<t_enum_value*>::iterator c_iter;
iproctorff8eb922007-07-25 19:06:13 +0000399 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
Bryan Duxburya406b902010-09-27 23:37:44 +0000400 int val = (*c_iter)->get_value();
401 if (val == value->get_integer()) {
iproctorff8eb922007-07-25 19:06:13 +0000402 indent(out) << capitalize((*c_iter)->get_name());
403 break;
404 }
405 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000406
iproctorff8eb922007-07-25 19:06:13 +0000407 } else if (type->is_struct() || type->is_xception()) {
408 string cname = type_name(type);
409 indent(out) << cname << "{";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000410
iproctorff8eb922007-07-25 19:06:13 +0000411 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
412 vector<t_field*>::const_iterator f_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000413
iproctorff8eb922007-07-25 19:06:13 +0000414 const map<t_const_value*, t_const_value*>& val = value->get_map();
415 map<t_const_value*, t_const_value*>::const_iterator v_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000416
iproctorff8eb922007-07-25 19:06:13 +0000417 bool first = true;
418 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
419 t_type* field_type = NULL;
iproctorff8eb922007-07-25 19:06:13 +0000420
Christian Lavoie600a88c2010-11-07 18:37:11 +0000421 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
422 if ((*f_iter)->get_name() == v_iter->first->get_string())
423 field_type = (*f_iter)->get_type();
424
425 if (field_type == NULL)
426 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
427
428 string fname = v_iter->first->get_string();
429 string const_value = render_const_value(field_type, v_iter->second);
430
431 out << (first ? "" : ",");
432 out << "f_" << cname << "_" << fname << " = Just (" << const_value << ")";
433 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000434 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000435
iproctorff8eb922007-07-25 19:06:13 +0000436 indent(out) << "}";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000437
iproctorff8eb922007-07-25 19:06:13 +0000438 } else if (type->is_map()) {
439 t_type* ktype = ((t_map*)type)->get_key_type();
440 t_type* vtype = ((t_map*)type)->get_val_type();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000441
iproctorff8eb922007-07-25 19:06:13 +0000442 const map<t_const_value*, t_const_value*>& val = value->get_map();
443 map<t_const_value*, t_const_value*>::const_iterator v_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000444
iproctorff8eb922007-07-25 19:06:13 +0000445 out << "(Map.fromList [";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000446
447 bool first = true;
iproctorff8eb922007-07-25 19:06:13 +0000448 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
449 string key = render_const_value(ktype, v_iter->first);
450 string val = render_const_value(vtype, v_iter->second);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000451 out << (first ? "" : ",");
452 out << "(" << key << "," << val << ")";
453 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000454 }
455 out << "])";
Kevin Clark4798a7a2009-03-24 15:56:19 +0000456
Christian Lavoie600a88c2010-11-07 18:37:11 +0000457 } else if (type->is_list() || type->is_set()) {
458 t_type* etype = type->is_list()
459 ? ((t_list*) type)->get_elem_type()
460 : ((t_set*) type)->get_elem_type();
Kevin Clark4798a7a2009-03-24 15:56:19 +0000461
iproctorff8eb922007-07-25 19:06:13 +0000462 const vector<t_const_value*>& val = value->get_list();
463 vector<t_const_value*>::const_iterator v_iter;
Kevin Clark4798a7a2009-03-24 15:56:19 +0000464
465 if (type->is_set())
Christian Lavoie600a88c2010-11-07 18:37:11 +0000466 out << "(Set.fromList ";
Kevin Clark4798a7a2009-03-24 15:56:19 +0000467
468 out << "[";
469
Christian Lavoie600a88c2010-11-07 18:37:11 +0000470 bool first = true;
iproctorff8eb922007-07-25 19:06:13 +0000471 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000472 out << (first ? "" : ",");
iproctorff8eb922007-07-25 19:06:13 +0000473 out << render_const_value(etype, *v_iter);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000474 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000475 }
Kevin Clark4798a7a2009-03-24 15:56:19 +0000476
iproctorff8eb922007-07-25 19:06:13 +0000477 out << "]";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000478
Kevin Clark4798a7a2009-03-24 15:56:19 +0000479 if (type->is_set())
Christian Lavoie600a88c2010-11-07 18:37:11 +0000480 out << ")";
481
David Reiss9a4edfa2008-05-01 05:52:50 +0000482 } else {
483 throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
iproctorff8eb922007-07-25 19:06:13 +0000484 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000485
iproctorff8eb922007-07-25 19:06:13 +0000486 return out.str();
487}
488
489/**
490 * Generates a "struct"
491 */
492void t_hs_generator::generate_struct(t_struct* tstruct) {
493 generate_hs_struct(tstruct, false);
494}
495
496/**
497 * Generates a struct definition for a thrift exception. Basically the same
498 * as a struct, but also has an exception declaration.
499 *
500 * @param txception The struct definition
501 */
502void t_hs_generator::generate_xception(t_struct* txception) {
David Reiss0c90f6f2008-02-06 22:18:40 +0000503 generate_hs_struct(txception, true);
iproctorff8eb922007-07-25 19:06:13 +0000504}
505
506/**
507 * Generates a Haskell struct
508 */
509void t_hs_generator::generate_hs_struct(t_struct* tstruct,
Christian Lavoie600a88c2010-11-07 18:37:11 +0000510 bool is_exception) {
iproctorff8eb922007-07-25 19:06:13 +0000511 generate_hs_struct_definition(f_types_,tstruct, is_exception,false);
512}
513
514/**
David Reiss0c90f6f2008-02-06 22:18:40 +0000515 * Generates a struct definition for a thrift data type.
iproctorff8eb922007-07-25 19:06:13 +0000516 *
517 * @param tstruct The struct definition
518 */
519void t_hs_generator::generate_hs_struct_definition(ofstream& out,
520 t_struct* tstruct,
521 bool is_exception,
522 bool helper) {
Roger Meier3b771a12010-11-17 22:11:26 +0000523 (void) helper;
iproctorff8eb922007-07-25 19:06:13 +0000524 string tname = type_name(tstruct);
525 string name = tstruct->get_name();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000526
iproctorff8eb922007-07-25 19:06:13 +0000527 const vector<t_field*>& members = tstruct->get_members();
David Reiss0c90f6f2008-02-06 22:18:40 +0000528 vector<t_field*>::const_iterator m_iter;
iproctorff8eb922007-07-25 19:06:13 +0000529
Christian Lavoie600a88c2010-11-07 18:37:11 +0000530 indent(out) << "data " << tname << " = " << tname;
iproctorff8eb922007-07-25 19:06:13 +0000531 if (members.size() > 0) {
532 out << "{";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000533
534 bool first = true;
iproctorff8eb922007-07-25 19:06:13 +0000535 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
iproctorff8eb922007-07-25 19:06:13 +0000536 string mname = (*m_iter)->get_name();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000537 out << (first ? "" : ",");
Kevin Clark38c8b5b2009-03-24 14:51:51 +0000538 out << "f_" << tname << "_" << mname << " :: Maybe " << render_hs_type((*m_iter)->get_type());
Christian Lavoie600a88c2010-11-07 18:37:11 +0000539 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000540 }
541 out << "}";
542 }
543
544 out << " deriving (Show,Eq,Ord,Typeable)" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000545
546 if (is_exception)
547 out << "instance Exception " << tname << endl;
548
iproctorff8eb922007-07-25 19:06:13 +0000549 generate_hs_struct_writer(out, tstruct);
iproctorff8eb922007-07-25 19:06:13 +0000550 generate_hs_struct_reader(out, tstruct);
iproctorff8eb922007-07-25 19:06:13 +0000551}
552
iproctorff8eb922007-07-25 19:06:13 +0000553/**
554 * Generates the read method for a struct
555 */
556void t_hs_generator::generate_hs_struct_reader(ofstream& out, t_struct* tstruct) {
557 const vector<t_field*>& fields = tstruct->get_members();
558 vector<t_field*>::const_iterator f_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000559
iproctorff8eb922007-07-25 19:06:13 +0000560 string sname = type_name(tstruct);
561 string str = tmp("_str");
562 string t = tmp("_t");
563 string id = tmp("_id");
564
Anthony F. Molinarodaef1c82010-09-26 04:25:36 +0000565 indent(out) << "read_" << sname << "_fields iprot record = do" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000566 indent_up();
David Reiss0c90f6f2008-02-06 22:18:40 +0000567
iproctorff8eb922007-07-25 19:06:13 +0000568 // Read beginning field marker
Christian Lavoie600a88c2010-11-07 18:37:11 +0000569 indent(out) << "(_," << t << "," << id << ") <- readFieldBegin iprot" << endl;
570
iproctorff8eb922007-07-25 19:06:13 +0000571 // Check for field STOP marker and break
Christian Lavoie600a88c2010-11-07 18:37:11 +0000572 indent(out) << "if " << t << " == T_STOP then return record else" << endl;
573
574 indent_up();
575 indent(out) << "case " << id << " of " << endl;
576 indent_up();
577
iproctorff8eb922007-07-25 19:06:13 +0000578 // Generate deserialization code for known cases
579 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000580 int32_t key = (*f_iter)->get_key();
581 string etype = type_to_enum((*f_iter)->get_type());
582 indent(out) << key << " -> " << "if " << t << " == " << etype << " then do" << endl;
583
584 indent_up();
iproctorff8eb922007-07-25 19:06:13 +0000585 indent(out) << "s <- ";
586 generate_deserialize_field(out, *f_iter,str);
587 out << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000588
589 string fname = decapitalize((*f_iter)->get_name());
590 indent(out) << "read_" << sname << "_fields iprot record{f_" << sname << "_" << fname << "=Just s}" << endl;
591
592 indent(out) << "else do" << endl;
593
iproctorff8eb922007-07-25 19:06:13 +0000594 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000595 indent(out) << "skip iprot " << t << endl;
596
597 indent(out) << "read_" << sname << "_fields iprot record" << endl;
598
599 indent_down();
600 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000601 }
602
iproctorff8eb922007-07-25 19:06:13 +0000603 // In the default case we skip the field
Christian Lavoie600a88c2010-11-07 18:37:11 +0000604 indent(out) << "_ -> do" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000605 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000606 indent(out) << "skip iprot " << t << endl;
iproctorff8eb922007-07-25 19:06:13 +0000607 indent(out) << "readFieldEnd iprot" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000608 indent(out) << "read_" << sname << "_fields iprot record" << endl;
609 indent_down();
610 indent_down();
611 indent_down();
David Reiss0c90f6f2008-02-06 22:18:40 +0000612 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000613
614 // read
Christian Lavoie600a88c2010-11-07 18:37:11 +0000615 indent(out) << "read_" << sname << " iprot = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000616 indent_up();
Bryan Duxburyf38b2f12010-09-20 17:41:40 +0000617 indent(out) << "_ <- readStructBegin iprot" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000618 indent(out) << "record <- read_" << sname << "_fields iprot (" << sname << "{";
619
iproctorff8eb922007-07-25 19:06:13 +0000620 bool first = true;
621 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000622 out << (first ? "" : ",");
iproctorff8eb922007-07-25 19:06:13 +0000623 out << "f_" << sname << "_" << decapitalize((*f_iter)->get_name()) << "=Nothing";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000624 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000625 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000626
iproctorff8eb922007-07-25 19:06:13 +0000627 out << "})" << endl;
628 indent(out) << "readStructEnd iprot" << endl;
Anthony F. Molinarodaef1c82010-09-26 04:25:36 +0000629 indent(out) << "return record" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000630 indent_down();
631}
632
633void t_hs_generator::generate_hs_struct_writer(ofstream& out,
634 t_struct* tstruct) {
635 string name = type_name(tstruct);
Bryan Duxburyff219ac2009-04-10 21:51:00 +0000636 const vector<t_field*>& fields = tstruct->get_sorted_members();
iproctorff8eb922007-07-25 19:06:13 +0000637 vector<t_field*>::const_iterator f_iter;
638 string str = tmp("_str");
639 string f = tmp("_f");
640
Christian Lavoie600a88c2010-11-07 18:37:11 +0000641 indent(out) << "write_" << name << " oprot record = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000642 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000643 indent(out) << "writeStructBegin oprot \"" << name << "\"" << endl;
644
iproctorff8eb922007-07-25 19:06:13 +0000645 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
646 // Write field header
647 string mname = (*f_iter)->get_name();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000648 indent(out) << "case f_" << name << "_" << mname << " record of {Nothing -> return (); Just _v -> do" << endl;
649
iproctorff8eb922007-07-25 19:06:13 +0000650 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000651 indent(out) << "writeFieldBegin oprot (\"" << (*f_iter)->get_name() << "\","
652 << type_to_enum((*f_iter)->get_type()) << ","
653 << (*f_iter)->get_key() << ")" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000654
655 // Write field contents
Christian Lavoie600a88c2010-11-07 18:37:11 +0000656 indent(out);
iproctorff8eb922007-07-25 19:06:13 +0000657 generate_serialize_field(out, *f_iter, "_v");
658 out << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000659
iproctorff8eb922007-07-25 19:06:13 +0000660 // Write field closer
661 indent(out) << "writeFieldEnd oprot}" << endl;
662 indent_down();
663 }
664
665 // Write the struct map
Christian Lavoie600a88c2010-11-07 18:37:11 +0000666 indent(out) << "writeFieldStop oprot" << endl;
667 indent(out) << "writeStructEnd oprot" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000668
669 indent_down();
670}
671
672/**
673 * Generates a thrift service.
674 *
675 * @param tservice The service definition
676 */
677void t_hs_generator::generate_service(t_service* tservice) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000678 string f_service_name = get_out_dir() + capitalize(service_name_) + ".hs";
iproctorff8eb922007-07-25 19:06:13 +0000679 f_service_.open(f_service_name.c_str());
680
Christian Lavoie600a88c2010-11-07 18:37:11 +0000681 f_service_ << hs_language_pragma() << endl;
682 f_service_ << hs_autogen_comment() << endl;
683 f_service_ << "module " << capitalize(service_name_) << " where" << endl;
684 f_service_ << hs_imports() << endl;
iproctorff8eb922007-07-25 19:06:13 +0000685
Christian Lavoie600a88c2010-11-07 18:37:11 +0000686 if (tservice->get_extends()) {
687 f_service_ << "import qualified " << capitalize(tservice->get_extends()->get_name()) << endl;
iproctorff8eb922007-07-25 19:06:13 +0000688 }
689
Christian Lavoie600a88c2010-11-07 18:37:11 +0000690 f_service_ << "import " << capitalize(program_name_) << "_Types" << endl;
691 f_service_ << "import qualified " << capitalize(service_name_) << "_Iface as Iface" << endl;
David Reiss0c90f6f2008-02-06 22:18:40 +0000692
693 // Generate the three main parts of the service
iproctorff8eb922007-07-25 19:06:13 +0000694 generate_service_helpers(tservice);
695 generate_service_interface(tservice);
696 generate_service_client(tservice);
697 generate_service_server(tservice);
698
iproctorff8eb922007-07-25 19:06:13 +0000699 // Close service file
700 f_service_.close();
701}
702
703/**
704 * Generates helper functions for a service.
705 *
706 * @param tservice The service to generate a header definition for
707 */
708void t_hs_generator::generate_service_helpers(t_service* tservice) {
709 vector<t_function*> functions = tservice->get_functions();
710 vector<t_function*>::iterator f_iter;
711
Christian Lavoie600a88c2010-11-07 18:37:11 +0000712 indent(f_service_) << "-- HELPER FUNCTIONS AND STRUCTURES --" << endl;
713 indent(f_service_) << endl;
iproctorff8eb922007-07-25 19:06:13 +0000714
715 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
716 t_struct* ts = (*f_iter)->get_arglist();
717 generate_hs_struct_definition(f_service_,ts, false);
718 generate_hs_function_helpers(*f_iter);
719 }
720}
721
722/**
723 * Generates a struct and helpers for a function.
724 *
725 * @param tfunction The function
726 */
727void t_hs_generator::generate_hs_function_helpers(t_function* tfunction) {
728 t_struct result(program_, decapitalize(tfunction->get_name()) + "_result");
729 t_field success(tfunction->get_returntype(), "success", 0);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000730
731 if (!tfunction->get_returntype()->is_void())
iproctorff8eb922007-07-25 19:06:13 +0000732 result.append(&success);
iproctorff8eb922007-07-25 19:06:13 +0000733
734 t_struct* xs = tfunction->get_xceptions();
735 const vector<t_field*>& fields = xs->get_members();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000736
iproctorff8eb922007-07-25 19:06:13 +0000737 vector<t_field*>::const_iterator f_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000738 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
iproctorff8eb922007-07-25 19:06:13 +0000739 result.append(*f_iter);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000740
iproctorff8eb922007-07-25 19:06:13 +0000741 generate_hs_struct_definition(f_service_,&result, false);
742}
743
744/**
745 * Generates a service interface definition.
746 *
747 * @param tservice The service to generate a header definition for
748 */
749void t_hs_generator::generate_service_interface(t_service* tservice) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000750 string f_iface_name = get_out_dir() + capitalize(service_name_) + "_Iface.hs";
iproctorff8eb922007-07-25 19:06:13 +0000751 f_iface_.open(f_iface_name.c_str());
Bryan Duxburye59a80f2010-09-20 15:21:37 +0000752
Christian Lavoie600a88c2010-11-07 18:37:11 +0000753 f_iface_ << hs_language_pragma() << endl;
754 f_iface_ << hs_autogen_comment() << endl;
iproctorff8eb922007-07-25 19:06:13 +0000755
Christian Lavoie600a88c2010-11-07 18:37:11 +0000756 f_iface_ << "module " << capitalize(service_name_) << "_Iface where" << endl;
David Reiss0c90f6f2008-02-06 22:18:40 +0000757
Christian Lavoie600a88c2010-11-07 18:37:11 +0000758 f_iface_ << hs_imports() << endl;
759 f_iface_ << "import " << capitalize(program_name_) << "_Types" << endl;
760 f_iface_ << endl;
761
762 string sname = capitalize(service_name_);
iproctorff8eb922007-07-25 19:06:13 +0000763 if (tservice->get_extends() != NULL) {
764 string extends = type_name(tservice->get_extends());
Christian Lavoie600a88c2010-11-07 18:37:11 +0000765
766 indent(f_iface_) << "import " << extends << "_Iface" << endl;
767 indent(f_iface_) << "class " << extends << "_Iface a => " << sname << "_Iface a where" << endl;
768
iproctorff8eb922007-07-25 19:06:13 +0000769 } else {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000770 indent(f_iface_) << "class " << sname << "_Iface a where" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000771 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000772
iproctorff8eb922007-07-25 19:06:13 +0000773 indent_up();
774
775 vector<t_function*> functions = tservice->get_functions();
David Reiss0c90f6f2008-02-06 22:18:40 +0000776 vector<t_function*>::iterator f_iter;
iproctorff8eb922007-07-25 19:06:13 +0000777 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000778 string ft = function_type(*f_iter, true, true, true);
779 indent(f_iface_) << decapitalize((*f_iter)->get_name()) << " :: a -> " << ft << endl;
iproctorff8eb922007-07-25 19:06:13 +0000780 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000781
iproctorff8eb922007-07-25 19:06:13 +0000782 indent_down();
783 f_iface_.close();
iproctorff8eb922007-07-25 19:06:13 +0000784}
785
786/**
787 * Generates a service client definition. Note that in Haskell, the client doesn't implement iface. This is because
788 * The client does not (and should not have to) deal with arguments being Nothing.
789 *
790 * @param tservice The service to generate a server for.
791 */
792void t_hs_generator::generate_service_client(t_service* tservice) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000793 string f_client_name = get_out_dir() + capitalize(service_name_) + "_Client.hs";
iproctorff8eb922007-07-25 19:06:13 +0000794 f_client_.open(f_client_name.c_str());
Christian Lavoie600a88c2010-11-07 18:37:11 +0000795 f_client_ << hs_language_pragma() << endl;
796 f_client_ << hs_autogen_comment() << endl;
iproctorff8eb922007-07-25 19:06:13 +0000797
798 vector<t_function*> functions = tservice->get_functions();
David Reiss0c90f6f2008-02-06 22:18:40 +0000799 vector<t_function*>::const_iterator f_iter;
iproctorff8eb922007-07-25 19:06:13 +0000800
801 string extends = "";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000802 string exports = "";
803
iproctorff8eb922007-07-25 19:06:13 +0000804 bool first = true;
805 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000806 exports += (first ? "" : ",");
iproctorff8eb922007-07-25 19:06:13 +0000807 string funname = (*f_iter)->get_name();
Anthony F. Molinaro71a58a82010-09-27 19:27:40 +0000808 exports += decapitalize(funname);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000809 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000810 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000811
812 string sname = capitalize(service_name_);
813 indent(f_client_) << "module " << sname << "_Client(" << exports << ") where" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000814
815 if (tservice->get_extends() != NULL) {
816 extends = type_name(tservice->get_extends());
817 indent(f_client_) << "import " << extends << "_Client" << endl;
818 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000819
iproctorff8eb922007-07-25 19:06:13 +0000820 indent(f_client_) << "import Data.IORef" << endl;
821 indent(f_client_) << hs_imports() << endl;
822 indent(f_client_) << "import " << capitalize(program_name_) << "_Types" << endl;
823 indent(f_client_) << "import " << capitalize(service_name_) << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000824
iproctorff8eb922007-07-25 19:06:13 +0000825 // DATS RITE A GLOBAL VAR
826 indent(f_client_) << "seqid = newIORef 0" << endl;
David Reiss0c90f6f2008-02-06 22:18:40 +0000827
iproctorff8eb922007-07-25 19:06:13 +0000828 // Generate client method implementations
iproctorff8eb922007-07-25 19:06:13 +0000829 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
830 t_struct* arg_struct = (*f_iter)->get_arglist();
831 const vector<t_field*>& fields = arg_struct->get_members();
832 vector<t_field*>::const_iterator fld_iter;
833 string funname = (*f_iter)->get_name();
834
835 string fargs = "";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000836 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter)
837 fargs += " arg_" + decapitalize((*fld_iter)->get_name());
iproctorff8eb922007-07-25 19:06:13 +0000838
839 // Open function
Anthony F. Molinaro71a58a82010-09-27 19:27:40 +0000840 indent(f_client_) << decapitalize(funname) << " (ip,op)" << fargs << " = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000841 indent_up();
842 indent(f_client_) << "send_" << funname << " op" << fargs;
843
844 f_client_ << endl;
David Reiss0c90f6f2008-02-06 22:18:40 +0000845
Christian Lavoie600a88c2010-11-07 18:37:11 +0000846 if (!(*f_iter)->is_oneway())
847 indent(f_client_) << "recv_" << funname << " ip" << endl;
848
iproctorff8eb922007-07-25 19:06:13 +0000849 indent_down();
David Reiss0c90f6f2008-02-06 22:18:40 +0000850
Christian Lavoie600a88c2010-11-07 18:37:11 +0000851 indent(f_client_) << "send_" << funname << " op" << fargs << " = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000852 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000853
iproctorff8eb922007-07-25 19:06:13 +0000854 indent(f_client_) << "seq <- seqid" << endl;
855 indent(f_client_) << "seqn <- readIORef seq" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000856 string argsname = capitalize((*f_iter)->get_name() + "_args");
David Reiss0c90f6f2008-02-06 22:18:40 +0000857
iproctorff8eb922007-07-25 19:06:13 +0000858 // Serialize the request header
Christian Lavoie600a88c2010-11-07 18:37:11 +0000859 string fname = (*f_iter)->get_name();
860 indent(f_client_) << "writeMessageBegin op (\"" << fname << "\", M_CALL, seqn)" << endl;
861 indent(f_client_) << "write_" << argsname << " op (" << argsname << "{";
862
iproctorff8eb922007-07-25 19:06:13 +0000863 bool first = true;
864 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000865 string fieldname = (*fld_iter)->get_name();
866 f_client_ << (first ? "" : ",");
867 f_client_ << "f_" << argsname << "_" << fieldname << "=Just arg_" << fieldname;
868 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000869 }
870 f_client_ << "})" << endl;
David Reiss0c90f6f2008-02-06 22:18:40 +0000871
iproctorff8eb922007-07-25 19:06:13 +0000872 // Write to the stream
Christian Lavoie600a88c2010-11-07 18:37:11 +0000873 indent(f_client_) << "writeMessageEnd op" << endl;
874 indent(f_client_) << "tFlush (getTransport op)" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000875 indent_down();
876
David Reiss47329252009-03-24 20:01:02 +0000877 if (!(*f_iter)->is_oneway()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000878 string resultname = capitalize((*f_iter)->get_name() + "_result");
iproctorff8eb922007-07-25 19:06:13 +0000879 t_struct noargs(program_);
880
Christian Lavoie600a88c2010-11-07 18:37:11 +0000881 string funname = string("recv_") + (*f_iter)->get_name();
882 t_function recv_function((*f_iter)->get_returntype(), funname, &noargs);
David Reiss0c90f6f2008-02-06 22:18:40 +0000883
iproctorff8eb922007-07-25 19:06:13 +0000884 // Open function
Christian Lavoie600a88c2010-11-07 18:37:11 +0000885 indent(f_client_) << funname << " ip = do" << endl;
886 indent_up();
iproctorff8eb922007-07-25 19:06:13 +0000887
888 // TODO(mcslee): Validate message reply here, seq ids etc.
Christian Lavoie600a88c2010-11-07 18:37:11 +0000889 indent(f_client_) << "(fname, mtype, rseqid) <- readMessageBegin ip" << endl;
890 indent(f_client_) << "if mtype == M_EXCEPTION then do" << endl;
891 indent(f_client_) << " x <- readAppExn ip" << endl;
892 indent(f_client_) << " readMessageEnd ip" << endl;
893 indent(f_client_) << " throw x" << endl;
894 indent(f_client_) << " else return ()" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000895
896 t_struct* xs = (*f_iter)->get_xceptions();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000897 const vector<t_field*>& xceptions = xs->get_members();
iproctorff8eb922007-07-25 19:06:13 +0000898
Christian Lavoie600a88c2010-11-07 18:37:11 +0000899 indent(f_client_) << "res <- read_" << resultname << " ip" << endl;
900 indent(f_client_) << "readMessageEnd ip" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000901
902 // Careful, only return _result if not a void function
903 if (!(*f_iter)->get_returntype()->is_void()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000904 indent(f_client_) << "case f_" << resultname << "_success res of" << endl;
905 indent_up();
906
iproctorff8eb922007-07-25 19:06:13 +0000907 indent(f_client_) << "Just v -> return v" << endl;
908 indent(f_client_) << "Nothing -> do" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000909 indent_up();
iproctorff8eb922007-07-25 19:06:13 +0000910 }
David Reiss0c90f6f2008-02-06 22:18:40 +0000911
iproctorff8eb922007-07-25 19:06:13 +0000912 vector<t_field*>::const_iterator x_iter;
913 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000914 string xname = (*x_iter)->get_name();
915 indent(f_client_) << "case f_" << resultname << "_" << xname << " res of" << endl;
916 indent_up();
917
iproctorff8eb922007-07-25 19:06:13 +0000918 indent(f_client_) << "Nothing -> return ()" << endl;
Bryan Duxbury0781f2b2009-04-07 23:29:42 +0000919 indent(f_client_) << "Just _v -> throw _v" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000920 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000921 }
David Reiss0c90f6f2008-02-06 22:18:40 +0000922
iproctorff8eb922007-07-25 19:06:13 +0000923 // Careful, only return _result if not a void function
924 if ((*f_iter)->get_returntype()->is_void()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000925 indent(f_client_) << "return ()" << endl;
926
iproctorff8eb922007-07-25 19:06:13 +0000927 } else {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000928 string tname = (*f_iter)->get_name();
929 indent(f_client_) << "throw (AppExn AE_MISSING_RESULT \"" << tname << " failed: unknown result\")" << endl;
930 indent_down();
931 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000932 }
933
934 // Close function
Christian Lavoie600a88c2010-11-07 18:37:11 +0000935 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000936 }
937 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000938
iproctorff8eb922007-07-25 19:06:13 +0000939 f_client_.close();
iproctorff8eb922007-07-25 19:06:13 +0000940}
941
942/**
943 * Generates a service server definition.
944 *
945 * @param tservice The service to generate a server for.
946 */
947void t_hs_generator::generate_service_server(t_service* tservice) {
948 // Generate the dispatch methods
949 vector<t_function*> functions = tservice->get_functions();
David Reiss0c90f6f2008-02-06 22:18:40 +0000950 vector<t_function*>::iterator f_iter;
iproctorff8eb922007-07-25 19:06:13 +0000951
952 // Generate the process subfunctions
Christian Lavoie600a88c2010-11-07 18:37:11 +0000953 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
iproctorff8eb922007-07-25 19:06:13 +0000954 generate_process_function(tservice, *f_iter);
iproctorff8eb922007-07-25 19:06:13 +0000955
Anthony F. Molinarodaef1c82010-09-26 04:25:36 +0000956 indent(f_service_) << "proc_ handler (iprot,oprot) (name,typ,seqid) = case name of" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000957 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000958
iproctorff8eb922007-07-25 19:06:13 +0000959 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
960 string fname = (*f_iter)->get_name();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000961 indent(f_service_) << "\"" << fname << "\" -> process_" << decapitalize(fname) << " (seqid,iprot,oprot,handler)" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000962 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000963
iproctorff8eb922007-07-25 19:06:13 +0000964 indent(f_service_) << "_ -> ";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000965 if (tservice->get_extends() != NULL) {
Anthony F. Molinarodaef1c82010-09-26 04:25:36 +0000966 f_service_ << type_name(tservice->get_extends()) << ".proc_ handler (iprot,oprot) (name,typ,seqid)" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000967
iproctorff8eb922007-07-25 19:06:13 +0000968 } else {
969 f_service_ << "do" << endl;
970 indent_up();
971 indent(f_service_) << "skip iprot T_STRUCT" << endl;
972 indent(f_service_) << "readMessageEnd iprot" << endl;
973 indent(f_service_) << "writeMessageBegin oprot (name,M_EXCEPTION,seqid)" << endl;
974 indent(f_service_) << "writeAppExn oprot (AppExn AE_UNKNOWN_METHOD (\"Unknown function \" ++ name))" << endl;
975 indent(f_service_) << "writeMessageEnd oprot" << endl;
Bryan Duxbury0781f2b2009-04-07 23:29:42 +0000976 indent(f_service_) << "tFlush (getTransport oprot)" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000977 indent_down();
978 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000979
iproctorff8eb922007-07-25 19:06:13 +0000980 indent_down();
981
982 // Generate the server implementation
Christian Lavoie600a88c2010-11-07 18:37:11 +0000983 indent(f_service_) << "process handler (iprot, oprot) = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000984 indent_up();
985
Christian Lavoie600a88c2010-11-07 18:37:11 +0000986 indent(f_service_) << "(name, typ, seqid) <- readMessageBegin iprot" << endl;
987 indent(f_service_) << "proc_ handler (iprot,oprot) (name,typ,seqid)" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000988 indent(f_service_) << "return True" << endl;
989 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000990}
991
992/**
993 * Generates a process function definition.
994 *
995 * @param tfunction The function to write a dispatcher for
996 */
997void t_hs_generator::generate_process_function(t_service* tservice,
998 t_function* tfunction) {
Roger Meier3b771a12010-11-17 22:11:26 +0000999 (void) tservice;
iproctorff8eb922007-07-25 19:06:13 +00001000 // Open function
Christian Lavoie600a88c2010-11-07 18:37:11 +00001001 string funname = decapitalize(tfunction->get_name());
1002 indent(f_service_) << "process_" << funname << " (seqid, iprot, oprot, handler) = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001003 indent_up();
1004
1005 string argsname = capitalize(tfunction->get_name()) + "_args";
1006 string resultname = capitalize(tfunction->get_name()) + "_result";
1007
1008 // Generate the function call
1009 t_struct* arg_struct = tfunction->get_arglist();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001010 const vector<t_field*>& fields = arg_struct->get_members();
iproctorff8eb922007-07-25 19:06:13 +00001011 vector<t_field*>::const_iterator f_iter;
1012
Christian Lavoie600a88c2010-11-07 18:37:11 +00001013 indent(f_service_) << "args <- read_" << argsname << " iprot" << endl;
1014 indent(f_service_) << "readMessageEnd iprot" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001015
1016 t_struct* xs = tfunction->get_xceptions();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001017 const vector<t_field*>& xceptions = xs->get_members();
iproctorff8eb922007-07-25 19:06:13 +00001018 vector<t_field*>::const_iterator x_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001019
1020 size_t n = xceptions.size();
1021 if (!tfunction->is_oneway()) {
1022 if (!tfunction->get_returntype()->is_void())
iproctorff8eb922007-07-25 19:06:13 +00001023 n++;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001024
iproctorff8eb922007-07-25 19:06:13 +00001025 indent(f_service_) << "rs <- return (" << resultname;
David Reiss0c90f6f2008-02-06 22:18:40 +00001026
Christian Lavoie600a88c2010-11-07 18:37:11 +00001027 for(size_t i = 0; i < n; i++)
iproctorff8eb922007-07-25 19:06:13 +00001028 f_service_ << " Nothing";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001029
iproctorff8eb922007-07-25 19:06:13 +00001030 f_service_ << ")" << endl;
1031 }
1032
1033 indent(f_service_) << "res <- ";
1034 // Try block for a function with exceptions
1035 if (xceptions.size() > 0) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001036 for(size_t i = 0; i < xceptions.size(); i++) {
Bryan Duxbury0781f2b2009-04-07 23:29:42 +00001037 f_service_ << "(Control.Exception.catch" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001038 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001039 indent(f_service_);
iproctorff8eb922007-07-25 19:06:13 +00001040 }
1041 }
1042
1043 f_service_ << "(do" << endl;
1044 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001045 indent(f_service_);
1046
1047 if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void())
iproctorff8eb922007-07-25 19:06:13 +00001048 f_service_ << "res <- ";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001049
Anthony F. Molinaro71a58a82010-09-27 19:27:40 +00001050 f_service_ << "Iface." << decapitalize(tfunction->get_name()) << " handler";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001051 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
iproctorff8eb922007-07-25 19:06:13 +00001052 f_service_ << " (f_" << argsname << "_" << (*f_iter)->get_name() << " args)";
iproctorff8eb922007-07-25 19:06:13 +00001053
Christian Lavoie600a88c2010-11-07 18:37:11 +00001054 if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
iproctorff8eb922007-07-25 19:06:13 +00001055 f_service_ << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001056 indent(f_service_) << "return rs{f_" << resultname << "_success= Just res}";
1057
1058 } else if (!tfunction->is_oneway()) {
iproctorff8eb922007-07-25 19:06:13 +00001059 f_service_ << endl;
1060 indent(f_service_) << "return rs";
1061 }
Christian Lavoie600a88c2010-11-07 18:37:11 +00001062
iproctorff8eb922007-07-25 19:06:13 +00001063 f_service_ << ")" << endl;
1064 indent_down();
David Reiss0c90f6f2008-02-06 22:18:40 +00001065
David Reiss47329252009-03-24 20:01:02 +00001066 if (xceptions.size() > 0 && !tfunction->is_oneway()) {
iproctorff8eb922007-07-25 19:06:13 +00001067 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001068 indent(f_service_) << "(\\e -> " << endl;
iproctorff8eb922007-07-25 19:06:13 +00001069 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001070
1071 if (!tfunction->is_oneway()) {
1072 indent(f_service_) << "return rs{f_" << resultname << "_" << (*x_iter)->get_name() << " =Just e}";
1073
iproctorff8eb922007-07-25 19:06:13 +00001074 } else {
1075 indent(f_service_) << "return ()";
1076 }
Christian Lavoie600a88c2010-11-07 18:37:11 +00001077
iproctorff8eb922007-07-25 19:06:13 +00001078 f_service_ << "))" << endl;
1079 indent_down();
1080 indent_down();
1081 }
1082 }
1083
David Reissc51986f2009-03-24 20:01:25 +00001084 // Shortcut out here for oneway functions
David Reiss47329252009-03-24 20:01:02 +00001085 if (tfunction->is_oneway()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001086 indent(f_service_) << "return ()" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001087 indent_down();
1088 return;
1089 }
1090
Christian Lavoie600a88c2010-11-07 18:37:11 +00001091 indent(f_service_ ) << "writeMessageBegin oprot (\"" << tfunction->get_name() << "\", M_REPLY, seqid);" << endl;
1092 indent(f_service_ ) << "write_" << resultname << " oprot res" << endl;
1093 indent(f_service_ ) << "writeMessageEnd oprot" << endl;
1094 indent(f_service_ ) << "tFlush (getTransport oprot)" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001095
1096 // Close function
1097 indent_down();
1098}
1099
1100/**
1101 * Deserializes a field of any type.
1102 */
1103void t_hs_generator::generate_deserialize_field(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001104 t_field* tfield,
1105 string prefix) {
Roger Meier3b771a12010-11-17 22:11:26 +00001106 (void) prefix;
iproctorff8eb922007-07-25 19:06:13 +00001107 t_type* type = tfield->get_type();
1108 generate_deserialize_type(out,type);
1109}
1110
iproctorff8eb922007-07-25 19:06:13 +00001111/**
1112 * Deserializes a field of any type.
1113 */
1114void t_hs_generator::generate_deserialize_type(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001115 t_type* type) {
David Reisse087a302007-08-23 21:43:25 +00001116 type = get_true_type(type);
iproctorff8eb922007-07-25 19:06:13 +00001117
Christian Lavoie600a88c2010-11-07 18:37:11 +00001118 if (type->is_void())
iproctorff8eb922007-07-25 19:06:13 +00001119 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE";
iproctorff8eb922007-07-25 19:06:13 +00001120
1121 if (type->is_struct() || type->is_xception()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001122 generate_deserialize_struct(out, (t_struct*)type);
1123
iproctorff8eb922007-07-25 19:06:13 +00001124 } else if (type->is_container()) {
1125 generate_deserialize_container(out, type);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001126
iproctorff8eb922007-07-25 19:06:13 +00001127 } else if (type->is_base_type()) {
1128 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001129
iproctorff8eb922007-07-25 19:06:13 +00001130 switch (tbase) {
1131 case t_base_type::TYPE_VOID:
1132 throw "compiler error: cannot serialize void field in a struct";
1133 break;
David Reiss0c90f6f2008-02-06 22:18:40 +00001134 case t_base_type::TYPE_STRING:
Bryan Duxbury75a33e82010-09-22 00:48:56 +00001135 out << (((t_base_type*)type)->is_binary() ? "readBinary" : "readString");
iproctorff8eb922007-07-25 19:06:13 +00001136 break;
1137 case t_base_type::TYPE_BOOL:
1138 out << "readBool";
1139 break;
1140 case t_base_type::TYPE_BYTE:
1141 out << "readByte";
1142 break;
1143 case t_base_type::TYPE_I16:
1144 out << "readI16";
1145 break;
1146 case t_base_type::TYPE_I32:
1147 out << "readI32";
1148 break;
1149 case t_base_type::TYPE_I64:
1150 out << "readI64";
1151 break;
1152 case t_base_type::TYPE_DOUBLE:
1153 out << "readDouble";
1154 break;
1155 default:
David Reissdd7796f2007-08-28 21:09:06 +00001156 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
iproctorff8eb922007-07-25 19:06:13 +00001157 }
1158 out << " iprot";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001159
iproctorff8eb922007-07-25 19:06:13 +00001160 } else if (type->is_enum()) {
1161 string ename = capitalize(type->get_name());
Anthony F. Molinaro71a58a82010-09-27 19:27:40 +00001162 out << "(do {i <- readI32 iprot; return $ toEnum $ fromIntegral i})";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001163
iproctorff8eb922007-07-25 19:06:13 +00001164 } else {
1165 printf("DO NOT KNOW HOW TO DESERIALIZE TYPE '%s'\n",
1166 type->get_name().c_str());
1167 }
1168}
David Reiss0c90f6f2008-02-06 22:18:40 +00001169
iproctorff8eb922007-07-25 19:06:13 +00001170
1171/**
1172 * Generates an unserializer for a struct, calling read()
1173 */
1174void t_hs_generator::generate_deserialize_struct(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001175 t_struct* tstruct) {
iproctorff8eb922007-07-25 19:06:13 +00001176 string name = capitalize(tstruct->get_name());
1177 out << "(read_" << name << " iprot)";
iproctorff8eb922007-07-25 19:06:13 +00001178}
1179
1180/**
1181 * Serialize a container by writing out the header followed by
1182 * data and then a footer.
1183 */
1184void t_hs_generator::generate_deserialize_container(ofstream &out,
1185 t_type* ttype) {
1186 string size = tmp("_size");
1187 string ktype = tmp("_ktype");
1188 string vtype = tmp("_vtype");
1189 string etype = tmp("_etype");
1190 string con = tmp("_con");
David Reiss0c90f6f2008-02-06 22:18:40 +00001191
iproctorff8eb922007-07-25 19:06:13 +00001192 t_field fsize(g_type_i32, size);
1193 t_field fktype(g_type_byte, ktype);
1194 t_field fvtype(g_type_byte, vtype);
1195 t_field fetype(g_type_byte, etype);
1196
1197 // Declare variables, read header
1198 if (ttype->is_map()) {
1199 out << "(let {f 0 = return []; f n = do {k <- ";
1200 generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
Christian Lavoie600a88c2010-11-07 18:37:11 +00001201
iproctorff8eb922007-07-25 19:06:13 +00001202 out << "; v <- ";
1203 generate_deserialize_type(out,((t_map*)ttype)->get_val_type());
Christian Lavoie600a88c2010-11-07 18:37:11 +00001204
1205 out << ";r <- f (n-1); return $ (k,v):r}} in do {(" << ktype << "," << vtype << "," << size << ") <- readMapBegin iprot; l <- f " << size << "; return $ Map.fromList l})";
1206
iproctorff8eb922007-07-25 19:06:13 +00001207 } else if (ttype->is_set()) {
1208 out << "(let {f 0 = return []; f n = do {v <- ";
1209 generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
Christian Lavoie600a88c2010-11-07 18:37:11 +00001210 out << ";r <- f (n-1); return $ v:r}} in do {(" << etype << "," << size << ") <- readSetBegin iprot; l <- f " << size << "; return $ Set.fromList l})";
1211
iproctorff8eb922007-07-25 19:06:13 +00001212 } else if (ttype->is_list()) {
1213 out << "(let {f 0 = return []; f n = do {v <- ";
1214 generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
Christian Lavoie600a88c2010-11-07 18:37:11 +00001215 out << ";r <- f (n-1); return $ v:r}} in do {(" << etype << "," << size << ") <- readListBegin iprot; f " << size << "})";
iproctorff8eb922007-07-25 19:06:13 +00001216 }
1217}
1218
iproctorff8eb922007-07-25 19:06:13 +00001219/**
1220 * Serializes a field of any type.
1221 *
1222 * @param tfield The field to serialize
1223 * @param prefix Name to prepend to field name
1224 */
1225void t_hs_generator::generate_serialize_field(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001226 t_field* tfield,
1227 string name) {
David Reisse087a302007-08-23 21:43:25 +00001228 t_type* type = get_true_type(tfield->get_type());
iproctorff8eb922007-07-25 19:06:13 +00001229
1230 // Do nothing for void types
Christian Lavoie600a88c2010-11-07 18:37:11 +00001231 if (type->is_void())
1232 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + tfield->get_name();
iproctorff8eb922007-07-25 19:06:13 +00001233
Christian Lavoie600a88c2010-11-07 18:37:11 +00001234 if (name.length() == 0)
iproctorff8eb922007-07-25 19:06:13 +00001235 name = decapitalize(tfield->get_name());
iproctorff8eb922007-07-25 19:06:13 +00001236
1237 if (type->is_struct() || type->is_xception()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001238 generate_serialize_struct(out, (t_struct*)type, name);
1239
iproctorff8eb922007-07-25 19:06:13 +00001240 } else if (type->is_container()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001241 generate_serialize_container(out, type, name);
1242
iproctorff8eb922007-07-25 19:06:13 +00001243 } else if (type->is_base_type() || type->is_enum()) {
1244 if (type->is_base_type()) {
1245 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1246 switch (tbase) {
1247 case t_base_type::TYPE_VOID:
1248 throw
1249 "compiler error: cannot serialize void field in a struct: " + name;
1250 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001251
iproctorff8eb922007-07-25 19:06:13 +00001252 case t_base_type::TYPE_STRING:
Bryan Duxbury75a33e82010-09-22 00:48:56 +00001253 out << (((t_base_type*)type)->is_binary() ? "writeBinary" : "writeString") << " oprot " << name;
iproctorff8eb922007-07-25 19:06:13 +00001254 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001255
iproctorff8eb922007-07-25 19:06:13 +00001256 case t_base_type::TYPE_BOOL:
1257 out << "writeBool oprot " << name;
1258 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001259
iproctorff8eb922007-07-25 19:06:13 +00001260 case t_base_type::TYPE_BYTE:
1261 out << "writeByte oprot " << name;
1262 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001263
iproctorff8eb922007-07-25 19:06:13 +00001264 case t_base_type::TYPE_I16:
1265 out << "writeI16 oprot " << name;
1266 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001267
iproctorff8eb922007-07-25 19:06:13 +00001268 case t_base_type::TYPE_I32:
1269 out << "writeI32 oprot " << name;
1270 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001271
iproctorff8eb922007-07-25 19:06:13 +00001272 case t_base_type::TYPE_I64:
1273 out << "writeI64 oprot " << name;
1274 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001275
iproctorff8eb922007-07-25 19:06:13 +00001276 case t_base_type::TYPE_DOUBLE:
1277 out << "writeDouble oprot " << name;
1278 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001279
iproctorff8eb922007-07-25 19:06:13 +00001280 default:
David Reissdd7796f2007-08-28 21:09:06 +00001281 throw "compiler error: no hs name for base type " + t_base_type::t_base_name(tbase);
iproctorff8eb922007-07-25 19:06:13 +00001282 }
David Reiss0c90f6f2008-02-06 22:18:40 +00001283
iproctorff8eb922007-07-25 19:06:13 +00001284 } else if (type->is_enum()) {
1285 string ename = capitalize(type->get_name());
Christian Lavoie600a88c2010-11-07 18:37:11 +00001286 out << "writeI32 oprot (fromIntegral $ fromEnum " << name << ")";
iproctorff8eb922007-07-25 19:06:13 +00001287 }
David Reiss0c90f6f2008-02-06 22:18:40 +00001288
iproctorff8eb922007-07-25 19:06:13 +00001289 } else {
1290 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
1291 tfield->get_name().c_str(),
1292 type->get_name().c_str());
1293 }
1294}
1295
1296/**
1297 * Serializes all the members of a struct.
1298 *
1299 * @param tstruct The struct to serialize
1300 * @param prefix String prefix to attach to all fields
1301 */
1302void t_hs_generator::generate_serialize_struct(ofstream &out,
1303 t_struct* tstruct,
1304 string prefix) {
David Reiss752529e2010-01-11 19:12:56 +00001305 out << type_name(tstruct, "write_") << " oprot " << prefix;
iproctorff8eb922007-07-25 19:06:13 +00001306}
1307
1308void t_hs_generator::generate_serialize_container(ofstream &out,
1309 t_type* ttype,
1310 string prefix) {
1311 if (ttype->is_map()) {
1312 string k = tmp("_kiter");
1313 string v = tmp("_viter");
Christian Lavoie600a88c2010-11-07 18:37:11 +00001314 out << "(let {f [] = return (); f ((" << k << "," << v << "):t) = do {";
iproctorff8eb922007-07-25 19:06:13 +00001315 generate_serialize_map_element(out, (t_map*)ttype, k, v);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001316 out << ";f t}} in do {writeMapBegin oprot (" << type_to_enum(((t_map*)ttype)->get_key_type()) << "," << type_to_enum(((t_map*)ttype)->get_val_type()) << ",fromIntegral $ Map.size " << prefix << "); f (Map.toList " << prefix << ");writeMapEnd oprot})";
1317
iproctorff8eb922007-07-25 19:06:13 +00001318 } else if (ttype->is_set()) {
1319 string v = tmp("_viter");
Christian Lavoie600a88c2010-11-07 18:37:11 +00001320 out << "(let {f [] = return (); f (" << v << ":t) = do {";
iproctorff8eb922007-07-25 19:06:13 +00001321 generate_serialize_set_element(out, (t_set*)ttype, v);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001322 out << ";f t}} in do {writeSetBegin oprot (" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ",fromIntegral $ Set.size " << prefix << "); f (Set.toList " << prefix << ");writeSetEnd oprot})";
1323
iproctorff8eb922007-07-25 19:06:13 +00001324 } else if (ttype->is_list()) {
1325 string v = tmp("_viter");
Christian Lavoie600a88c2010-11-07 18:37:11 +00001326 out << "(let {f [] = return (); f (" << v << ":t) = do {";
iproctorff8eb922007-07-25 19:06:13 +00001327 generate_serialize_list_element(out, (t_list*)ttype, v);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001328 out << ";f t}} in do {writeListBegin oprot (" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ",fromIntegral $ Prelude.length " << prefix << "); f " << prefix << ";writeListEnd oprot})";
iproctorff8eb922007-07-25 19:06:13 +00001329 }
1330
1331}
1332
1333/**
1334 * Serializes the members of a map.
1335 *
1336 */
1337void t_hs_generator::generate_serialize_map_element(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001338 t_map* tmap,
1339 string kiter,
1340 string viter) {
iproctorff8eb922007-07-25 19:06:13 +00001341 t_field kfield(tmap->get_key_type(), kiter);
1342 out << "do {";
1343 generate_serialize_field(out, &kfield);
1344 out << ";";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001345
iproctorff8eb922007-07-25 19:06:13 +00001346 t_field vfield(tmap->get_val_type(), viter);
1347 generate_serialize_field(out, &vfield);
1348 out << "}";
1349}
1350
1351/**
1352 * Serializes the members of a set.
1353 */
1354void t_hs_generator::generate_serialize_set_element(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001355 t_set* tset,
1356 string iter) {
iproctorff8eb922007-07-25 19:06:13 +00001357 t_field efield(tset->get_elem_type(), iter);
1358 generate_serialize_field(out, &efield);
1359}
1360
1361/**
1362 * Serializes the members of a list.
1363 */
1364void t_hs_generator::generate_serialize_list_element(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001365 t_list* tlist,
1366 string iter) {
iproctorff8eb922007-07-25 19:06:13 +00001367 t_field efield(tlist->get_elem_type(), iter);
1368 generate_serialize_field(out, &efield);
1369}
1370
Christian Lavoie600a88c2010-11-07 18:37:11 +00001371string t_hs_generator::function_type(t_function* tfunc, bool options, bool io, bool method) {
1372 string result = "";
David Reiss0c90f6f2008-02-06 22:18:40 +00001373
iproctorff8eb922007-07-25 19:06:13 +00001374 const vector<t_field*>& fields = tfunc->get_arglist()->get_members();
1375 vector<t_field*>::const_iterator f_iter;
1376 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001377 if (options) result += "Maybe ";
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001378 result += render_hs_type((*f_iter)->get_type(), options);
iproctorff8eb922007-07-25 19:06:13 +00001379 result += " -> ";
1380 }
Christian Lavoie600a88c2010-11-07 18:37:11 +00001381
1382 if (fields.empty() && !method)
iproctorff8eb922007-07-25 19:06:13 +00001383 result += "() -> ";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001384
1385 if (io)
1386 result += "IO ";
1387
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001388 result += render_hs_type(tfunc->get_returntype(), io);
iproctorff8eb922007-07-25 19:06:13 +00001389 return result;
1390}
1391
1392
David Reiss752529e2010-01-11 19:12:56 +00001393string t_hs_generator::type_name(t_type* ttype, string function_prefix) {
iproctorff8eb922007-07-25 19:06:13 +00001394 string prefix = "";
1395 t_program* program = ttype->get_program();
iproctorff8eb922007-07-25 19:06:13 +00001396
Christian Lavoie600a88c2010-11-07 18:37:11 +00001397 if (program != NULL && program != program_)
1398 if (!ttype->is_service())
1399 prefix = capitalize(program->get_name()) + "_Types.";
1400
1401 return prefix + function_prefix + capitalize(ttype->get_name());
iproctorff8eb922007-07-25 19:06:13 +00001402}
1403
1404/**
1405 * Converts the parse type to a Protocol.t_type enum
1406 */
1407string t_hs_generator::type_to_enum(t_type* type) {
David Reisse087a302007-08-23 21:43:25 +00001408 type = get_true_type(type);
David Reiss0c90f6f2008-02-06 22:18:40 +00001409
iproctorff8eb922007-07-25 19:06:13 +00001410 if (type->is_base_type()) {
1411 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1412 switch (tbase) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001413 case t_base_type::TYPE_VOID: return "T_VOID";
1414 case t_base_type::TYPE_STRING: return "T_STRING";
1415 case t_base_type::TYPE_BOOL: return "T_BOOL";
1416 case t_base_type::TYPE_BYTE: return "T_BYTE";
1417 case t_base_type::TYPE_I16: return "T_I16";
1418 case t_base_type::TYPE_I32: return "T_I32";
1419 case t_base_type::TYPE_I64: return "T_I64";
1420 case t_base_type::TYPE_DOUBLE: return "T_DOUBLE";
iproctorff8eb922007-07-25 19:06:13 +00001421 }
Christian Lavoie600a88c2010-11-07 18:37:11 +00001422
iproctorff8eb922007-07-25 19:06:13 +00001423 } else if (type->is_enum()) {
1424 return "T_I32";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001425
iproctorff8eb922007-07-25 19:06:13 +00001426 } else if (type->is_struct() || type->is_xception()) {
1427 return "T_STRUCT";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001428
iproctorff8eb922007-07-25 19:06:13 +00001429 } else if (type->is_map()) {
1430 return "T_MAP";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001431
iproctorff8eb922007-07-25 19:06:13 +00001432 } else if (type->is_set()) {
1433 return "T_SET";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001434
iproctorff8eb922007-07-25 19:06:13 +00001435 } else if (type->is_list()) {
1436 return "T_LIST";
1437 }
1438
1439 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
1440}
1441
1442/**
1443 * Converts the parse type to an haskell type
1444 */
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001445string t_hs_generator::render_hs_type(t_type* type, bool needs_parens) {
David Reisse087a302007-08-23 21:43:25 +00001446 type = get_true_type(type);
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001447 string type_repr;
David Reiss0c90f6f2008-02-06 22:18:40 +00001448
iproctorff8eb922007-07-25 19:06:13 +00001449 if (type->is_base_type()) {
1450 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1451 switch (tbase) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001452 case t_base_type::TYPE_VOID: return "()";
1453 case t_base_type::TYPE_STRING: return (((t_base_type*)type)->is_binary() ? "ByteString" : "String");
1454 case t_base_type::TYPE_BOOL: return "Bool";
1455 case t_base_type::TYPE_BYTE: return "Int8";
1456 case t_base_type::TYPE_I16: return "Int16";
1457 case t_base_type::TYPE_I32: return "Int32";
1458 case t_base_type::TYPE_I64: return "Int64";
1459 case t_base_type::TYPE_DOUBLE: return "Double";
iproctorff8eb922007-07-25 19:06:13 +00001460 }
Christian Lavoie600a88c2010-11-07 18:37:11 +00001461
iproctorff8eb922007-07-25 19:06:13 +00001462 } else if (type->is_enum()) {
1463 return capitalize(((t_enum*)type)->get_name());
Christian Lavoie600a88c2010-11-07 18:37:11 +00001464
iproctorff8eb922007-07-25 19:06:13 +00001465 } else if (type->is_struct() || type->is_xception()) {
1466 return type_name((t_struct*)type);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001467
iproctorff8eb922007-07-25 19:06:13 +00001468 } else if (type->is_map()) {
1469 t_type* ktype = ((t_map*)type)->get_key_type();
1470 t_type* vtype = ((t_map*)type)->get_val_type();
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001471 type_repr = "Map.Map " + render_hs_type(ktype, true) + " " + render_hs_type(vtype, true);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001472
iproctorff8eb922007-07-25 19:06:13 +00001473 } else if (type->is_set()) {
1474 t_type* etype = ((t_set*)type)->get_elem_type();
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001475 type_repr = "Set.Set " + render_hs_type(etype, true) ;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001476
iproctorff8eb922007-07-25 19:06:13 +00001477 } else if (type->is_list()) {
1478 t_type* etype = ((t_list*)type)->get_elem_type();
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001479 return "[" + render_hs_type(etype, false) + "]";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001480
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001481 } else {
1482 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
iproctorff8eb922007-07-25 19:06:13 +00001483 }
1484
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001485 return needs_parens ? "(" + type_repr + ")" : type_repr;
iproctorff8eb922007-07-25 19:06:13 +00001486}
David Reissaf3ab262008-03-27 21:40:16 +00001487
Roger Meier0069cc42010-10-13 18:10:18 +00001488THRIFT_REGISTER_GENERATOR(hs, "Haskell", "")