blob: bbfaba566092cc2f3ef7bd2f62631bb32e1f0704 [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
Jens Geyer945537c2013-01-04 19:33:29 +010034using std::map;
35using std::ofstream;
36using std::ostringstream;
37using std::string;
38using std::stringstream;
39using std::vector;
40
41static const string endl = "\n"; // avoid ostream << std::endl flushes
David Reiss42e6d512008-03-27 21:40:20 +000042
43/**
44 * Haskell code generator.
45 *
David Reiss42e6d512008-03-27 21:40:20 +000046 */
47class t_hs_generator : public t_oop_generator {
48 public:
Christian Lavoie600a88c2010-11-07 18:37:11 +000049 t_hs_generator(t_program* program,
50 const map<string, string>& parsed_options,
51 const string& option_string)
David Reiss42e6d512008-03-27 21:40:20 +000052 : t_oop_generator(program)
53 {
Roger Meier3b771a12010-11-17 22:11:26 +000054 (void) parsed_options;
55 (void) option_string;
David Reiss42e6d512008-03-27 21:40:20 +000056 out_dir_base_ = "gen-hs";
57 }
58
59 /**
60 * Init and close methods
61 */
62
63 void init_generator();
64 void close_generator();
65
66 /**
67 * Program-level generation functions
68 */
David Reiss42e6d512008-03-27 21:40:20 +000069 void generate_typedef (t_typedef* ttypedef);
70 void generate_enum (t_enum* tenum);
71 void generate_const (t_const* tconst);
72 void generate_struct (t_struct* tstruct);
73 void generate_xception (t_struct* txception);
74 void generate_service (t_service* tservice);
75
Christian Lavoie600a88c2010-11-07 18:37:11 +000076 string render_const_value(t_type* type, t_const_value* value);
David Reiss42e6d512008-03-27 21:40:20 +000077
78 /**
79 * Struct generation code
80 */
81
Christian Lavoie600a88c2010-11-07 18:37:11 +000082 void generate_hs_struct (t_struct* tstruct,
83 bool is_exception);
84
85 void generate_hs_struct_definition (ofstream &out,
86 t_struct* tstruct,
87 bool is_xception = false,
88 bool helper = false);
89
90 void generate_hs_struct_reader (ofstream& out,
91 t_struct* tstruct);
92
93 void generate_hs_struct_writer (ofstream& out,
94 t_struct* tstruct);
95
96 void generate_hs_function_helpers (t_function* tfunction);
David Reiss42e6d512008-03-27 21:40:20 +000097
98 /**
99 * Service-level generation functions
100 */
101
Christian Lavoie600a88c2010-11-07 18:37:11 +0000102 void generate_service_helpers (t_service* tservice);
David Reiss42e6d512008-03-27 21:40:20 +0000103 void generate_service_interface (t_service* tservice);
104 void generate_service_client (t_service* tservice);
105 void generate_service_server (t_service* tservice);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000106 void generate_process_function (t_service* tservice,
107 t_function* tfunction);
David Reiss42e6d512008-03-27 21:40:20 +0000108
109 /**
110 * Serialization constructs
111 */
112
Christian Lavoie600a88c2010-11-07 18:37:11 +0000113 void generate_deserialize_field (ofstream &out,
114 t_field* tfield,
115 string prefix);
David Reiss42e6d512008-03-27 21:40:20 +0000116
Christian Lavoie600a88c2010-11-07 18:37:11 +0000117 void generate_deserialize_struct (ofstream &out,
118 t_struct* tstruct);
David Reiss42e6d512008-03-27 21:40:20 +0000119
Christian Lavoie600a88c2010-11-07 18:37:11 +0000120 void generate_deserialize_container (ofstream &out,
121 t_type* ttype);
David Reiss42e6d512008-03-27 21:40:20 +0000122
Christian Lavoie600a88c2010-11-07 18:37:11 +0000123 void generate_deserialize_set_element (ofstream &out,
124 t_set* tset);
David Reiss42e6d512008-03-27 21:40:20 +0000125
126
Christian Lavoie600a88c2010-11-07 18:37:11 +0000127 void generate_deserialize_list_element (ofstream &out,
128 t_list* tlist,
129 string prefix = "");
130
131 void generate_deserialize_type (ofstream &out,
David Reiss42e6d512008-03-27 21:40:20 +0000132 t_type* type);
133
Christian Lavoie600a88c2010-11-07 18:37:11 +0000134 void generate_serialize_field (ofstream &out,
135 t_field* tfield,
136 string name = "");
David Reiss42e6d512008-03-27 21:40:20 +0000137
Christian Lavoie600a88c2010-11-07 18:37:11 +0000138 void generate_serialize_struct (ofstream &out,
139 t_struct* tstruct,
140 string prefix = "");
David Reiss42e6d512008-03-27 21:40:20 +0000141
Christian Lavoie600a88c2010-11-07 18:37:11 +0000142 void generate_serialize_container (ofstream &out,
143 t_type* ttype,
144 string prefix = "");
David Reiss42e6d512008-03-27 21:40:20 +0000145
Christian Lavoie600a88c2010-11-07 18:37:11 +0000146 void generate_serialize_map_element (ofstream &out,
147 t_map* tmap,
148 string kiter,
149 string viter);
David Reiss42e6d512008-03-27 21:40:20 +0000150
Christian Lavoie600a88c2010-11-07 18:37:11 +0000151 void generate_serialize_set_element (ofstream &out,
152 t_set* tmap,
153 string iter);
David Reiss42e6d512008-03-27 21:40:20 +0000154
Christian Lavoie600a88c2010-11-07 18:37:11 +0000155 void generate_serialize_list_element (ofstream &out,
156 t_list* tlist,
157 string iter);
David Reiss42e6d512008-03-27 21:40:20 +0000158
159 /**
160 * Helper rendering functions
161 */
162
Christian Lavoie600a88c2010-11-07 18:37:11 +0000163 string hs_autogen_comment();
164 string hs_language_pragma();
165 string hs_imports();
David Reiss42e6d512008-03-27 21:40:20 +0000166
Christian Lavoie600a88c2010-11-07 18:37:11 +0000167 string type_name(t_type* ttype,
168 string function_prefix = "");
169
170 string function_type(t_function* tfunc,
171 bool options = false,
172 bool io = false,
173 bool method = false);
174
175 string type_to_enum(t_type* ttype);
176
177 string render_hs_type(t_type* type,
Roger Meier6849f202012-05-18 07:35:19 +0000178 bool needs_parens);
David Reiss42e6d512008-03-27 21:40:20 +0000179
180 private:
Christian Lavoie600a88c2010-11-07 18:37:11 +0000181 ofstream f_types_;
182 ofstream f_consts_;
183 ofstream f_service_;
184 ofstream f_iface_;
185 ofstream f_client_;
David Reiss42e6d512008-03-27 21:40:20 +0000186};
187
iproctorff8eb922007-07-25 19:06:13 +0000188/**
189 * Prepares for file generation by opening up the necessary file output
190 * streams.
191 *
192 * @param tprogram The program to generate
193 */
194void t_hs_generator::init_generator() {
195 // Make output directory
David Reiss204420f2008-01-11 20:59:03 +0000196 MKDIR(get_out_dir().c_str());
iproctorff8eb922007-07-25 19:06:13 +0000197
198 // Make output file
iproctorff8eb922007-07-25 19:06:13 +0000199 string pname = capitalize(program_name_);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000200 string f_types_name = get_out_dir() + pname + "_Types.hs";
iproctorff8eb922007-07-25 19:06:13 +0000201 f_types_.open(f_types_name.c_str());
202
Christian Lavoie600a88c2010-11-07 18:37:11 +0000203 string f_consts_name = get_out_dir() + pname + "_Consts.hs";
iproctorff8eb922007-07-25 19:06:13 +0000204 f_consts_.open(f_consts_name.c_str());
205
206 // Print header
Christian Lavoie600a88c2010-11-07 18:37:11 +0000207 f_types_ << hs_language_pragma() << endl;
208 f_types_ << hs_autogen_comment() << endl;
209 f_types_ << "module " << pname << "_Types where" << endl;
210 f_types_ << hs_imports() << endl;
iproctorff8eb922007-07-25 19:06:13 +0000211
Christian Lavoie600a88c2010-11-07 18:37:11 +0000212 f_consts_ << hs_language_pragma() << endl;
213 f_consts_ << hs_autogen_comment() << endl;
214 f_consts_ << "module " << pname << "_Consts where" << endl;
215 f_consts_ << hs_imports() << endl;
216 f_consts_ << "import " << pname << "_Types" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000217}
218
David Reiss752529e2010-01-11 19:12:56 +0000219string t_hs_generator::hs_language_pragma() {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000220 return string("{-# LANGUAGE DeriveDataTypeable #-}\n"
Roger Meier6849f202012-05-18 07:35:19 +0000221 "{-# LANGUAGE OverloadedStrings #-}\n"
Christian Lavoie600a88c2010-11-07 18:37:11 +0000222 "{-# OPTIONS_GHC -fno-warn-missing-fields #-}\n"
223 "{-# OPTIONS_GHC -fno-warn-missing-signatures #-}\n"
224 "{-# OPTIONS_GHC -fno-warn-name-shadowing #-}\n"
225 "{-# OPTIONS_GHC -fno-warn-unused-imports #-}\n"
226 "{-# OPTIONS_GHC -fno-warn-unused-matches #-}\n");
David Reiss752529e2010-01-11 19:12:56 +0000227}
iproctorff8eb922007-07-25 19:06:13 +0000228
229/**
230 * Autogen'd comment
231 */
232string t_hs_generator::hs_autogen_comment() {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000233 return string("-----------------------------------------------------------------\n") +
Roger Meier08d46812011-04-12 19:08:21 +0000234 "-- Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ") --\n" +
Christian Lavoie600a88c2010-11-07 18:37:11 +0000235 "-- --\n" +
236 "-- DO NOT EDIT UNLESS YOU ARE SURE YOU KNOW WHAT YOU ARE DOING --\n" +
237 "-----------------------------------------------------------------\n";
iproctorff8eb922007-07-25 19:06:13 +0000238}
239
240/**
241 * Prints standard thrift imports
242 */
243string t_hs_generator::hs_imports() {
David Reiss752529e2010-01-11 19:12:56 +0000244 const vector<t_program*>& includes = program_->get_includes();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000245 string result = string(
246 "import Prelude ( Bool(..), Enum, Double, String, Maybe(..),\n"
247 " Eq, Show, Ord,\n"
248 " return, length, IO, fromIntegral, fromEnum, toEnum,\n"
Roger Meier6849f202012-05-18 07:35:19 +0000249 " (.), (&&), (||), (==), (++), ($), (-) )\n"
Christian Lavoie600a88c2010-11-07 18:37:11 +0000250 "\n"
251 "import Control.Exception\n"
252 "import Data.ByteString.Lazy\n"
Roger Meier6849f202012-05-18 07:35:19 +0000253 "import Data.Hashable\n"
Christian Lavoie600a88c2010-11-07 18:37:11 +0000254 "import Data.Int\n"
Roger Meier6849f202012-05-18 07:35:19 +0000255 "import Data.Text.Lazy ( Text )\n"
256 "import qualified Data.Text.Lazy as TL\n"
Christian Lavoie600a88c2010-11-07 18:37:11 +0000257 "import Data.Typeable ( Typeable )\n"
Roger Meier6849f202012-05-18 07:35:19 +0000258 "import qualified Data.HashMap.Strict as Map\n"
259 "import qualified Data.HashSet as Set\n"
260 "import qualified Data.Vector as Vector\n"
Christian Lavoie600a88c2010-11-07 18:37:11 +0000261 "\n"
262 "import Thrift\n"
Roger Meier6849f202012-05-18 07:35:19 +0000263 "import Thrift.Types ()\n"
Christian Lavoie600a88c2010-11-07 18:37:11 +0000264 "\n");
David Reiss752529e2010-01-11 19:12:56 +0000265
Christian Lavoie600a88c2010-11-07 18:37:11 +0000266 for (size_t i = 0; i < includes.size(); ++i)
267 result += "import qualified " + capitalize(includes[i]->get_name()) + "_Types\n";
268
269 if (includes.size() > 0)
270 result += "\n";
271
David Reiss752529e2010-01-11 19:12:56 +0000272 return result;
iproctorff8eb922007-07-25 19:06:13 +0000273}
274
275/**
276 * Closes the type files
277 */
278void t_hs_generator::close_generator() {
279 // Close types file
280 f_types_.close();
281 f_consts_.close();
282}
David Reiss0c90f6f2008-02-06 22:18:40 +0000283
iproctorff8eb922007-07-25 19:06:13 +0000284/**
285 * Generates a typedef. Ez.
286 *
287 * @param ttypedef The type definition
288 */
289void t_hs_generator::generate_typedef(t_typedef* ttypedef) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000290 string tname = capitalize(ttypedef->get_symbolic());
291 string tdef = render_hs_type(ttypedef->get_type(), false);
292 indent(f_types_) << "type " << tname << " = " << tdef << endl;
293 f_types_ << endl;
iproctorff8eb922007-07-25 19:06:13 +0000294}
295
296/**
David Reiss0c90f6f2008-02-06 22:18:40 +0000297 * Generates code for an enumerated type.
iproctorff8eb922007-07-25 19:06:13 +0000298 * the values.
299 *
300 * @param tenum The enumeration
301 */
302void t_hs_generator::generate_enum(t_enum* tenum) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000303 indent(f_types_) << "data " << capitalize(tenum->get_name()) << " = ";
iproctorff8eb922007-07-25 19:06:13 +0000304 indent_up();
305 vector<t_enum_value*> constants = tenum->get_constants();
306 vector<t_enum_value*>::iterator c_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000307
iproctorff8eb922007-07-25 19:06:13 +0000308 bool first = true;
309 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
310 string name = capitalize((*c_iter)->get_name());
Christian Lavoie600a88c2010-11-07 18:37:11 +0000311 f_types_ << (first ? "" : "|");
iproctorff8eb922007-07-25 19:06:13 +0000312 f_types_ << name;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000313 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000314 }
Bryan Duxbury0781f2b2009-04-07 23:29:42 +0000315 indent(f_types_) << "deriving (Show,Eq, Typeable, Ord)" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000316 indent_down();
317
Christian Lavoie600a88c2010-11-07 18:37:11 +0000318 string ename = capitalize(tenum->get_name());
Roger Meier6849f202012-05-18 07:35:19 +0000319
Christian Lavoie600a88c2010-11-07 18:37:11 +0000320 indent(f_types_) << "instance Enum " << ename << " where" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000321 indent_up();
322 indent(f_types_) << "fromEnum t = case t of" << endl;
323 indent_up();
324 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
Bryan Duxburya406b902010-09-27 23:37:44 +0000325 int value = (*c_iter)->get_value();
iproctorff8eb922007-07-25 19:06:13 +0000326 string name = capitalize((*c_iter)->get_name());
Bryan Duxburya406b902010-09-27 23:37:44 +0000327 indent(f_types_) << name << " -> " << value << endl;
iproctorff8eb922007-07-25 19:06:13 +0000328 }
329 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000330 indent(f_types_) << "toEnum t = case t of" << endl;
331 indent_up();
332 for(c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
Bryan Duxburya406b902010-09-27 23:37:44 +0000333 int value = (*c_iter)->get_value();
iproctorff8eb922007-07-25 19:06:13 +0000334 string name = capitalize((*c_iter)->get_name());
Bryan Duxburya406b902010-09-27 23:37:44 +0000335 indent(f_types_) << value << " -> " << name << endl;
iproctorff8eb922007-07-25 19:06:13 +0000336 }
Bryan Duxbury0781f2b2009-04-07 23:29:42 +0000337 indent(f_types_) << "_ -> throw ThriftException" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000338 indent_down();
339 indent_down();
Roger Meier6849f202012-05-18 07:35:19 +0000340
341 indent(f_types_) << "instance Hashable " << ename << " where" << endl;
342 indent_up();
343 indent(f_types_) << "hashWithSalt salt = hashWithSalt salt . fromEnum" << endl;
344 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000345}
346
347/**
348 * Generate a constant value
349 */
350void t_hs_generator::generate_const(t_const* tconst) {
351 t_type* type = tconst->get_type();
352 string name = decapitalize(tconst->get_name());
Christian Lavoie600a88c2010-11-07 18:37:11 +0000353
iproctorff8eb922007-07-25 19:06:13 +0000354 t_const_value* value = tconst->get_value();
355
Kevin Clark4798a7a2009-03-24 15:56:19 +0000356 indent(f_consts_) << name << " :: " << render_hs_type(type, false) << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000357 indent(f_consts_) << name << " = " << render_const_value(type, value) << endl;
358 f_consts_ << endl;
iproctorff8eb922007-07-25 19:06:13 +0000359}
360
361/**
362 * Prints the value of a constant with the given type. Note that type checking
363 * is NOT performed in this function as it is always run beforehand using the
364 * validate_types method in main.cc
365 */
366string t_hs_generator::render_const_value(t_type* type, t_const_value* value) {
David Reiss9a4edfa2008-05-01 05:52:50 +0000367 type = get_true_type(type);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000368 ostringstream out;
369
iproctorff8eb922007-07-25 19:06:13 +0000370 if (type->is_base_type()) {
371 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
372 switch (tbase) {
Bryan Duxbury75a33e82010-09-22 00:48:56 +0000373
iproctorff8eb922007-07-25 19:06:13 +0000374 case t_base_type::TYPE_STRING:
David Reiss82e6fc02009-03-26 23:32:36 +0000375 out << '"' << get_escaped_string(value) << '"';
iproctorff8eb922007-07-25 19:06:13 +0000376 break;
Bryan Duxbury75a33e82010-09-22 00:48:56 +0000377
iproctorff8eb922007-07-25 19:06:13 +0000378 case t_base_type::TYPE_BOOL:
379 out << (value->get_integer() > 0 ? "True" : "False");
380 break;
Bryan Duxbury75a33e82010-09-22 00:48:56 +0000381
iproctorff8eb922007-07-25 19:06:13 +0000382 case t_base_type::TYPE_BYTE:
Christian Lavoieae7f7fa2010-11-02 21:42:53 +0000383 out << "(" << value->get_integer() << " :: Int8)";
iproctorff8eb922007-07-25 19:06:13 +0000384 break;
Bryan Duxbury75a33e82010-09-22 00:48:56 +0000385
386 case t_base_type::TYPE_I16:
387 out << "(" << value->get_integer() << " :: Int16)";
388 break;
389
390 case t_base_type::TYPE_I32:
391 out << "(" << value->get_integer() << " :: Int32)";
392 break;
393
394 case t_base_type::TYPE_I64:
395 out << "(" << value->get_integer() << " :: Int64)";
396 break;
397
iproctorff8eb922007-07-25 19:06:13 +0000398 case t_base_type::TYPE_DOUBLE:
399 if (value->get_type() == t_const_value::CV_INTEGER) {
400 out << value->get_integer();
401 } else {
402 out << value->get_double();
403 }
404 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000405
iproctorff8eb922007-07-25 19:06:13 +0000406 default:
David Reissdd7796f2007-08-28 21:09:06 +0000407 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
iproctorff8eb922007-07-25 19:06:13 +0000408 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000409
iproctorff8eb922007-07-25 19:06:13 +0000410 } else if (type->is_enum()) {
411 t_enum* tenum = (t_enum*)type;
412 vector<t_enum_value*> constants = tenum->get_constants();
413 vector<t_enum_value*>::iterator c_iter;
iproctorff8eb922007-07-25 19:06:13 +0000414 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
Bryan Duxburya406b902010-09-27 23:37:44 +0000415 int val = (*c_iter)->get_value();
416 if (val == value->get_integer()) {
iproctorff8eb922007-07-25 19:06:13 +0000417 indent(out) << capitalize((*c_iter)->get_name());
418 break;
419 }
420 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000421
iproctorff8eb922007-07-25 19:06:13 +0000422 } else if (type->is_struct() || type->is_xception()) {
423 string cname = type_name(type);
424 indent(out) << cname << "{";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000425
iproctorff8eb922007-07-25 19:06:13 +0000426 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
427 vector<t_field*>::const_iterator f_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000428
iproctorff8eb922007-07-25 19:06:13 +0000429 const map<t_const_value*, t_const_value*>& val = value->get_map();
430 map<t_const_value*, t_const_value*>::const_iterator v_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000431
iproctorff8eb922007-07-25 19:06:13 +0000432 bool first = true;
433 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
434 t_type* field_type = NULL;
iproctorff8eb922007-07-25 19:06:13 +0000435
Christian Lavoie600a88c2010-11-07 18:37:11 +0000436 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
437 if ((*f_iter)->get_name() == v_iter->first->get_string())
438 field_type = (*f_iter)->get_type();
439
440 if (field_type == NULL)
441 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
442
443 string fname = v_iter->first->get_string();
444 string const_value = render_const_value(field_type, v_iter->second);
445
446 out << (first ? "" : ",");
447 out << "f_" << cname << "_" << fname << " = Just (" << const_value << ")";
448 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000449 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000450
iproctorff8eb922007-07-25 19:06:13 +0000451 indent(out) << "}";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000452
iproctorff8eb922007-07-25 19:06:13 +0000453 } else if (type->is_map()) {
454 t_type* ktype = ((t_map*)type)->get_key_type();
455 t_type* vtype = ((t_map*)type)->get_val_type();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000456
iproctorff8eb922007-07-25 19:06:13 +0000457 const map<t_const_value*, t_const_value*>& val = value->get_map();
458 map<t_const_value*, t_const_value*>::const_iterator v_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000459
iproctorff8eb922007-07-25 19:06:13 +0000460 out << "(Map.fromList [";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000461
462 bool first = true;
iproctorff8eb922007-07-25 19:06:13 +0000463 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
464 string key = render_const_value(ktype, v_iter->first);
465 string val = render_const_value(vtype, v_iter->second);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000466 out << (first ? "" : ",");
467 out << "(" << key << "," << val << ")";
468 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000469 }
470 out << "])";
Kevin Clark4798a7a2009-03-24 15:56:19 +0000471
Christian Lavoie600a88c2010-11-07 18:37:11 +0000472 } else if (type->is_list() || type->is_set()) {
473 t_type* etype = type->is_list()
474 ? ((t_list*) type)->get_elem_type()
475 : ((t_set*) type)->get_elem_type();
Kevin Clark4798a7a2009-03-24 15:56:19 +0000476
iproctorff8eb922007-07-25 19:06:13 +0000477 const vector<t_const_value*>& val = value->get_list();
478 vector<t_const_value*>::const_iterator v_iter;
Kevin Clark4798a7a2009-03-24 15:56:19 +0000479
480 if (type->is_set())
Roger Meier6849f202012-05-18 07:35:19 +0000481 out << "(Set.fromList [";
482 else
483 out << "(Vector.fromList ";
Kevin Clark4798a7a2009-03-24 15:56:19 +0000484
Christian Lavoie600a88c2010-11-07 18:37:11 +0000485 bool first = true;
iproctorff8eb922007-07-25 19:06:13 +0000486 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000487 out << (first ? "" : ",");
iproctorff8eb922007-07-25 19:06:13 +0000488 out << render_const_value(etype, *v_iter);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000489 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000490 }
Kevin Clark4798a7a2009-03-24 15:56:19 +0000491
Roger Meier6849f202012-05-18 07:35:19 +0000492 out << "])";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000493
David Reiss9a4edfa2008-05-01 05:52:50 +0000494 } else {
495 throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
iproctorff8eb922007-07-25 19:06:13 +0000496 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000497
iproctorff8eb922007-07-25 19:06:13 +0000498 return out.str();
499}
500
501/**
502 * Generates a "struct"
503 */
504void t_hs_generator::generate_struct(t_struct* tstruct) {
505 generate_hs_struct(tstruct, false);
506}
507
508/**
509 * Generates a struct definition for a thrift exception. Basically the same
510 * as a struct, but also has an exception declaration.
511 *
512 * @param txception The struct definition
513 */
514void t_hs_generator::generate_xception(t_struct* txception) {
David Reiss0c90f6f2008-02-06 22:18:40 +0000515 generate_hs_struct(txception, true);
iproctorff8eb922007-07-25 19:06:13 +0000516}
517
518/**
519 * Generates a Haskell struct
520 */
521void t_hs_generator::generate_hs_struct(t_struct* tstruct,
Christian Lavoie600a88c2010-11-07 18:37:11 +0000522 bool is_exception) {
iproctorff8eb922007-07-25 19:06:13 +0000523 generate_hs_struct_definition(f_types_,tstruct, is_exception,false);
524}
525
526/**
David Reiss0c90f6f2008-02-06 22:18:40 +0000527 * Generates a struct definition for a thrift data type.
iproctorff8eb922007-07-25 19:06:13 +0000528 *
529 * @param tstruct The struct definition
530 */
531void t_hs_generator::generate_hs_struct_definition(ofstream& out,
532 t_struct* tstruct,
533 bool is_exception,
534 bool helper) {
Roger Meier3b771a12010-11-17 22:11:26 +0000535 (void) helper;
iproctorff8eb922007-07-25 19:06:13 +0000536 string tname = type_name(tstruct);
537 string name = tstruct->get_name();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000538
iproctorff8eb922007-07-25 19:06:13 +0000539 const vector<t_field*>& members = tstruct->get_members();
David Reiss0c90f6f2008-02-06 22:18:40 +0000540 vector<t_field*>::const_iterator m_iter;
iproctorff8eb922007-07-25 19:06:13 +0000541
Christian Lavoie600a88c2010-11-07 18:37:11 +0000542 indent(out) << "data " << tname << " = " << tname;
iproctorff8eb922007-07-25 19:06:13 +0000543 if (members.size() > 0) {
544 out << "{";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000545
546 bool first = true;
iproctorff8eb922007-07-25 19:06:13 +0000547 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
iproctorff8eb922007-07-25 19:06:13 +0000548 string mname = (*m_iter)->get_name();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000549 out << (first ? "" : ",");
Roger Meier6849f202012-05-18 07:35:19 +0000550 out << "f_" << tname << "_" << mname << " :: Maybe " << render_hs_type((*m_iter)->get_type(), true);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000551 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000552 }
553 out << "}";
554 }
555
Roger Meier6849f202012-05-18 07:35:19 +0000556 out << " deriving (Show,Eq,Typeable)" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000557
558 if (is_exception)
559 out << "instance Exception " << tname << endl;
560
Roger Meier6849f202012-05-18 07:35:19 +0000561 indent(out) << "instance Hashable " << tname << " where" << endl;
562 indent_up();
563 indent(out) << "hashWithSalt salt record = salt";
564 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
565 string mname = (*m_iter)->get_name();
566 indent(out) << " `hashWithSalt` " << "f_" << tname << "_" << mname << " record";
567 }
568 indent(out) << endl;
569 indent_down();
570
iproctorff8eb922007-07-25 19:06:13 +0000571 generate_hs_struct_writer(out, tstruct);
iproctorff8eb922007-07-25 19:06:13 +0000572 generate_hs_struct_reader(out, tstruct);
iproctorff8eb922007-07-25 19:06:13 +0000573}
574
iproctorff8eb922007-07-25 19:06:13 +0000575/**
576 * Generates the read method for a struct
577 */
578void t_hs_generator::generate_hs_struct_reader(ofstream& out, t_struct* tstruct) {
579 const vector<t_field*>& fields = tstruct->get_members();
580 vector<t_field*>::const_iterator f_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000581
iproctorff8eb922007-07-25 19:06:13 +0000582 string sname = type_name(tstruct);
583 string str = tmp("_str");
584 string t = tmp("_t");
585 string id = tmp("_id");
586
Anthony F. Molinarodaef1c82010-09-26 04:25:36 +0000587 indent(out) << "read_" << sname << "_fields iprot record = do" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000588 indent_up();
David Reiss0c90f6f2008-02-06 22:18:40 +0000589
iproctorff8eb922007-07-25 19:06:13 +0000590 // Read beginning field marker
Christian Lavoie600a88c2010-11-07 18:37:11 +0000591 indent(out) << "(_," << t << "," << id << ") <- readFieldBegin iprot" << endl;
592
iproctorff8eb922007-07-25 19:06:13 +0000593 // Check for field STOP marker and break
Christian Lavoie600a88c2010-11-07 18:37:11 +0000594 indent(out) << "if " << t << " == T_STOP then return record else" << endl;
595
596 indent_up();
597 indent(out) << "case " << id << " of " << endl;
598 indent_up();
599
iproctorff8eb922007-07-25 19:06:13 +0000600 // Generate deserialization code for known cases
601 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000602 int32_t key = (*f_iter)->get_key();
603 string etype = type_to_enum((*f_iter)->get_type());
604 indent(out) << key << " -> " << "if " << t << " == " << etype << " then do" << endl;
605
606 indent_up();
iproctorff8eb922007-07-25 19:06:13 +0000607 indent(out) << "s <- ";
608 generate_deserialize_field(out, *f_iter,str);
609 out << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000610
611 string fname = decapitalize((*f_iter)->get_name());
612 indent(out) << "read_" << sname << "_fields iprot record{f_" << sname << "_" << fname << "=Just s}" << endl;
613
614 indent(out) << "else do" << endl;
615
iproctorff8eb922007-07-25 19:06:13 +0000616 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000617 indent(out) << "skip iprot " << t << endl;
618
619 indent(out) << "read_" << sname << "_fields iprot record" << endl;
620
621 indent_down();
622 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000623 }
624
iproctorff8eb922007-07-25 19:06:13 +0000625 // In the default case we skip the field
Christian Lavoie600a88c2010-11-07 18:37:11 +0000626 indent(out) << "_ -> do" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000627 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000628 indent(out) << "skip iprot " << t << endl;
iproctorff8eb922007-07-25 19:06:13 +0000629 indent(out) << "readFieldEnd iprot" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000630 indent(out) << "read_" << sname << "_fields iprot record" << endl;
631 indent_down();
632 indent_down();
633 indent_down();
David Reiss0c90f6f2008-02-06 22:18:40 +0000634 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000635
636 // read
Christian Lavoie600a88c2010-11-07 18:37:11 +0000637 indent(out) << "read_" << sname << " iprot = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000638 indent_up();
Bryan Duxburyf38b2f12010-09-20 17:41:40 +0000639 indent(out) << "_ <- readStructBegin iprot" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000640 indent(out) << "record <- read_" << sname << "_fields iprot (" << sname << "{";
641
iproctorff8eb922007-07-25 19:06:13 +0000642 bool first = true;
643 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000644 out << (first ? "" : ",");
iproctorff8eb922007-07-25 19:06:13 +0000645 out << "f_" << sname << "_" << decapitalize((*f_iter)->get_name()) << "=Nothing";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000646 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000647 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000648
iproctorff8eb922007-07-25 19:06:13 +0000649 out << "})" << endl;
650 indent(out) << "readStructEnd iprot" << endl;
Anthony F. Molinarodaef1c82010-09-26 04:25:36 +0000651 indent(out) << "return record" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000652 indent_down();
653}
654
655void t_hs_generator::generate_hs_struct_writer(ofstream& out,
656 t_struct* tstruct) {
657 string name = type_name(tstruct);
Bryan Duxburyff219ac2009-04-10 21:51:00 +0000658 const vector<t_field*>& fields = tstruct->get_sorted_members();
iproctorff8eb922007-07-25 19:06:13 +0000659 vector<t_field*>::const_iterator f_iter;
660 string str = tmp("_str");
661 string f = tmp("_f");
662
Christian Lavoie600a88c2010-11-07 18:37:11 +0000663 indent(out) << "write_" << name << " oprot record = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000664 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000665 indent(out) << "writeStructBegin oprot \"" << name << "\"" << endl;
666
iproctorff8eb922007-07-25 19:06:13 +0000667 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
668 // Write field header
669 string mname = (*f_iter)->get_name();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000670 indent(out) << "case f_" << name << "_" << mname << " record of {Nothing -> return (); Just _v -> do" << endl;
671
iproctorff8eb922007-07-25 19:06:13 +0000672 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000673 indent(out) << "writeFieldBegin oprot (\"" << (*f_iter)->get_name() << "\","
674 << type_to_enum((*f_iter)->get_type()) << ","
675 << (*f_iter)->get_key() << ")" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000676
677 // Write field contents
Christian Lavoie600a88c2010-11-07 18:37:11 +0000678 indent(out);
iproctorff8eb922007-07-25 19:06:13 +0000679 generate_serialize_field(out, *f_iter, "_v");
680 out << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000681
iproctorff8eb922007-07-25 19:06:13 +0000682 // Write field closer
683 indent(out) << "writeFieldEnd oprot}" << endl;
684 indent_down();
685 }
686
687 // Write the struct map
Christian Lavoie600a88c2010-11-07 18:37:11 +0000688 indent(out) << "writeFieldStop oprot" << endl;
689 indent(out) << "writeStructEnd oprot" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000690
691 indent_down();
692}
693
694/**
695 * Generates a thrift service.
696 *
697 * @param tservice The service definition
698 */
699void t_hs_generator::generate_service(t_service* tservice) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000700 string f_service_name = get_out_dir() + capitalize(service_name_) + ".hs";
iproctorff8eb922007-07-25 19:06:13 +0000701 f_service_.open(f_service_name.c_str());
702
Christian Lavoie600a88c2010-11-07 18:37:11 +0000703 f_service_ << hs_language_pragma() << endl;
704 f_service_ << hs_autogen_comment() << endl;
705 f_service_ << "module " << capitalize(service_name_) << " where" << endl;
706 f_service_ << hs_imports() << endl;
iproctorff8eb922007-07-25 19:06:13 +0000707
Christian Lavoie600a88c2010-11-07 18:37:11 +0000708 if (tservice->get_extends()) {
709 f_service_ << "import qualified " << capitalize(tservice->get_extends()->get_name()) << endl;
iproctorff8eb922007-07-25 19:06:13 +0000710 }
711
Christian Lavoie600a88c2010-11-07 18:37:11 +0000712 f_service_ << "import " << capitalize(program_name_) << "_Types" << endl;
713 f_service_ << "import qualified " << capitalize(service_name_) << "_Iface as Iface" << endl;
David Reiss0c90f6f2008-02-06 22:18:40 +0000714
715 // Generate the three main parts of the service
iproctorff8eb922007-07-25 19:06:13 +0000716 generate_service_helpers(tservice);
717 generate_service_interface(tservice);
718 generate_service_client(tservice);
719 generate_service_server(tservice);
720
iproctorff8eb922007-07-25 19:06:13 +0000721 // Close service file
722 f_service_.close();
723}
724
725/**
726 * Generates helper functions for a service.
727 *
728 * @param tservice The service to generate a header definition for
729 */
730void t_hs_generator::generate_service_helpers(t_service* tservice) {
731 vector<t_function*> functions = tservice->get_functions();
732 vector<t_function*>::iterator f_iter;
733
Christian Lavoie600a88c2010-11-07 18:37:11 +0000734 indent(f_service_) << "-- HELPER FUNCTIONS AND STRUCTURES --" << endl;
735 indent(f_service_) << endl;
iproctorff8eb922007-07-25 19:06:13 +0000736
737 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
738 t_struct* ts = (*f_iter)->get_arglist();
739 generate_hs_struct_definition(f_service_,ts, false);
740 generate_hs_function_helpers(*f_iter);
741 }
742}
743
744/**
745 * Generates a struct and helpers for a function.
746 *
747 * @param tfunction The function
748 */
749void t_hs_generator::generate_hs_function_helpers(t_function* tfunction) {
750 t_struct result(program_, decapitalize(tfunction->get_name()) + "_result");
751 t_field success(tfunction->get_returntype(), "success", 0);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000752
753 if (!tfunction->get_returntype()->is_void())
iproctorff8eb922007-07-25 19:06:13 +0000754 result.append(&success);
iproctorff8eb922007-07-25 19:06:13 +0000755
756 t_struct* xs = tfunction->get_xceptions();
757 const vector<t_field*>& fields = xs->get_members();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000758
iproctorff8eb922007-07-25 19:06:13 +0000759 vector<t_field*>::const_iterator f_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000760 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
iproctorff8eb922007-07-25 19:06:13 +0000761 result.append(*f_iter);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000762
iproctorff8eb922007-07-25 19:06:13 +0000763 generate_hs_struct_definition(f_service_,&result, false);
764}
765
766/**
767 * Generates a service interface definition.
768 *
769 * @param tservice The service to generate a header definition for
770 */
771void t_hs_generator::generate_service_interface(t_service* tservice) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000772 string f_iface_name = get_out_dir() + capitalize(service_name_) + "_Iface.hs";
iproctorff8eb922007-07-25 19:06:13 +0000773 f_iface_.open(f_iface_name.c_str());
Bryan Duxburye59a80f2010-09-20 15:21:37 +0000774
Christian Lavoie600a88c2010-11-07 18:37:11 +0000775 f_iface_ << hs_language_pragma() << endl;
776 f_iface_ << hs_autogen_comment() << endl;
iproctorff8eb922007-07-25 19:06:13 +0000777
Christian Lavoie600a88c2010-11-07 18:37:11 +0000778 f_iface_ << "module " << capitalize(service_name_) << "_Iface where" << endl;
David Reiss0c90f6f2008-02-06 22:18:40 +0000779
Christian Lavoie600a88c2010-11-07 18:37:11 +0000780 f_iface_ << hs_imports() << endl;
781 f_iface_ << "import " << capitalize(program_name_) << "_Types" << endl;
782 f_iface_ << endl;
783
784 string sname = capitalize(service_name_);
iproctorff8eb922007-07-25 19:06:13 +0000785 if (tservice->get_extends() != NULL) {
786 string extends = type_name(tservice->get_extends());
Christian Lavoie600a88c2010-11-07 18:37:11 +0000787
788 indent(f_iface_) << "import " << extends << "_Iface" << endl;
789 indent(f_iface_) << "class " << extends << "_Iface a => " << sname << "_Iface a where" << endl;
790
iproctorff8eb922007-07-25 19:06:13 +0000791 } else {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000792 indent(f_iface_) << "class " << sname << "_Iface a where" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000793 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000794
iproctorff8eb922007-07-25 19:06:13 +0000795 indent_up();
796
797 vector<t_function*> functions = tservice->get_functions();
David Reiss0c90f6f2008-02-06 22:18:40 +0000798 vector<t_function*>::iterator f_iter;
iproctorff8eb922007-07-25 19:06:13 +0000799 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000800 string ft = function_type(*f_iter, true, true, true);
801 indent(f_iface_) << decapitalize((*f_iter)->get_name()) << " :: a -> " << ft << endl;
iproctorff8eb922007-07-25 19:06:13 +0000802 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000803
iproctorff8eb922007-07-25 19:06:13 +0000804 indent_down();
805 f_iface_.close();
iproctorff8eb922007-07-25 19:06:13 +0000806}
807
808/**
809 * Generates a service client definition. Note that in Haskell, the client doesn't implement iface. This is because
810 * The client does not (and should not have to) deal with arguments being Nothing.
811 *
812 * @param tservice The service to generate a server for.
813 */
814void t_hs_generator::generate_service_client(t_service* tservice) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000815 string f_client_name = get_out_dir() + capitalize(service_name_) + "_Client.hs";
iproctorff8eb922007-07-25 19:06:13 +0000816 f_client_.open(f_client_name.c_str());
Christian Lavoie600a88c2010-11-07 18:37:11 +0000817 f_client_ << hs_language_pragma() << endl;
818 f_client_ << hs_autogen_comment() << endl;
iproctorff8eb922007-07-25 19:06:13 +0000819
820 vector<t_function*> functions = tservice->get_functions();
David Reiss0c90f6f2008-02-06 22:18:40 +0000821 vector<t_function*>::const_iterator f_iter;
iproctorff8eb922007-07-25 19:06:13 +0000822
823 string extends = "";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000824 string exports = "";
825
iproctorff8eb922007-07-25 19:06:13 +0000826 bool first = true;
827 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000828 exports += (first ? "" : ",");
iproctorff8eb922007-07-25 19:06:13 +0000829 string funname = (*f_iter)->get_name();
Anthony F. Molinaro71a58a82010-09-27 19:27:40 +0000830 exports += decapitalize(funname);
Christian Lavoie600a88c2010-11-07 18:37:11 +0000831 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000832 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000833
834 string sname = capitalize(service_name_);
835 indent(f_client_) << "module " << sname << "_Client(" << exports << ") where" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000836
837 if (tservice->get_extends() != NULL) {
838 extends = type_name(tservice->get_extends());
839 indent(f_client_) << "import " << extends << "_Client" << endl;
840 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000841
iproctorff8eb922007-07-25 19:06:13 +0000842 indent(f_client_) << "import Data.IORef" << endl;
843 indent(f_client_) << hs_imports() << endl;
844 indent(f_client_) << "import " << capitalize(program_name_) << "_Types" << endl;
845 indent(f_client_) << "import " << capitalize(service_name_) << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000846
iproctorff8eb922007-07-25 19:06:13 +0000847 // DATS RITE A GLOBAL VAR
848 indent(f_client_) << "seqid = newIORef 0" << endl;
David Reiss0c90f6f2008-02-06 22:18:40 +0000849
iproctorff8eb922007-07-25 19:06:13 +0000850 // Generate client method implementations
iproctorff8eb922007-07-25 19:06:13 +0000851 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
852 t_struct* arg_struct = (*f_iter)->get_arglist();
853 const vector<t_field*>& fields = arg_struct->get_members();
854 vector<t_field*>::const_iterator fld_iter;
855 string funname = (*f_iter)->get_name();
856
857 string fargs = "";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000858 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter)
859 fargs += " arg_" + decapitalize((*fld_iter)->get_name());
iproctorff8eb922007-07-25 19:06:13 +0000860
861 // Open function
Anthony F. Molinaro71a58a82010-09-27 19:27:40 +0000862 indent(f_client_) << decapitalize(funname) << " (ip,op)" << fargs << " = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000863 indent_up();
864 indent(f_client_) << "send_" << funname << " op" << fargs;
865
866 f_client_ << endl;
David Reiss0c90f6f2008-02-06 22:18:40 +0000867
Christian Lavoie600a88c2010-11-07 18:37:11 +0000868 if (!(*f_iter)->is_oneway())
869 indent(f_client_) << "recv_" << funname << " ip" << endl;
870
iproctorff8eb922007-07-25 19:06:13 +0000871 indent_down();
David Reiss0c90f6f2008-02-06 22:18:40 +0000872
Christian Lavoie600a88c2010-11-07 18:37:11 +0000873 indent(f_client_) << "send_" << funname << " op" << fargs << " = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000874 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000875
iproctorff8eb922007-07-25 19:06:13 +0000876 indent(f_client_) << "seq <- seqid" << endl;
877 indent(f_client_) << "seqn <- readIORef seq" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000878 string argsname = capitalize((*f_iter)->get_name() + "_args");
David Reiss0c90f6f2008-02-06 22:18:40 +0000879
iproctorff8eb922007-07-25 19:06:13 +0000880 // Serialize the request header
Christian Lavoie600a88c2010-11-07 18:37:11 +0000881 string fname = (*f_iter)->get_name();
882 indent(f_client_) << "writeMessageBegin op (\"" << fname << "\", M_CALL, seqn)" << endl;
883 indent(f_client_) << "write_" << argsname << " op (" << argsname << "{";
884
iproctorff8eb922007-07-25 19:06:13 +0000885 bool first = true;
886 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000887 string fieldname = (*fld_iter)->get_name();
888 f_client_ << (first ? "" : ",");
889 f_client_ << "f_" << argsname << "_" << fieldname << "=Just arg_" << fieldname;
890 first = false;
iproctorff8eb922007-07-25 19:06:13 +0000891 }
892 f_client_ << "})" << endl;
David Reiss0c90f6f2008-02-06 22:18:40 +0000893
iproctorff8eb922007-07-25 19:06:13 +0000894 // Write to the stream
Christian Lavoie600a88c2010-11-07 18:37:11 +0000895 indent(f_client_) << "writeMessageEnd op" << endl;
896 indent(f_client_) << "tFlush (getTransport op)" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000897 indent_down();
898
David Reiss47329252009-03-24 20:01:02 +0000899 if (!(*f_iter)->is_oneway()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000900 string resultname = capitalize((*f_iter)->get_name() + "_result");
iproctorff8eb922007-07-25 19:06:13 +0000901 t_struct noargs(program_);
902
Christian Lavoie600a88c2010-11-07 18:37:11 +0000903 string funname = string("recv_") + (*f_iter)->get_name();
904 t_function recv_function((*f_iter)->get_returntype(), funname, &noargs);
David Reiss0c90f6f2008-02-06 22:18:40 +0000905
iproctorff8eb922007-07-25 19:06:13 +0000906 // Open function
Christian Lavoie600a88c2010-11-07 18:37:11 +0000907 indent(f_client_) << funname << " ip = do" << endl;
908 indent_up();
iproctorff8eb922007-07-25 19:06:13 +0000909
910 // TODO(mcslee): Validate message reply here, seq ids etc.
Christian Lavoie600a88c2010-11-07 18:37:11 +0000911 indent(f_client_) << "(fname, mtype, rseqid) <- readMessageBegin ip" << endl;
912 indent(f_client_) << "if mtype == M_EXCEPTION then do" << endl;
913 indent(f_client_) << " x <- readAppExn ip" << endl;
914 indent(f_client_) << " readMessageEnd ip" << endl;
915 indent(f_client_) << " throw x" << endl;
916 indent(f_client_) << " else return ()" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000917
918 t_struct* xs = (*f_iter)->get_xceptions();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000919 const vector<t_field*>& xceptions = xs->get_members();
iproctorff8eb922007-07-25 19:06:13 +0000920
Christian Lavoie600a88c2010-11-07 18:37:11 +0000921 indent(f_client_) << "res <- read_" << resultname << " ip" << endl;
922 indent(f_client_) << "readMessageEnd ip" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000923
924 // Careful, only return _result if not a void function
925 if (!(*f_iter)->get_returntype()->is_void()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000926 indent(f_client_) << "case f_" << resultname << "_success res of" << endl;
927 indent_up();
928
iproctorff8eb922007-07-25 19:06:13 +0000929 indent(f_client_) << "Just v -> return v" << endl;
930 indent(f_client_) << "Nothing -> do" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000931 indent_up();
iproctorff8eb922007-07-25 19:06:13 +0000932 }
David Reiss0c90f6f2008-02-06 22:18:40 +0000933
iproctorff8eb922007-07-25 19:06:13 +0000934 vector<t_field*>::const_iterator x_iter;
935 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000936 string xname = (*x_iter)->get_name();
937 indent(f_client_) << "case f_" << resultname << "_" << xname << " res of" << endl;
938 indent_up();
939
iproctorff8eb922007-07-25 19:06:13 +0000940 indent(f_client_) << "Nothing -> return ()" << endl;
Bryan Duxbury0781f2b2009-04-07 23:29:42 +0000941 indent(f_client_) << "Just _v -> throw _v" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000942 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000943 }
David Reiss0c90f6f2008-02-06 22:18:40 +0000944
iproctorff8eb922007-07-25 19:06:13 +0000945 // Careful, only return _result if not a void function
946 if ((*f_iter)->get_returntype()->is_void()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000947 indent(f_client_) << "return ()" << endl;
948
iproctorff8eb922007-07-25 19:06:13 +0000949 } else {
Christian Lavoie600a88c2010-11-07 18:37:11 +0000950 string tname = (*f_iter)->get_name();
951 indent(f_client_) << "throw (AppExn AE_MISSING_RESULT \"" << tname << " failed: unknown result\")" << endl;
952 indent_down();
953 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000954 }
955
956 // Close function
Christian Lavoie600a88c2010-11-07 18:37:11 +0000957 indent_down();
iproctorff8eb922007-07-25 19:06:13 +0000958 }
959 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000960
iproctorff8eb922007-07-25 19:06:13 +0000961 f_client_.close();
iproctorff8eb922007-07-25 19:06:13 +0000962}
963
964/**
965 * Generates a service server definition.
966 *
967 * @param tservice The service to generate a server for.
968 */
969void t_hs_generator::generate_service_server(t_service* tservice) {
970 // Generate the dispatch methods
971 vector<t_function*> functions = tservice->get_functions();
David Reiss0c90f6f2008-02-06 22:18:40 +0000972 vector<t_function*>::iterator f_iter;
iproctorff8eb922007-07-25 19:06:13 +0000973
974 // Generate the process subfunctions
Christian Lavoie600a88c2010-11-07 18:37:11 +0000975 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
iproctorff8eb922007-07-25 19:06:13 +0000976 generate_process_function(tservice, *f_iter);
iproctorff8eb922007-07-25 19:06:13 +0000977
Anthony F. Molinarodaef1c82010-09-26 04:25:36 +0000978 indent(f_service_) << "proc_ handler (iprot,oprot) (name,typ,seqid) = case name of" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000979 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000980
iproctorff8eb922007-07-25 19:06:13 +0000981 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
982 string fname = (*f_iter)->get_name();
Christian Lavoie600a88c2010-11-07 18:37:11 +0000983 indent(f_service_) << "\"" << fname << "\" -> process_" << decapitalize(fname) << " (seqid,iprot,oprot,handler)" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000984 }
Christian Lavoie600a88c2010-11-07 18:37:11 +0000985
iproctorff8eb922007-07-25 19:06:13 +0000986 indent(f_service_) << "_ -> ";
Christian Lavoie600a88c2010-11-07 18:37:11 +0000987 if (tservice->get_extends() != NULL) {
Anthony F. Molinarodaef1c82010-09-26 04:25:36 +0000988 f_service_ << type_name(tservice->get_extends()) << ".proc_ handler (iprot,oprot) (name,typ,seqid)" << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +0000989
iproctorff8eb922007-07-25 19:06:13 +0000990 } else {
991 f_service_ << "do" << endl;
992 indent_up();
993 indent(f_service_) << "skip iprot T_STRUCT" << endl;
994 indent(f_service_) << "readMessageEnd iprot" << endl;
995 indent(f_service_) << "writeMessageBegin oprot (name,M_EXCEPTION,seqid)" << endl;
Roger Meier6849f202012-05-18 07:35:19 +0000996 indent(f_service_) << "writeAppExn oprot (AppExn AE_UNKNOWN_METHOD (\"Unknown function \" ++ TL.unpack name))" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000997 indent(f_service_) << "writeMessageEnd oprot" << endl;
Bryan Duxbury0781f2b2009-04-07 23:29:42 +0000998 indent(f_service_) << "tFlush (getTransport oprot)" << endl;
iproctorff8eb922007-07-25 19:06:13 +0000999 indent_down();
1000 }
Christian Lavoie600a88c2010-11-07 18:37:11 +00001001
iproctorff8eb922007-07-25 19:06:13 +00001002 indent_down();
1003
1004 // Generate the server implementation
Christian Lavoie600a88c2010-11-07 18:37:11 +00001005 indent(f_service_) << "process handler (iprot, oprot) = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001006 indent_up();
1007
Christian Lavoie600a88c2010-11-07 18:37:11 +00001008 indent(f_service_) << "(name, typ, seqid) <- readMessageBegin iprot" << endl;
1009 indent(f_service_) << "proc_ handler (iprot,oprot) (name,typ,seqid)" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001010 indent(f_service_) << "return True" << endl;
1011 indent_down();
iproctorff8eb922007-07-25 19:06:13 +00001012}
1013
1014/**
1015 * Generates a process function definition.
1016 *
1017 * @param tfunction The function to write a dispatcher for
1018 */
1019void t_hs_generator::generate_process_function(t_service* tservice,
1020 t_function* tfunction) {
Roger Meier3b771a12010-11-17 22:11:26 +00001021 (void) tservice;
iproctorff8eb922007-07-25 19:06:13 +00001022 // Open function
Christian Lavoie600a88c2010-11-07 18:37:11 +00001023 string funname = decapitalize(tfunction->get_name());
1024 indent(f_service_) << "process_" << funname << " (seqid, iprot, oprot, handler) = do" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001025 indent_up();
1026
1027 string argsname = capitalize(tfunction->get_name()) + "_args";
1028 string resultname = capitalize(tfunction->get_name()) + "_result";
1029
1030 // Generate the function call
1031 t_struct* arg_struct = tfunction->get_arglist();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001032 const vector<t_field*>& fields = arg_struct->get_members();
iproctorff8eb922007-07-25 19:06:13 +00001033 vector<t_field*>::const_iterator f_iter;
1034
Christian Lavoie600a88c2010-11-07 18:37:11 +00001035 indent(f_service_) << "args <- read_" << argsname << " iprot" << endl;
1036 indent(f_service_) << "readMessageEnd iprot" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001037
1038 t_struct* xs = tfunction->get_xceptions();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001039 const vector<t_field*>& xceptions = xs->get_members();
iproctorff8eb922007-07-25 19:06:13 +00001040 vector<t_field*>::const_iterator x_iter;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001041
1042 size_t n = xceptions.size();
1043 if (!tfunction->is_oneway()) {
1044 if (!tfunction->get_returntype()->is_void())
iproctorff8eb922007-07-25 19:06:13 +00001045 n++;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001046
iproctorff8eb922007-07-25 19:06:13 +00001047 indent(f_service_) << "rs <- return (" << resultname;
David Reiss0c90f6f2008-02-06 22:18:40 +00001048
Christian Lavoie600a88c2010-11-07 18:37:11 +00001049 for(size_t i = 0; i < n; i++)
iproctorff8eb922007-07-25 19:06:13 +00001050 f_service_ << " Nothing";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001051
iproctorff8eb922007-07-25 19:06:13 +00001052 f_service_ << ")" << endl;
1053 }
1054
1055 indent(f_service_) << "res <- ";
1056 // Try block for a function with exceptions
1057 if (xceptions.size() > 0) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001058 for(size_t i = 0; i < xceptions.size(); i++) {
Bryan Duxbury0781f2b2009-04-07 23:29:42 +00001059 f_service_ << "(Control.Exception.catch" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001060 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001061 indent(f_service_);
iproctorff8eb922007-07-25 19:06:13 +00001062 }
1063 }
1064
1065 f_service_ << "(do" << endl;
1066 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001067 indent(f_service_);
1068
1069 if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void())
iproctorff8eb922007-07-25 19:06:13 +00001070 f_service_ << "res <- ";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001071
Anthony F. Molinaro71a58a82010-09-27 19:27:40 +00001072 f_service_ << "Iface." << decapitalize(tfunction->get_name()) << " handler";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001073 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
iproctorff8eb922007-07-25 19:06:13 +00001074 f_service_ << " (f_" << argsname << "_" << (*f_iter)->get_name() << " args)";
iproctorff8eb922007-07-25 19:06:13 +00001075
Christian Lavoie600a88c2010-11-07 18:37:11 +00001076 if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
iproctorff8eb922007-07-25 19:06:13 +00001077 f_service_ << endl;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001078 indent(f_service_) << "return rs{f_" << resultname << "_success= Just res}";
1079
1080 } else if (!tfunction->is_oneway()) {
iproctorff8eb922007-07-25 19:06:13 +00001081 f_service_ << endl;
1082 indent(f_service_) << "return rs";
1083 }
Christian Lavoie600a88c2010-11-07 18:37:11 +00001084
iproctorff8eb922007-07-25 19:06:13 +00001085 f_service_ << ")" << endl;
1086 indent_down();
David Reiss0c90f6f2008-02-06 22:18:40 +00001087
David Reiss47329252009-03-24 20:01:02 +00001088 if (xceptions.size() > 0 && !tfunction->is_oneway()) {
iproctorff8eb922007-07-25 19:06:13 +00001089 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001090 indent(f_service_) << "(\\e -> " << endl;
iproctorff8eb922007-07-25 19:06:13 +00001091 indent_up();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001092
1093 if (!tfunction->is_oneway()) {
1094 indent(f_service_) << "return rs{f_" << resultname << "_" << (*x_iter)->get_name() << " =Just e}";
1095
iproctorff8eb922007-07-25 19:06:13 +00001096 } else {
1097 indent(f_service_) << "return ()";
1098 }
Christian Lavoie600a88c2010-11-07 18:37:11 +00001099
iproctorff8eb922007-07-25 19:06:13 +00001100 f_service_ << "))" << endl;
1101 indent_down();
1102 indent_down();
1103 }
1104 }
1105
David Reissc51986f2009-03-24 20:01:25 +00001106 // Shortcut out here for oneway functions
David Reiss47329252009-03-24 20:01:02 +00001107 if (tfunction->is_oneway()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001108 indent(f_service_) << "return ()" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001109 indent_down();
1110 return;
1111 }
1112
Christian Lavoie600a88c2010-11-07 18:37:11 +00001113 indent(f_service_ ) << "writeMessageBegin oprot (\"" << tfunction->get_name() << "\", M_REPLY, seqid);" << endl;
1114 indent(f_service_ ) << "write_" << resultname << " oprot res" << endl;
1115 indent(f_service_ ) << "writeMessageEnd oprot" << endl;
1116 indent(f_service_ ) << "tFlush (getTransport oprot)" << endl;
iproctorff8eb922007-07-25 19:06:13 +00001117
1118 // Close function
1119 indent_down();
1120}
1121
1122/**
1123 * Deserializes a field of any type.
1124 */
1125void t_hs_generator::generate_deserialize_field(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001126 t_field* tfield,
1127 string prefix) {
Roger Meier3b771a12010-11-17 22:11:26 +00001128 (void) prefix;
iproctorff8eb922007-07-25 19:06:13 +00001129 t_type* type = tfield->get_type();
1130 generate_deserialize_type(out,type);
1131}
1132
iproctorff8eb922007-07-25 19:06:13 +00001133/**
1134 * Deserializes a field of any type.
1135 */
1136void t_hs_generator::generate_deserialize_type(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001137 t_type* type) {
David Reisse087a302007-08-23 21:43:25 +00001138 type = get_true_type(type);
iproctorff8eb922007-07-25 19:06:13 +00001139
Christian Lavoie600a88c2010-11-07 18:37:11 +00001140 if (type->is_void())
iproctorff8eb922007-07-25 19:06:13 +00001141 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE";
iproctorff8eb922007-07-25 19:06:13 +00001142
1143 if (type->is_struct() || type->is_xception()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001144 generate_deserialize_struct(out, (t_struct*)type);
1145
iproctorff8eb922007-07-25 19:06:13 +00001146 } else if (type->is_container()) {
1147 generate_deserialize_container(out, type);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001148
iproctorff8eb922007-07-25 19:06:13 +00001149 } else if (type->is_base_type()) {
1150 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
Christian Lavoie600a88c2010-11-07 18:37:11 +00001151
iproctorff8eb922007-07-25 19:06:13 +00001152 switch (tbase) {
1153 case t_base_type::TYPE_VOID:
1154 throw "compiler error: cannot serialize void field in a struct";
1155 break;
David Reiss0c90f6f2008-02-06 22:18:40 +00001156 case t_base_type::TYPE_STRING:
Bryan Duxbury75a33e82010-09-22 00:48:56 +00001157 out << (((t_base_type*)type)->is_binary() ? "readBinary" : "readString");
iproctorff8eb922007-07-25 19:06:13 +00001158 break;
1159 case t_base_type::TYPE_BOOL:
1160 out << "readBool";
1161 break;
1162 case t_base_type::TYPE_BYTE:
1163 out << "readByte";
1164 break;
1165 case t_base_type::TYPE_I16:
1166 out << "readI16";
1167 break;
1168 case t_base_type::TYPE_I32:
1169 out << "readI32";
1170 break;
1171 case t_base_type::TYPE_I64:
1172 out << "readI64";
1173 break;
1174 case t_base_type::TYPE_DOUBLE:
1175 out << "readDouble";
1176 break;
1177 default:
David Reissdd7796f2007-08-28 21:09:06 +00001178 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
iproctorff8eb922007-07-25 19:06:13 +00001179 }
1180 out << " iprot";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001181
iproctorff8eb922007-07-25 19:06:13 +00001182 } else if (type->is_enum()) {
1183 string ename = capitalize(type->get_name());
Anthony F. Molinaro71a58a82010-09-27 19:27:40 +00001184 out << "(do {i <- readI32 iprot; return $ toEnum $ fromIntegral i})";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001185
iproctorff8eb922007-07-25 19:06:13 +00001186 } else {
1187 printf("DO NOT KNOW HOW TO DESERIALIZE TYPE '%s'\n",
1188 type->get_name().c_str());
1189 }
1190}
David Reiss0c90f6f2008-02-06 22:18:40 +00001191
iproctorff8eb922007-07-25 19:06:13 +00001192
1193/**
1194 * Generates an unserializer for a struct, calling read()
1195 */
1196void t_hs_generator::generate_deserialize_struct(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001197 t_struct* tstruct) {
iproctorff8eb922007-07-25 19:06:13 +00001198 string name = capitalize(tstruct->get_name());
1199 out << "(read_" << name << " iprot)";
iproctorff8eb922007-07-25 19:06:13 +00001200}
1201
1202/**
1203 * Serialize a container by writing out the header followed by
1204 * data and then a footer.
1205 */
1206void t_hs_generator::generate_deserialize_container(ofstream &out,
1207 t_type* ttype) {
1208 string size = tmp("_size");
1209 string ktype = tmp("_ktype");
1210 string vtype = tmp("_vtype");
1211 string etype = tmp("_etype");
1212 string con = tmp("_con");
David Reiss0c90f6f2008-02-06 22:18:40 +00001213
iproctorff8eb922007-07-25 19:06:13 +00001214 t_field fsize(g_type_i32, size);
1215 t_field fktype(g_type_byte, ktype);
1216 t_field fvtype(g_type_byte, vtype);
1217 t_field fetype(g_type_byte, etype);
1218
1219 // Declare variables, read header
1220 if (ttype->is_map()) {
1221 out << "(let {f 0 = return []; f n = do {k <- ";
1222 generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
Christian Lavoie600a88c2010-11-07 18:37:11 +00001223
iproctorff8eb922007-07-25 19:06:13 +00001224 out << "; v <- ";
1225 generate_deserialize_type(out,((t_map*)ttype)->get_val_type());
Christian Lavoie600a88c2010-11-07 18:37:11 +00001226
1227 out << ";r <- f (n-1); return $ (k,v):r}} in do {(" << ktype << "," << vtype << "," << size << ") <- readMapBegin iprot; l <- f " << size << "; return $ Map.fromList l})";
1228
iproctorff8eb922007-07-25 19:06:13 +00001229 } else if (ttype->is_set()) {
1230 out << "(let {f 0 = return []; f n = do {v <- ";
1231 generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
Christian Lavoie600a88c2010-11-07 18:37:11 +00001232 out << ";r <- f (n-1); return $ v:r}} in do {(" << etype << "," << size << ") <- readSetBegin iprot; l <- f " << size << "; return $ Set.fromList l})";
1233
iproctorff8eb922007-07-25 19:06:13 +00001234 } else if (ttype->is_list()) {
Roger Meier6849f202012-05-18 07:35:19 +00001235 out << "(let f n = Vector.replicateM (fromIntegral n) (";
iproctorff8eb922007-07-25 19:06:13 +00001236 generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
Roger Meier6849f202012-05-18 07:35:19 +00001237 out << ") in do {(" << etype << "," << size << ") <- readListBegin iprot; f " << size << "})";
iproctorff8eb922007-07-25 19:06:13 +00001238 }
1239}
1240
iproctorff8eb922007-07-25 19:06:13 +00001241/**
1242 * Serializes a field of any type.
1243 *
1244 * @param tfield The field to serialize
1245 * @param prefix Name to prepend to field name
1246 */
1247void t_hs_generator::generate_serialize_field(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001248 t_field* tfield,
1249 string name) {
David Reisse087a302007-08-23 21:43:25 +00001250 t_type* type = get_true_type(tfield->get_type());
iproctorff8eb922007-07-25 19:06:13 +00001251
1252 // Do nothing for void types
Christian Lavoie600a88c2010-11-07 18:37:11 +00001253 if (type->is_void())
1254 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + tfield->get_name();
iproctorff8eb922007-07-25 19:06:13 +00001255
Christian Lavoie600a88c2010-11-07 18:37:11 +00001256 if (name.length() == 0)
iproctorff8eb922007-07-25 19:06:13 +00001257 name = decapitalize(tfield->get_name());
iproctorff8eb922007-07-25 19:06:13 +00001258
1259 if (type->is_struct() || type->is_xception()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001260 generate_serialize_struct(out, (t_struct*)type, name);
1261
iproctorff8eb922007-07-25 19:06:13 +00001262 } else if (type->is_container()) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001263 generate_serialize_container(out, type, name);
1264
iproctorff8eb922007-07-25 19:06:13 +00001265 } else if (type->is_base_type() || type->is_enum()) {
1266 if (type->is_base_type()) {
1267 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1268 switch (tbase) {
1269 case t_base_type::TYPE_VOID:
1270 throw
1271 "compiler error: cannot serialize void field in a struct: " + name;
1272 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001273
iproctorff8eb922007-07-25 19:06:13 +00001274 case t_base_type::TYPE_STRING:
Bryan Duxbury75a33e82010-09-22 00:48:56 +00001275 out << (((t_base_type*)type)->is_binary() ? "writeBinary" : "writeString") << " oprot " << name;
iproctorff8eb922007-07-25 19:06:13 +00001276 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001277
iproctorff8eb922007-07-25 19:06:13 +00001278 case t_base_type::TYPE_BOOL:
1279 out << "writeBool oprot " << name;
1280 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001281
iproctorff8eb922007-07-25 19:06:13 +00001282 case t_base_type::TYPE_BYTE:
1283 out << "writeByte oprot " << name;
1284 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001285
iproctorff8eb922007-07-25 19:06:13 +00001286 case t_base_type::TYPE_I16:
1287 out << "writeI16 oprot " << name;
1288 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001289
iproctorff8eb922007-07-25 19:06:13 +00001290 case t_base_type::TYPE_I32:
1291 out << "writeI32 oprot " << name;
1292 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001293
iproctorff8eb922007-07-25 19:06:13 +00001294 case t_base_type::TYPE_I64:
1295 out << "writeI64 oprot " << name;
1296 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001297
iproctorff8eb922007-07-25 19:06:13 +00001298 case t_base_type::TYPE_DOUBLE:
1299 out << "writeDouble oprot " << name;
1300 break;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001301
iproctorff8eb922007-07-25 19:06:13 +00001302 default:
David Reissdd7796f2007-08-28 21:09:06 +00001303 throw "compiler error: no hs name for base type " + t_base_type::t_base_name(tbase);
iproctorff8eb922007-07-25 19:06:13 +00001304 }
David Reiss0c90f6f2008-02-06 22:18:40 +00001305
iproctorff8eb922007-07-25 19:06:13 +00001306 } else if (type->is_enum()) {
1307 string ename = capitalize(type->get_name());
Christian Lavoie600a88c2010-11-07 18:37:11 +00001308 out << "writeI32 oprot (fromIntegral $ fromEnum " << name << ")";
iproctorff8eb922007-07-25 19:06:13 +00001309 }
David Reiss0c90f6f2008-02-06 22:18:40 +00001310
iproctorff8eb922007-07-25 19:06:13 +00001311 } else {
1312 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
1313 tfield->get_name().c_str(),
1314 type->get_name().c_str());
1315 }
1316}
1317
1318/**
1319 * Serializes all the members of a struct.
1320 *
1321 * @param tstruct The struct to serialize
1322 * @param prefix String prefix to attach to all fields
1323 */
1324void t_hs_generator::generate_serialize_struct(ofstream &out,
1325 t_struct* tstruct,
1326 string prefix) {
David Reiss752529e2010-01-11 19:12:56 +00001327 out << type_name(tstruct, "write_") << " oprot " << prefix;
iproctorff8eb922007-07-25 19:06:13 +00001328}
1329
1330void t_hs_generator::generate_serialize_container(ofstream &out,
1331 t_type* ttype,
1332 string prefix) {
1333 if (ttype->is_map()) {
1334 string k = tmp("_kiter");
1335 string v = tmp("_viter");
Christian Lavoie600a88c2010-11-07 18:37:11 +00001336 out << "(let {f [] = return (); f ((" << k << "," << v << "):t) = do {";
iproctorff8eb922007-07-25 19:06:13 +00001337 generate_serialize_map_element(out, (t_map*)ttype, k, v);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001338 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})";
1339
iproctorff8eb922007-07-25 19:06:13 +00001340 } else if (ttype->is_set()) {
1341 string v = tmp("_viter");
Christian Lavoie600a88c2010-11-07 18:37:11 +00001342 out << "(let {f [] = return (); f (" << v << ":t) = do {";
iproctorff8eb922007-07-25 19:06:13 +00001343 generate_serialize_set_element(out, (t_set*)ttype, v);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001344 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})";
1345
iproctorff8eb922007-07-25 19:06:13 +00001346 } else if (ttype->is_list()) {
1347 string v = tmp("_viter");
Roger Meier6849f202012-05-18 07:35:19 +00001348 out << "(let f = Vector.mapM_ (\\" << v << " -> ";
iproctorff8eb922007-07-25 19:06:13 +00001349 generate_serialize_list_element(out, (t_list*)ttype, v);
Roger Meier6849f202012-05-18 07:35:19 +00001350 out << ") in do {writeListBegin oprot (" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ",fromIntegral $ Vector.length " << prefix << "); f " << prefix << ";writeListEnd oprot})";
iproctorff8eb922007-07-25 19:06:13 +00001351 }
1352
1353}
1354
1355/**
1356 * Serializes the members of a map.
1357 *
1358 */
1359void t_hs_generator::generate_serialize_map_element(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001360 t_map* tmap,
1361 string kiter,
1362 string viter) {
iproctorff8eb922007-07-25 19:06:13 +00001363 t_field kfield(tmap->get_key_type(), kiter);
1364 out << "do {";
1365 generate_serialize_field(out, &kfield);
1366 out << ";";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001367
iproctorff8eb922007-07-25 19:06:13 +00001368 t_field vfield(tmap->get_val_type(), viter);
1369 generate_serialize_field(out, &vfield);
1370 out << "}";
1371}
1372
1373/**
1374 * Serializes the members of a set.
1375 */
1376void t_hs_generator::generate_serialize_set_element(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001377 t_set* tset,
1378 string iter) {
iproctorff8eb922007-07-25 19:06:13 +00001379 t_field efield(tset->get_elem_type(), iter);
1380 generate_serialize_field(out, &efield);
1381}
1382
1383/**
1384 * Serializes the members of a list.
1385 */
1386void t_hs_generator::generate_serialize_list_element(ofstream &out,
Christian Lavoie600a88c2010-11-07 18:37:11 +00001387 t_list* tlist,
1388 string iter) {
iproctorff8eb922007-07-25 19:06:13 +00001389 t_field efield(tlist->get_elem_type(), iter);
1390 generate_serialize_field(out, &efield);
1391}
1392
Christian Lavoie600a88c2010-11-07 18:37:11 +00001393string t_hs_generator::function_type(t_function* tfunc, bool options, bool io, bool method) {
1394 string result = "";
David Reiss0c90f6f2008-02-06 22:18:40 +00001395
iproctorff8eb922007-07-25 19:06:13 +00001396 const vector<t_field*>& fields = tfunc->get_arglist()->get_members();
1397 vector<t_field*>::const_iterator f_iter;
1398 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001399 if (options) result += "Maybe ";
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001400 result += render_hs_type((*f_iter)->get_type(), options);
iproctorff8eb922007-07-25 19:06:13 +00001401 result += " -> ";
1402 }
Christian Lavoie600a88c2010-11-07 18:37:11 +00001403
1404 if (fields.empty() && !method)
iproctorff8eb922007-07-25 19:06:13 +00001405 result += "() -> ";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001406
1407 if (io)
1408 result += "IO ";
1409
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001410 result += render_hs_type(tfunc->get_returntype(), io);
iproctorff8eb922007-07-25 19:06:13 +00001411 return result;
1412}
1413
1414
David Reiss752529e2010-01-11 19:12:56 +00001415string t_hs_generator::type_name(t_type* ttype, string function_prefix) {
iproctorff8eb922007-07-25 19:06:13 +00001416 string prefix = "";
1417 t_program* program = ttype->get_program();
iproctorff8eb922007-07-25 19:06:13 +00001418
Christian Lavoie600a88c2010-11-07 18:37:11 +00001419 if (program != NULL && program != program_)
1420 if (!ttype->is_service())
1421 prefix = capitalize(program->get_name()) + "_Types.";
1422
1423 return prefix + function_prefix + capitalize(ttype->get_name());
iproctorff8eb922007-07-25 19:06:13 +00001424}
1425
1426/**
1427 * Converts the parse type to a Protocol.t_type enum
1428 */
1429string t_hs_generator::type_to_enum(t_type* type) {
David Reisse087a302007-08-23 21:43:25 +00001430 type = get_true_type(type);
David Reiss0c90f6f2008-02-06 22:18:40 +00001431
iproctorff8eb922007-07-25 19:06:13 +00001432 if (type->is_base_type()) {
1433 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1434 switch (tbase) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001435 case t_base_type::TYPE_VOID: return "T_VOID";
1436 case t_base_type::TYPE_STRING: return "T_STRING";
1437 case t_base_type::TYPE_BOOL: return "T_BOOL";
1438 case t_base_type::TYPE_BYTE: return "T_BYTE";
1439 case t_base_type::TYPE_I16: return "T_I16";
1440 case t_base_type::TYPE_I32: return "T_I32";
1441 case t_base_type::TYPE_I64: return "T_I64";
1442 case t_base_type::TYPE_DOUBLE: return "T_DOUBLE";
iproctorff8eb922007-07-25 19:06:13 +00001443 }
Christian Lavoie600a88c2010-11-07 18:37:11 +00001444
iproctorff8eb922007-07-25 19:06:13 +00001445 } else if (type->is_enum()) {
1446 return "T_I32";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001447
iproctorff8eb922007-07-25 19:06:13 +00001448 } else if (type->is_struct() || type->is_xception()) {
1449 return "T_STRUCT";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001450
iproctorff8eb922007-07-25 19:06:13 +00001451 } else if (type->is_map()) {
1452 return "T_MAP";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001453
iproctorff8eb922007-07-25 19:06:13 +00001454 } else if (type->is_set()) {
1455 return "T_SET";
Christian Lavoie600a88c2010-11-07 18:37:11 +00001456
iproctorff8eb922007-07-25 19:06:13 +00001457 } else if (type->is_list()) {
1458 return "T_LIST";
1459 }
1460
1461 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
1462}
1463
1464/**
1465 * Converts the parse type to an haskell type
1466 */
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001467string t_hs_generator::render_hs_type(t_type* type, bool needs_parens) {
David Reisse087a302007-08-23 21:43:25 +00001468 type = get_true_type(type);
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001469 string type_repr;
David Reiss0c90f6f2008-02-06 22:18:40 +00001470
iproctorff8eb922007-07-25 19:06:13 +00001471 if (type->is_base_type()) {
1472 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1473 switch (tbase) {
Christian Lavoie600a88c2010-11-07 18:37:11 +00001474 case t_base_type::TYPE_VOID: return "()";
Roger Meier6849f202012-05-18 07:35:19 +00001475 case t_base_type::TYPE_STRING: return (((t_base_type*)type)->is_binary() ? "ByteString" : "Text");
Christian Lavoie600a88c2010-11-07 18:37:11 +00001476 case t_base_type::TYPE_BOOL: return "Bool";
1477 case t_base_type::TYPE_BYTE: return "Int8";
1478 case t_base_type::TYPE_I16: return "Int16";
1479 case t_base_type::TYPE_I32: return "Int32";
1480 case t_base_type::TYPE_I64: return "Int64";
1481 case t_base_type::TYPE_DOUBLE: return "Double";
iproctorff8eb922007-07-25 19:06:13 +00001482 }
Christian Lavoie600a88c2010-11-07 18:37:11 +00001483
iproctorff8eb922007-07-25 19:06:13 +00001484 } else if (type->is_enum()) {
1485 return capitalize(((t_enum*)type)->get_name());
Christian Lavoie600a88c2010-11-07 18:37:11 +00001486
iproctorff8eb922007-07-25 19:06:13 +00001487 } else if (type->is_struct() || type->is_xception()) {
1488 return type_name((t_struct*)type);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001489
iproctorff8eb922007-07-25 19:06:13 +00001490 } else if (type->is_map()) {
1491 t_type* ktype = ((t_map*)type)->get_key_type();
1492 t_type* vtype = ((t_map*)type)->get_val_type();
Roger Meier6849f202012-05-18 07:35:19 +00001493 type_repr = "Map.HashMap " + render_hs_type(ktype, true) + " " + render_hs_type(vtype, true);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001494
iproctorff8eb922007-07-25 19:06:13 +00001495 } else if (type->is_set()) {
1496 t_type* etype = ((t_set*)type)->get_elem_type();
Roger Meier6849f202012-05-18 07:35:19 +00001497 type_repr = "Set.HashSet " + render_hs_type(etype, true) ;
Christian Lavoie600a88c2010-11-07 18:37:11 +00001498
iproctorff8eb922007-07-25 19:06:13 +00001499 } else if (type->is_list()) {
1500 t_type* etype = ((t_list*)type)->get_elem_type();
Roger Meier6849f202012-05-18 07:35:19 +00001501 type_repr = "Vector.Vector " + render_hs_type(etype, true);
Christian Lavoie600a88c2010-11-07 18:37:11 +00001502
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001503 } else {
1504 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
iproctorff8eb922007-07-25 19:06:13 +00001505 }
1506
Kevin Clark38c8b5b2009-03-24 14:51:51 +00001507 return needs_parens ? "(" + type_repr + ")" : type_repr;
iproctorff8eb922007-07-25 19:06:13 +00001508}
David Reissaf3ab262008-03-27 21:40:16 +00001509
Roger Meier0069cc42010-10-13 18:10:18 +00001510THRIFT_REGISTER_GENERATOR(hs, "Haskell", "")