blob: 6c618904339949d17270b20106c45933df019f15 [file] [log] [blame]
T Jake Luciani322caa22010-02-15 03:24:55 +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 */
19
20#include <string>
21#include <fstream>
22#include <iostream>
23#include <vector>
24#include <list>
25
26#include <stdlib.h>
27#include <sys/stat.h>
28#include <sstream>
29#include "platform.h"
Roger Meier08d46812011-04-12 19:08:21 +000030#include "version.h"
31
T Jake Luciani322caa22010-02-15 03:24:55 +000032using namespace std;
33
34
35#include "t_oop_generator.h"
36
37/**
38 * JS code generator.
39 */
40class t_js_generator : public t_oop_generator {
41 public:
42 t_js_generator(t_program* program,
43 const std::map<std::string, std::string>& parsed_options,
44 const std::string& option_string) :
45 t_oop_generator(program) {
Roger Meier3b771a12010-11-17 22:11:26 +000046 (void) option_string;
T Jake Luciani0c124bb2011-01-08 03:49:16 +000047
48 std::map<std::string, std::string>::const_iterator iter;
49
50 iter = parsed_options.find("node");
51 gen_node_ = (iter != parsed_options.end());
Roger Meier08b30992011-04-06 21:30:53 +000052
53 iter = parsed_options.find("jquery");
54 gen_jquery_ = (iter != parsed_options.end());
T Jake Luciani0c124bb2011-01-08 03:49:16 +000055
56 if (gen_node_) {
57 out_dir_base_ = "gen-nodejs";
58 } else {
59 out_dir_base_ = "gen-js";
60 }
T Jake Luciani322caa22010-02-15 03:24:55 +000061 }
62
63 /**
64 * Init and close methods
65 */
66
67 void init_generator();
68 void close_generator();
69
70 /**
71 * Program-level generation functions
72 */
73
74 void generate_typedef (t_typedef* ttypedef);
75 void generate_enum (t_enum* tenum);
76 void generate_const (t_const* tconst);
77 void generate_struct (t_struct* tstruct);
78 void generate_xception (t_struct* txception);
79 void generate_service (t_service* tservice);
80
T Jake Luciani0c124bb2011-01-08 03:49:16 +000081 std::string render_recv_throw(std::string var);
82 std::string render_recv_return(std::string var);
T Jake Luciani322caa22010-02-15 03:24:55 +000083
84 std::string render_const_value(t_type* type, t_const_value* value);
85
86
87 /**
88 * Structs!
89 */
90 void generate_js_struct(t_struct* tstruct, bool is_exception);
T Jake Luciani0c124bb2011-01-08 03:49:16 +000091 void generate_js_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_exported=true);
T Jake Luciani322caa22010-02-15 03:24:55 +000092 void generate_js_struct_reader(std::ofstream& out, t_struct* tstruct);
93 void generate_js_struct_writer(std::ofstream& out, t_struct* tstruct);
94 void generate_js_function_helpers(t_function* tfunction);
95
96 /**
97 * Service-level generation functions
98 */
99 void generate_service_helpers (t_service* tservice);
100 void generate_service_interface (t_service* tservice);
101 void generate_service_rest (t_service* tservice);
102 void generate_service_client (t_service* tservice);
103 void generate_service_processor (t_service* tservice);
104 void generate_process_function (t_service* tservice, t_function* tfunction);
105
106 /**
107 * Serialization constructs
108 */
109
110 void generate_deserialize_field (std::ofstream &out,
111 t_field* tfield,
112 std::string prefix="",
113 bool inclass=false);
114
115 void generate_deserialize_struct (std::ofstream &out,
116 t_struct* tstruct,
117 std::string prefix="");
118
119 void generate_deserialize_container (std::ofstream &out,
120 t_type* ttype,
121 std::string prefix="");
122
123 void generate_deserialize_set_element (std::ofstream &out,
124 t_set* tset,
125 std::string prefix="");
126
127 void generate_deserialize_map_element (std::ofstream &out,
128 t_map* tmap,
129 std::string prefix="");
130
131 void generate_deserialize_list_element (std::ofstream &out,
132 t_list* tlist,
133 std::string prefix="");
134
135 void generate_serialize_field (std::ofstream &out,
136 t_field* tfield,
137 std::string prefix="");
138
139 void generate_serialize_struct (std::ofstream &out,
140 t_struct* tstruct,
141 std::string prefix="");
142
143 void generate_serialize_container (std::ofstream &out,
144 t_type* ttype,
145 std::string prefix="");
146
147 void generate_serialize_map_element (std::ofstream &out,
148 t_map* tmap,
149 std::string kiter,
150 std::string viter);
151
152 void generate_serialize_set_element (std::ofstream &out,
153 t_set* tmap,
154 std::string iter);
155
156 void generate_serialize_list_element (std::ofstream &out,
157 t_list* tlist,
158 std::string iter);
159
160 /**
161 * Helper rendering functions
162 */
163
164 std::string js_includes();
Roger Meierafb0c7f2011-01-22 21:43:59 +0000165 std::string render_includes();
T Jake Luciani322caa22010-02-15 03:24:55 +0000166 std::string declare_field(t_field* tfield, bool init=false, bool obj=false);
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000167 std::string function_signature(t_function* tfunction, std::string prefix="", bool include_callback=false);
Roger Meier08b30992011-04-06 21:30:53 +0000168 std::string argument_list(t_struct* tstruct, bool include_callback=false);
T Jake Luciani322caa22010-02-15 03:24:55 +0000169 std::string type_to_enum(t_type* ttype);
170
171 std::string autogen_comment() {
172 return
173 std::string("//\n") +
Roger Meier08d46812011-04-12 19:08:21 +0000174 "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" +
T Jake Luciani322caa22010-02-15 03:24:55 +0000175 "//\n" +
176 "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
177 "//\n";
178 }
179
180 std::vector<std::string> js_namespace_pieces(t_program* p) {
181 std::string ns = p->get_namespace("js");
182
183 std::string::size_type loc;
184 std::vector<std::string> pieces;
185
186 if (ns.size() > 0) {
187 while ((loc = ns.find(".")) != std::string::npos) {
188 pieces.push_back(ns.substr(0, loc));
189 ns = ns.substr(loc+1);
190 }
191 }
192
193 if (ns.size() > 0) {
194 pieces.push_back(ns);
195 }
196
197 return pieces;
198 }
199
Roger Meierdd0c3282011-02-16 19:25:05 +0000200 std::string js_type_namespace(t_program* p) {
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000201 if (gen_node_) {
Roger Meierdd0c3282011-02-16 19:25:05 +0000202 if (p != NULL && p != program_) {
203 return p->get_name() + "_ttypes.";
Roger Meierafb0c7f2011-01-22 21:43:59 +0000204 }
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000205 return "ttypes.";
206 }
Roger Meierdd0c3282011-02-16 19:25:05 +0000207 return js_namespace(p);
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000208 }
209
210 std::string js_export_namespace(t_program* p) {
211 if (gen_node_) {
212 return "exports.";
213 }
214 return js_namespace(p);
215 }
216
T Jake Luciani322caa22010-02-15 03:24:55 +0000217 std::string js_namespace(t_program* p) {
218 std::string ns = p->get_namespace("js");
219 if (ns.size() > 0) {
220 ns += ".";
221 }
222
223
224 return ns;
225 }
226
227 private:
228
229 /**
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000230 * True iff we should generate NodeJS-friendly RPC services.
231 */
232 bool gen_node_;
233
234 /**
Roger Meier08b30992011-04-06 21:30:53 +0000235 * True if we should generate services that use jQuery ajax (async/sync).
236 */
237 bool gen_jquery_;
238
239 /**
T Jake Luciani322caa22010-02-15 03:24:55 +0000240 * File streams
241 */
242 std::ofstream f_types_;
243 std::ofstream f_service_;
244};
245
246
247/**
248 * Prepares for file generation by opening up the necessary file output
249 * streams.
250 *
251 * @param tprogram The program to generate
252 */
253void t_js_generator::init_generator() {
254 // Make output directory
255 MKDIR(get_out_dir().c_str());
256
257 string outdir = get_out_dir();
258
259 // Make output file
260 string f_types_name = outdir+program_->get_name()+"_types.js";
261 f_types_.open(f_types_name.c_str());
262
263 // Print header
264 f_types_ <<
265 autogen_comment() <<
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000266 js_includes() << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000267
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000268 if (gen_node_) {
269 f_types_ << "var ttypes = module.exports = {};" << endl;
270 }
T Jake Luciani322caa22010-02-15 03:24:55 +0000271
272 string pns;
273
274 //setup the namespace
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000275 // TODO should the namespace just be in the directory structure for node?
T Jake Luciani322caa22010-02-15 03:24:55 +0000276 vector<string> ns_pieces = js_namespace_pieces( program_ );
277 if( ns_pieces.size() > 0){
Roger Meier8430d502011-03-11 12:38:54 +0000278 f_types_ << "var " << ns_pieces[0] << " = {};"<<endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000279
280 pns = ns_pieces[0];
281
282 for(size_t i=1; i<ns_pieces.size(); i++){
283 pns += "." + ns_pieces[i];
284
285 f_types_ << pns << " = {}"<<endl;
286 }
287 }
288
289}
290
291/**
292 * Prints standard js imports
293 */
294string t_js_generator::js_includes() {
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000295 if (gen_node_) {
296 return string("var Thrift = require('thrift').Thrift;");
297 }
T Jake Luciani322caa22010-02-15 03:24:55 +0000298 string inc;
299
300 return inc;
301}
302
303/**
Roger Meierafb0c7f2011-01-22 21:43:59 +0000304 * Renders all the imports necessary for including another Thrift program
305 */
306string t_js_generator::render_includes() {
307 if (gen_node_) {
308 const vector<t_program*>& includes = program_->get_includes();
309 string result = "";
310 for (size_t i = 0; i < includes.size(); ++i) {
311 result += "var " + includes[i]->get_name() + "_ttypes = require('./" + includes[i]->get_name() + "_types')\n";
312 }
313 if (includes.size() > 0) {
314 result += "\n";
315 }
316 return result;
317 }
318 string inc;
319
320 return inc;
321}
322
323/**
T Jake Luciani322caa22010-02-15 03:24:55 +0000324 * Close up (or down) some filez.
325 */
326void t_js_generator::close_generator() {
327 // Close types file
328
329 f_types_.close();
330}
331
332/**
333 * Generates a typedef. This is not done in JS, types are all implicit.
334 *
335 * @param ttypedef The type definition
336 */
Roger Meier3b771a12010-11-17 22:11:26 +0000337void t_js_generator::generate_typedef(t_typedef* ttypedef) {
338 (void) ttypedef;
339}
T Jake Luciani322caa22010-02-15 03:24:55 +0000340
341/**
342 * Generates code for an enumerated type. Since define is expensive to lookup
343 * in JS, we use a global array for this.
344 *
345 * @param tenum The enumeration
346 */
347void t_js_generator::generate_enum(t_enum* tenum) {
Roger Meier8430d502011-03-11 12:38:54 +0000348 f_types_ << js_type_namespace(tenum->get_program())<<tenum->get_name()<<" = {"<<endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000349
350 vector<t_enum_value*> constants = tenum->get_constants();
351 vector<t_enum_value*>::iterator c_iter;
T Jake Luciani322caa22010-02-15 03:24:55 +0000352 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
Bryan Duxburya406b902010-09-27 23:37:44 +0000353 int value = (*c_iter)->get_value();
Roger Meier08b30992011-04-06 21:30:53 +0000354 f_types_ << "'" << (*c_iter)->get_name() << "' : " << value;
355 if (c_iter != constants.end()-1) {
T Jake Luciani322caa22010-02-15 03:24:55 +0000356 f_types_ << ",";
Roger Meier08b30992011-04-06 21:30:53 +0000357 }
358 f_types_ << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000359 }
360
Roger Meier8430d502011-03-11 12:38:54 +0000361 f_types_ << "};"<<endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000362}
363
364/**
365 * Generate a constant value
366 */
367void t_js_generator::generate_const(t_const* tconst) {
368 t_type* type = tconst->get_type();
369 string name = tconst->get_name();
370 t_const_value* value = tconst->get_value();
371
Roger Meierdd0c3282011-02-16 19:25:05 +0000372 f_types_ << js_type_namespace(program_) << name << " = ";
Roger Meier8430d502011-03-11 12:38:54 +0000373 f_types_ << render_const_value(type, value) << ";" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000374}
375
376/**
377 * Prints the value of a constant with the given type. Note that type checking
378 * is NOT performed in this function as it is always run beforehand using the
379 * validate_types method in main.cc
380 */
381string t_js_generator::render_const_value(t_type* type, t_const_value* value) {
382 std::ostringstream out;
383
384 type = get_true_type(type);
385
386 if (type->is_base_type()) {
387 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
388 switch (tbase) {
389 case t_base_type::TYPE_STRING:
390 out << "'" << value->get_string() << "'";
391 break;
392 case t_base_type::TYPE_BOOL:
393 out << (value->get_integer() > 0 ? "true" : "false");
394 break;
395 case t_base_type::TYPE_BYTE:
396 case t_base_type::TYPE_I16:
397 case t_base_type::TYPE_I32:
398 case t_base_type::TYPE_I64:
399 out << value->get_integer();
400 break;
401 case t_base_type::TYPE_DOUBLE:
402 if (value->get_type() == t_const_value::CV_INTEGER) {
403 out << value->get_integer();
404 } else {
405 out << value->get_double();
406 }
407 break;
408 default:
409 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
410 }
411 } else if (type->is_enum()) {
412 out << value->get_integer();
413 } else if (type->is_struct() || type->is_xception()) {
Roger Meierdd0c3282011-02-16 19:25:05 +0000414 out << "new " << js_type_namespace(type->get_program()) << type->get_name() << "({" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000415 indent_up();
416 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
417 vector<t_field*>::const_iterator f_iter;
418 const map<t_const_value*, t_const_value*>& val = value->get_map();
419 map<t_const_value*, t_const_value*>::const_iterator v_iter;
420 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
421 t_type* field_type = NULL;
422 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
423 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
424 field_type = (*f_iter)->get_type();
425 }
426 }
427 if (field_type == NULL) {
428 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
429 }
T Jake Luciani6461d562010-09-22 02:33:06 +0000430 if (v_iter != val.begin())
431 out << ",";
T Jake Luciani322caa22010-02-15 03:24:55 +0000432 out << render_const_value(g_type_string, v_iter->first);
433 out << " : ";
434 out << render_const_value(field_type, v_iter->second);
T Jake Luciani322caa22010-02-15 03:24:55 +0000435 }
436
437 out << "})";
438 } else if (type->is_map()) {
439 t_type* ktype = ((t_map*)type)->get_key_type();
440 bool key_is_string = false;
441 if (ktype->is_base_type() && ((t_base_type*)ktype)->get_base() == t_base_type::TYPE_STRING){
442 key_is_string = true;
443 }
444
445 t_type* vtype = ((t_map*)type)->get_val_type();
446 out << "{";
447
448 const map<t_const_value*, t_const_value*>& val = value->get_map();
449 map<t_const_value*, t_const_value*>::const_iterator v_iter;
450 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
T Jake Luciani6461d562010-09-22 02:33:06 +0000451 if (v_iter != val.begin())
452 out << "," << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000453
454 out << render_const_value(ktype, v_iter->first);
455
456 out << " : ";
457 out << render_const_value(vtype, v_iter->second);
T Jake Luciani322caa22010-02-15 03:24:55 +0000458 }
459
T Jake Luciani6461d562010-09-22 02:33:06 +0000460 out << endl << "}";
T Jake Luciani322caa22010-02-15 03:24:55 +0000461 } else if (type->is_list() || type->is_set()) {
462 t_type* etype;
463 if (type->is_list()) {
464 etype = ((t_list*)type)->get_elem_type();
465 } else {
466 etype = ((t_set*)type)->get_elem_type();
467 }
468 out << "[";
469 const vector<t_const_value*>& val = value->get_list();
470 vector<t_const_value*>::const_iterator v_iter;
471 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
T Jake Luciani6461d562010-09-22 02:33:06 +0000472 if (v_iter != val.begin())
473 out << ",";
T Jake Luciani322caa22010-02-15 03:24:55 +0000474 out << render_const_value(etype, *v_iter);
T Jake Luciani322caa22010-02-15 03:24:55 +0000475 }
476 out << "]";
477 }
478 return out.str();
479}
480
481/**
482 * Make a struct
483 */
484void t_js_generator::generate_struct(t_struct* tstruct) {
485 generate_js_struct(tstruct, false);
486}
487
488/**
489 * Generates a struct definition for a thrift exception. Basically the same
490 * as a struct but extends the Exception class.
491 *
492 * @param txception The struct definition
493 */
494void t_js_generator::generate_xception(t_struct* txception) {
495 generate_js_struct(txception, true);
496}
497
498/**
499 * Structs can be normal or exceptions.
500 */
501void t_js_generator::generate_js_struct(t_struct* tstruct,
502 bool is_exception) {
503 generate_js_struct_definition(f_types_, tstruct, is_exception);
504}
505
506/**
507 * Generates a struct definition for a thrift data type. This is nothing in JS
508 * where the objects are all just associative arrays (unless of course we
509 * decide to start using objects for them...)
510 *
511 * @param tstruct The struct definition
512 */
513void t_js_generator::generate_js_struct_definition(ofstream& out,
514 t_struct* tstruct,
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000515 bool is_exception,
516 bool is_exported) {
T Jake Luciani322caa22010-02-15 03:24:55 +0000517 const vector<t_field*>& members = tstruct->get_members();
518 vector<t_field*>::const_iterator m_iter;
519
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000520 indent_up();
T Jake Luciani322caa22010-02-15 03:24:55 +0000521
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000522 if (gen_node_) {
523 if (is_exported) {
524 out << "var " << js_namespace(tstruct->get_program()) << tstruct->get_name() << " = " <<
Roger Meier8430d502011-03-11 12:38:54 +0000525 "module.exports." << js_namespace(tstruct->get_program()) << tstruct->get_name() << " = function(args) {\n";
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000526 } else {
Roger Meier8430d502011-03-11 12:38:54 +0000527 out << "var " << js_namespace(tstruct->get_program()) << tstruct->get_name() << " = function(args) {\n";
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000528 }
529 } else {
Roger Meier8430d502011-03-11 12:38:54 +0000530 out << js_namespace(tstruct->get_program()) << tstruct->get_name() <<" = function(args) {\n";
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000531 }
532
533 if (gen_node_ && is_exception) {
534 out << indent() << "Thrift.TException.call(this, \"" <<
535 js_namespace(tstruct->get_program()) << tstruct->get_name() << "\")" << endl;
536 out << indent() << "this.name = \"" <<
537 js_namespace(tstruct->get_program()) << tstruct->get_name() << "\"" << endl;
538 }
T Jake Luciani322caa22010-02-15 03:24:55 +0000539
540 //members with arguments
541 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000542 string dval = declare_field(*m_iter,false,true);
T Jake Luciani322caa22010-02-15 03:24:55 +0000543 t_type* t = get_true_type((*m_iter)->get_type());
544 if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
Roger Meier8430d502011-03-11 12:38:54 +0000545 dval = render_const_value((*m_iter)-> get_type(), (*m_iter)->get_value());
546 out << indent() << "this." << (*m_iter)->get_name() << " = " << dval << ";" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000547 } else {
Roger Meier8430d502011-03-11 12:38:54 +0000548 out << indent() << dval << ";" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000549 }
550
551 }
552
553 // Generate constructor from array
554 if (members.size() > 0) {
555
556 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
557 t_type* t = get_true_type((*m_iter)->get_type());
558 if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
Roger Meier8430d502011-03-11 12:38:54 +0000559 indent(out) << "this." << (*m_iter)->get_name() << " = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000560 }
561 }
562
Roger Meierda6e6ae2011-03-15 09:55:33 +0000563 out << indent() << "if (args) {" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000564
565 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
Roger Meierda6e6ae2011-03-15 09:55:33 +0000566 out << indent() << indent() << "if (!args." << (*m_iter)->get_name() << ") {" << endl
Roger Meier8430d502011-03-11 12:38:54 +0000567 << indent() << indent() << indent() << "this." << (*m_iter)->get_name() << " = args." << (*m_iter)->get_name() << ";" << endl
568 << indent() << indent() << "}" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000569 }
570
Roger Meier8430d502011-03-11 12:38:54 +0000571 out << indent() << "}" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000572
573 }
574
575 indent_down();
Roger Meier8430d502011-03-11 12:38:54 +0000576 out << "};\n";
T Jake Luciani322caa22010-02-15 03:24:55 +0000577
578 if (is_exception) {
Roger Meier90443f42011-01-22 21:35:48 +0000579 out << "Thrift.inherits(" <<
580 js_namespace(tstruct->get_program()) <<
Roger Meier8430d502011-03-11 12:38:54 +0000581 tstruct->get_name() << ", Thrift.TException);" << endl;
Roger Meier90443f42011-01-22 21:35:48 +0000582 } else {
583 //init prototype
Roger Meier8430d502011-03-11 12:38:54 +0000584 out << js_namespace(tstruct->get_program())<<tstruct->get_name() <<".prototype = {};\n";
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000585 }
T Jake Luciani322caa22010-02-15 03:24:55 +0000586
587
588 generate_js_struct_reader(out, tstruct);
589 generate_js_struct_writer(out, tstruct);
590
591}
592
593/**
594 * Generates the read() method for a struct
595 */
596void t_js_generator::generate_js_struct_reader(ofstream& out,
597 t_struct* tstruct) {
598 const vector<t_field*>& fields = tstruct->get_members();
599 vector<t_field*>::const_iterator f_iter;
600
Roger Meier8430d502011-03-11 12:38:54 +0000601 out << js_namespace(tstruct->get_program())<<tstruct->get_name() << ".prototype.read = function(input) {"<<endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000602
603 indent_up();
604
Roger Meier8430d502011-03-11 12:38:54 +0000605 indent(out) << "input.readStructBegin();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000606
607
608 // Loop over reading in fields
Roger Meier8430d502011-03-11 12:38:54 +0000609 indent(out) << "while (true)" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000610
611 scope_up(out);
612
Roger Meier8430d502011-03-11 12:38:54 +0000613 indent(out) << "var ret = input.readFieldBegin();" << endl;
614 indent(out) << "var fname = ret.fname;" << endl;
615 indent(out) << "var ftype = ret.ftype;" << endl;
616 indent(out) << "var fid = ret.fid;" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000617
618
619 // Check for field STOP marker and break
Roger Meierda6e6ae2011-03-15 09:55:33 +0000620 indent(out) << "if (ftype == Thrift.Type.STOP) {" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000621 indent_up();
Roger Meier8430d502011-03-11 12:38:54 +0000622 indent(out) << "break;" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000623 indent_down();
Roger Meierda6e6ae2011-03-15 09:55:33 +0000624 indent(out) << "}" << endl;
625 if (!fields.empty()) {
626 // Switch statement on the field we are reading
627 indent(out) << "switch (fid)" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000628
Roger Meierda6e6ae2011-03-15 09:55:33 +0000629 scope_up(out);
T Jake Luciani322caa22010-02-15 03:24:55 +0000630
Roger Meierda6e6ae2011-03-15 09:55:33 +0000631 // Generate deserialization code for known cases
632 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
T Jake Luciani322caa22010-02-15 03:24:55 +0000633
Roger Meierda6e6ae2011-03-15 09:55:33 +0000634 indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
635 indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000636
Roger Meierda6e6ae2011-03-15 09:55:33 +0000637 indent_up();
638 generate_deserialize_field(out, *f_iter, "this.");
639 indent_down();
T Jake Luciani322caa22010-02-15 03:24:55 +0000640
Roger Meierda6e6ae2011-03-15 09:55:33 +0000641 indent(out) << "} else {" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000642
Roger Meierda6e6ae2011-03-15 09:55:33 +0000643 indent(out) << " input.skip(ftype);" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000644
Roger Meierda6e6ae2011-03-15 09:55:33 +0000645 out <<
646 indent() << "}" << endl <<
647 indent() << "break;" << endl;
648
649 }
650 if (fields.size() == 1) {
651 // pseudo case to make jslint happy
652 indent(out) << "case 0:" << endl;
653 indent(out) << " input.skip(ftype);" << endl;
654 indent(out) << " break;" << endl;
655 }
656 // In the default case we skip the field
657 indent(out) << "default:" << endl;
Roger Meier8430d502011-03-11 12:38:54 +0000658 indent(out) << " input.skip(ftype);" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000659
Roger Meierda6e6ae2011-03-15 09:55:33 +0000660 scope_down(out);
661 } else {
662 indent(out) << "input.skip(ftype);" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000663 }
T Jake Luciani322caa22010-02-15 03:24:55 +0000664
Roger Meier8430d502011-03-11 12:38:54 +0000665 indent(out) << "input.readFieldEnd();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000666
667 scope_down(out);
668
Roger Meier8430d502011-03-11 12:38:54 +0000669 indent(out) << "input.readStructEnd();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000670
Roger Meier8430d502011-03-11 12:38:54 +0000671 indent(out) << "return;" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000672
673 indent_down();
Roger Meier8430d502011-03-11 12:38:54 +0000674 out << indent() << "};" << endl << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000675}
676
677/**
678 * Generates the write() method for a struct
679 */
680void t_js_generator::generate_js_struct_writer(ofstream& out,
681 t_struct* tstruct) {
682 string name = tstruct->get_name();
683 const vector<t_field*>& fields = tstruct->get_members();
684 vector<t_field*>::const_iterator f_iter;
685
Roger Meier8430d502011-03-11 12:38:54 +0000686 out << js_namespace(tstruct->get_program())<< tstruct->get_name() << ".prototype.write = function(output) {"<<endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000687
688 indent_up();
689
Roger Meier8430d502011-03-11 12:38:54 +0000690 indent(out) << "output.writeStructBegin('" << name << "');" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000691
692 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
Roger Meierda6e6ae2011-03-15 09:55:33 +0000693 out << indent() << "if (this." << (*f_iter)->get_name() << ") {" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000694 indent_up();
695
696 indent(out) <<
697 "output.writeFieldBegin(" <<
698 "'" << (*f_iter)->get_name() << "', " <<
699 type_to_enum((*f_iter)->get_type()) << ", " <<
Roger Meier8430d502011-03-11 12:38:54 +0000700 (*f_iter)->get_key() << ");" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000701
702
703 // Write field contents
704 generate_serialize_field(out, *f_iter, "this.");
705
706 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +0000707 "output.writeFieldEnd();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000708
709 indent_down();
710 indent(out) << "}" << endl;
711 }
712
713
714 out <<
Roger Meier8430d502011-03-11 12:38:54 +0000715 indent() << "output.writeFieldStop();" << endl <<
716 indent() << "output.writeStructEnd();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000717
Roger Meier8430d502011-03-11 12:38:54 +0000718 out <<indent() << "return;" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000719
720 indent_down();
721 out <<
Roger Meier8430d502011-03-11 12:38:54 +0000722 indent() << "};" << endl <<
T Jake Luciani322caa22010-02-15 03:24:55 +0000723 endl;
724}
725
726/**
727 * Generates a thrift service.
728 *
729 * @param tservice The service definition
730 */
731void t_js_generator::generate_service(t_service* tservice) {
732 string f_service_name = get_out_dir()+service_name_+".js";
733 f_service_.open(f_service_name.c_str());
734
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000735 f_service_ <<
736 autogen_comment() <<
Roger Meierafb0c7f2011-01-22 21:43:59 +0000737 js_includes() << endl <<
738 render_includes() << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000739
740 if (gen_node_) {
Roger Meierafb0c7f2011-01-22 21:43:59 +0000741 if (tservice->get_extends() != NULL) {
742 f_service_ <<
743 "var " << tservice->get_extends()->get_name() <<
744 " = require('./" << tservice->get_extends()->get_name() << "')" << endl <<
745 "var " << tservice->get_extends()->get_name() << "Client = " <<
746 tservice->get_extends()->get_name() << ".Client" << endl;
747
748 }
749
Roger Meierdd0c3282011-02-16 19:25:05 +0000750 f_service_ <<
751 "var ttypes = require('./" + program_->get_name() + "_types');" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000752 }
753
T Jake Luciani322caa22010-02-15 03:24:55 +0000754 generate_service_helpers(tservice);
755 generate_service_interface(tservice);
756 generate_service_client(tservice);
757
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000758 if (gen_node_) {
759 generate_service_processor(tservice);
760 }
761
T Jake Luciani322caa22010-02-15 03:24:55 +0000762 f_service_.close();
763}
764
765/**
766 * Generates a service server definition.
767 *
768 * @param tservice The service to generate a server for.
769 */
770void t_js_generator::generate_service_processor(t_service* tservice) {
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000771 vector<t_function*> functions = tservice->get_functions();
772 vector<t_function*>::iterator f_iter;
773
774 f_service_ <<
775 "var " << js_namespace(tservice->get_program()) << service_name_ << "Processor = " <<
776 "exports.Processor = function(handler) ";
777
778 scope_up(f_service_);
779
780 f_service_ << indent() << "this._handler = handler" << endl;
781
782 scope_down(f_service_);
783
784 // Generate the server implementation
785 indent(f_service_) <<
786 js_namespace(tservice->get_program()) << service_name_ << "Processor.prototype.process = function(input, output) ";
787
788 scope_up(f_service_);
789
Roger Meier8430d502011-03-11 12:38:54 +0000790 f_service_ << indent() << "var r = input.readMessageBegin();" << endl
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000791 << indent() << "if (this['process_' + r.fname]) {" << endl
Roger Meier8430d502011-03-11 12:38:54 +0000792 << indent() << " return this['process_' + r.fname].call(this, r.rseqid, input, output);" << endl
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000793 << indent() << "} else {" << endl
Roger Meier8430d502011-03-11 12:38:54 +0000794 << indent() << " input.skip(Thrift.Type.STRUCT);" << endl
795 << indent() << " input.readMessageEnd();" << endl
796 << indent() << " var x = new Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN_METHOD, 'Unknown function ' + r.fname);" << endl
797 << indent() << " output.writeMessageBegin(r.fname, Thrift.MessageType.Exception, r.rseqid);" << endl
798 << indent() << " x.write(output);" << endl
799 << indent() << " output.writeMessageEnd();" << endl
800 << indent() << " output.flush();" << endl
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000801 << indent() << "}" << endl;
802
803 scope_down(f_service_);
804 f_service_ << endl;
805
806 // Generate the process subfunctions
807 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
808 generate_process_function(tservice, *f_iter);
809 }
T Jake Luciani322caa22010-02-15 03:24:55 +0000810}
811
812/**
813 * Generates a process function definition.
814 *
815 * @param tfunction The function to write a dispatcher for
816 */
817void t_js_generator::generate_process_function(t_service* tservice,
818 t_function* tfunction) {
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000819 indent(f_service_) <<
820 js_namespace(tservice->get_program()) << service_name_ << "Processor.prototype.process_" + tfunction->get_name() + " = function(seqid, input, output) ";
821
822 scope_up(f_service_);
823
824 string argsname = js_namespace(program_)+ service_name_ + "_" + tfunction->get_name() + "_args";
825 string resultname = js_namespace(program_)+ service_name_ + "_" + tfunction->get_name() + "_result";
826
827 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +0000828 indent() << "var args = new " << argsname << "();" << endl <<
829 indent() << "args.read(input);" << endl <<
830 indent() << "input.readMessageEnd();" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000831
832 // Declare result for non oneway function
833 if (!tfunction->is_oneway()) {
834 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +0000835 indent() << "var result = new " << resultname << "();" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000836 }
837
838 // Generate the function call
839 t_struct* arg_struct = tfunction->get_arglist();
840 const std::vector<t_field*>& fields = arg_struct->get_members();
841 vector<t_field*>::const_iterator f_iter;
842
843 f_service_ <<
844 indent() << "this._handler." << tfunction->get_name() << "(";
845
846 bool first = true;
847 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
848 if (first) {
849 first = false;
850 } else {
851 f_service_ << ", ";
852 }
853 f_service_ << "args." << (*f_iter)->get_name();
854 }
855
856 // Shortcut out here for oneway functions
857 if (tfunction->is_oneway()) {
858 f_service_ << ")" << endl;
859 scope_down(f_service_);
860 f_service_ << endl;
861 return;
862 }
863
864 if (!first) {
865 f_service_ << ", ";
866 }
Roger Meier8430d502011-03-11 12:38:54 +0000867 f_service_ << "function (success) {" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000868 indent_up();
869
870 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +0000871 indent() << "result.success = success;" << endl <<
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000872 indent() << "output.writeMessageBegin(\"" << tfunction->get_name() <<
Roger Meier8430d502011-03-11 12:38:54 +0000873 "\", Thrift.MessageType.REPLY, seqid);" << endl <<
874 indent() << "result.write(output);" << endl <<
875 indent() << "output.writeMessageEnd();" << endl <<
876 indent() << "output.flush();" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000877
878 indent_down();
879 indent(f_service_) << "})" << endl;
880
881 scope_down(f_service_);
882 f_service_ << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000883}
884
885/**
886 * Generates helper functions for a service.
887 *
888 * @param tservice The service to generate a header definition for
889 */
890void t_js_generator::generate_service_helpers(t_service* tservice) {
891 vector<t_function*> functions = tservice->get_functions();
892 vector<t_function*>::iterator f_iter;
893
894 f_service_ <<
895 "//HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
896
897 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
898 t_struct* ts = (*f_iter)->get_arglist();
899 string name = ts->get_name();
900 ts->set_name(service_name_ + "_" + name);
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000901 generate_js_struct_definition(f_service_, ts, false, false);
T Jake Luciani322caa22010-02-15 03:24:55 +0000902 generate_js_function_helpers(*f_iter);
903 ts->set_name(name);
904 }
905}
906
907/**
908 * Generates a struct and helpers for a function.
909 *
910 * @param tfunction The function
911 */
912void t_js_generator::generate_js_function_helpers(t_function* tfunction) {
913 t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result");
914 t_field success(tfunction->get_returntype(), "success", 0);
915 if (!tfunction->get_returntype()->is_void()) {
916 result.append(&success);
917 }
918
919 t_struct* xs = tfunction->get_xceptions();
920 const vector<t_field*>& fields = xs->get_members();
921 vector<t_field*>::const_iterator f_iter;
922 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
923 result.append(*f_iter);
924 }
925
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000926 generate_js_struct_definition(f_service_, &result, false, false);
T Jake Luciani322caa22010-02-15 03:24:55 +0000927}
928
929/**
930 * Generates a service interface definition.
931 *
932 * @param tservice The service to generate a header definition for
933 */
934void t_js_generator::generate_service_interface(t_service* tservice) {
Roger Meier3b771a12010-11-17 22:11:26 +0000935 (void) tservice;
T Jake Luciani322caa22010-02-15 03:24:55 +0000936}
937
938/**
939 * Generates a REST interface
940 */
941void t_js_generator::generate_service_rest(t_service* tservice) {
Roger Meier3b771a12010-11-17 22:11:26 +0000942 (void) tservice;
T Jake Luciani322caa22010-02-15 03:24:55 +0000943}
944
945/**
946 * Generates a service client definition.
947 *
948 * @param tservice The service to generate a server for.
949 */
950void t_js_generator::generate_service_client(t_service* tservice) {
951 string extends = "";
952
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000953 if (gen_node_) {
954 f_service_ <<
955 "var " << js_namespace(tservice->get_program()) << service_name_ << "Client = " <<
956 "exports.Client = function(output, pClass) {"<<endl;
957 } else {
958 f_service_ <<
959 js_namespace(tservice->get_program()) << service_name_ << "Client = function(input, output) {"<<endl;
960 }
T Jake Luciani322caa22010-02-15 03:24:55 +0000961
962 indent_up();
963
964
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000965 if (gen_node_) {
966 f_service_ <<
967 indent() << " this.output = output;" << endl <<
968 indent() << " this.pClass = pClass;" << endl <<
969 indent() << " this.seqid = 0;" << endl <<
Roger Meier8430d502011-03-11 12:38:54 +0000970 indent() << " this._reqs = {};" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000971 } else {
972 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +0000973 indent() << " this.input = input;" << endl <<
Roger Meierda6e6ae2011-03-15 09:55:33 +0000974 indent() << " this.output = (!output) ? input : output;" << endl <<
Roger Meier8430d502011-03-11 12:38:54 +0000975 indent() << " this.seqid = 0;" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +0000976 }
977
T Jake Luciani322caa22010-02-15 03:24:55 +0000978
979 indent_down();
980
981 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +0000982 indent() << "};" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000983
984
985 if (tservice->get_extends() != NULL) {
Roger Meier90443f42011-01-22 21:35:48 +0000986 indent(f_service_) << "Thrift.inherits(" <<
987 js_namespace(tservice->get_program()) <<
988 service_name_ << "Client, " <<
Roger Meierafb0c7f2011-01-22 21:43:59 +0000989 tservice->get_extends()->get_name() << "Client)" << endl;
Roger Meier90443f42011-01-22 21:35:48 +0000990 } else {
991 //init prototype
Roger Meier8430d502011-03-11 12:38:54 +0000992 indent(f_service_) << js_namespace(tservice->get_program())<<service_name_ << "Client.prototype = {};"<<endl;
T Jake Luciani322caa22010-02-15 03:24:55 +0000993 }
994
T Jake Luciani322caa22010-02-15 03:24:55 +0000995 // Generate client method implementations
996 vector<t_function*> functions = tservice->get_functions();
997 vector<t_function*>::const_iterator f_iter;
998 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
999 t_struct* arg_struct = (*f_iter)->get_arglist();
1000 const vector<t_field*>& fields = arg_struct->get_members();
1001 vector<t_field*>::const_iterator fld_iter;
1002 string funname = (*f_iter)->get_name();
Roger Meier08b30992011-04-06 21:30:53 +00001003 string arglist = argument_list(arg_struct);
T Jake Luciani322caa22010-02-15 03:24:55 +00001004
1005 // Open function
Roger Meier08b30992011-04-06 21:30:53 +00001006 f_service_ << js_namespace(tservice->get_program())<<service_name_<<"Client.prototype." <<
1007 function_signature(*f_iter, "", gen_node_ || gen_jquery_) << " {" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001008
1009 indent_up();
1010
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001011 if (gen_node_) {
1012 f_service_ <<
1013 indent() << "this.seqid += 1;" << endl <<
1014 indent() << "this._reqs[this.seqid] = callback;" << endl;
Roger Meier08b30992011-04-06 21:30:53 +00001015 } else if (gen_jquery_) {
1016 f_service_ <<
1017 indent() << "if (callback === undefined) {" << endl;
1018 indent_up();
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001019 }
1020
Roger Meier08b30992011-04-06 21:30:53 +00001021 f_service_ << indent() <<
1022 "this.send_" << funname << "(" << arglist << ");" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001023
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001024 if (!gen_node_ && !(*f_iter)->is_oneway()) {
T Jake Luciani322caa22010-02-15 03:24:55 +00001025 f_service_ << indent();
1026 if (!(*f_iter)->get_returntype()->is_void()) {
1027 f_service_ << "return ";
1028 }
1029 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +00001030 "this.recv_" << funname << "();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001031 }
1032
Roger Meier08b30992011-04-06 21:30:53 +00001033 if (gen_jquery_) {
1034 indent_down();
1035 f_service_ << indent() << "} else {" << endl;
1036 indent_up();
1037 f_service_ << indent() << "var postData = this.send_" << funname <<
1038 "(" << arglist << (arglist.empty() ? "" : ", ") << "true);" << endl;
1039 f_service_ << indent() << "return this.output.getTransport()" << endl;
1040 indent_up();
1041 f_service_ << indent() << ".jqRequest(this, postData, arguments, this.recv_" << funname << ");" << endl;
1042 indent_down();
1043 indent_down();
1044 f_service_ << indent() << "}" << endl;
1045 }
1046
T Jake Luciani322caa22010-02-15 03:24:55 +00001047 indent_down();
1048
Roger Meier8430d502011-03-11 12:38:54 +00001049 f_service_ << "};" << endl << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001050
Roger Meier08b30992011-04-06 21:30:53 +00001051
1052 // Send function
T Jake Luciani322caa22010-02-15 03:24:55 +00001053 f_service_ << js_namespace(tservice->get_program())<<service_name_ <<
Roger Meier08b30992011-04-06 21:30:53 +00001054 "Client.prototype.send_" << function_signature(*f_iter, "", gen_jquery_) << " {" <<endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001055
1056 indent_up();
1057
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001058 std::string outputVar;
1059 if (gen_node_) {
1060 f_service_ <<
1061 indent() << "var output = new this.pClass(this.output);" << endl;
1062 outputVar = "output";
1063 } else {
1064 outputVar = "this.output";
1065 }
1066
T Jake Luciani322caa22010-02-15 03:24:55 +00001067 std::string argsname = js_namespace(program_)+ service_name_ + "_" + (*f_iter)->get_name() + "_args";
1068
1069 // Serialize the request header
1070 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +00001071 indent() << outputVar << ".writeMessageBegin('" << (*f_iter)->get_name() << "', Thrift.MessageType.CALL, this.seqid);" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001072
1073 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +00001074 indent() << "var args = new " << argsname << "();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001075
1076 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1077 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +00001078 indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001079 }
1080
1081 // Write to the stream
1082 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +00001083 indent() << "args.write(" << outputVar << ");" << endl <<
1084 indent() << outputVar << ".writeMessageEnd();" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001085
1086 if (gen_node_) {
Roger Meier8430d502011-03-11 12:38:54 +00001087 f_service_ << indent() << "return this.output.flush();" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001088 } else {
Roger Meier08b30992011-04-06 21:30:53 +00001089 if (gen_jquery_) {
1090 f_service_ << indent() << "return this.output.getTransport().flush(callback);" << endl;
1091 } else {
1092 f_service_ << indent() << "return this.output.getTransport().flush();" << endl;
1093 }
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001094 }
T Jake Luciani322caa22010-02-15 03:24:55 +00001095
1096
1097 indent_down();
1098
Roger Meier8430d502011-03-11 12:38:54 +00001099 f_service_ << "};" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001100
1101
1102 if (!(*f_iter)->is_oneway()) {
1103 std::string resultname = js_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result";
T Jake Luciani322caa22010-02-15 03:24:55 +00001104
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001105 if (gen_node_) {
1106 // Open function
1107 f_service_ <<
1108 endl << js_namespace(tservice->get_program())<<service_name_ <<
Roger Meier8430d502011-03-11 12:38:54 +00001109 "Client.prototype.recv_" << (*f_iter)->get_name() << " = function(input,mtype,rseqid) {" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001110 } else {
1111 t_struct noargs(program_);
1112
1113 t_function recv_function((*f_iter)->get_returntype(),
1114 string("recv_") + (*f_iter)->get_name(),
1115 &noargs);
1116 // Open function
1117 f_service_ <<
1118 endl << js_namespace(tservice->get_program())<<service_name_ <<
Roger Meier8430d502011-03-11 12:38:54 +00001119 "Client.prototype." << function_signature(&recv_function) << " {" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001120 }
T Jake Luciani322caa22010-02-15 03:24:55 +00001121
1122 indent_up();
1123
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001124 std::string inputVar;
1125 if (gen_node_) {
1126 inputVar = "input";
1127 } else {
1128 inputVar = "this.input";
1129 }
1130
1131 if (gen_node_) {
1132 f_service_ <<
1133 indent() << "var callback = this._reqs[rseqid] || function() {};" << endl <<
1134 indent() << "delete this._reqs[rseqid];" << endl;
1135 } else {
1136 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +00001137 indent() << "var ret = this.input.readMessageBegin();" << endl <<
1138 indent() << "var fname = ret.fname;" << endl <<
1139 indent() << "var mtype = ret.mtype;" << endl <<
1140 indent() << "var rseqid = ret.rseqid;" <<endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001141 }
1142
1143 f_service_ <<
T Jake Luciani322caa22010-02-15 03:24:55 +00001144 indent() << "if (mtype == Thrift.MessageType.EXCEPTION) {" << endl <<
Roger Meier8430d502011-03-11 12:38:54 +00001145 indent() << " var x = new Thrift.TApplicationException();" << endl <<
1146 indent() << " x.read(" << inputVar << ");" << endl <<
1147 indent() << " " << inputVar << ".readMessageEnd();" << endl <<
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001148 indent() << " " << render_recv_throw("x") << endl <<
T Jake Luciani322caa22010-02-15 03:24:55 +00001149 indent() << "}" << endl;
1150
1151
1152 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +00001153 indent() << "var result = new " << resultname << "();" << endl <<
1154 indent() << "result.read(" << inputVar << ");" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001155
1156
1157 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +00001158 indent() << inputVar << ".readMessageEnd();" << endl <<
T Jake Luciani322caa22010-02-15 03:24:55 +00001159 endl;
1160
1161
T Jake Luciani322caa22010-02-15 03:24:55 +00001162 t_struct* xs = (*f_iter)->get_xceptions();
1163 const std::vector<t_field*>& xceptions = xs->get_members();
1164 vector<t_field*>::const_iterator x_iter;
1165 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1166 f_service_ <<
Roger Meierda6e6ae2011-03-15 09:55:33 +00001167 indent() << "if (null !== result." << (*x_iter)->get_name() << ") {" << endl <<
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001168 indent() << " " << render_recv_throw("result." + (*x_iter)->get_name()) << endl <<
T Jake Luciani322caa22010-02-15 03:24:55 +00001169 indent() << "}" << endl;
1170 }
1171
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001172 // Careful, only return result if not a void function
1173 if (!(*f_iter)->get_returntype()->is_void()) {
T Jake Luciani322caa22010-02-15 03:24:55 +00001174 f_service_ <<
Roger Meierda6e6ae2011-03-15 09:55:33 +00001175 indent() << "if (null !== result.success) {" << endl <<
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001176 indent() << " " << render_recv_return("result.success") << endl <<
1177 indent() << "}" << endl;
1178 f_service_ <<
Roger Meier8430d502011-03-11 12:38:54 +00001179 indent() << render_recv_throw("'" + (*f_iter)->get_name() + " failed: unknown result'") << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001180 } else {
1181 if (gen_node_) {
1182 indent(f_service_) << "callback(null)" << endl;
1183 } else {
Roger Meier8430d502011-03-11 12:38:54 +00001184 indent(f_service_) << "return;" << endl;
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001185 }
T Jake Luciani322caa22010-02-15 03:24:55 +00001186 }
1187
1188 // Close function
1189 indent_down();
Roger Meier8430d502011-03-11 12:38:54 +00001190 f_service_ << "};"<<endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001191
1192 }
1193 }
1194
1195}
1196
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001197std::string t_js_generator::render_recv_throw(std::string var) {
1198 if (gen_node_) {
1199 return "return callback(" + var + ");";
1200 } else {
Roger Meier8430d502011-03-11 12:38:54 +00001201 return "throw " + var + ";";
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001202 }
1203}
1204
1205std::string t_js_generator::render_recv_return(std::string var) {
1206 if (gen_node_) {
1207 return "return callback(null, " + var + ");";
1208 } else {
Roger Meier8430d502011-03-11 12:38:54 +00001209 return "return " + var + ";";
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001210 }
1211}
1212
T Jake Luciani322caa22010-02-15 03:24:55 +00001213/**
1214 * Deserializes a field of any type.
1215 */
1216void t_js_generator::generate_deserialize_field(ofstream &out,
1217 t_field* tfield,
1218 string prefix,
1219 bool inclass) {
Roger Meier3b771a12010-11-17 22:11:26 +00001220 (void) inclass;
T Jake Luciani322caa22010-02-15 03:24:55 +00001221 t_type* type = get_true_type(tfield->get_type());
1222
1223 if (type->is_void()) {
1224 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1225 prefix + tfield->get_name();
1226 }
1227
1228 string name = prefix+tfield->get_name();
1229
1230 if (type->is_struct() || type->is_xception()) {
1231 generate_deserialize_struct(out,
1232 (t_struct*)type,
1233 name);
1234 } else if (type->is_container()) {
1235 generate_deserialize_container(out, type, name);
1236 } else if (type->is_base_type() || type->is_enum()) {
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001237 indent(out) << name << " = input.";
T Jake Luciani322caa22010-02-15 03:24:55 +00001238
1239 if (type->is_base_type()) {
1240 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1241 switch (tbase) {
1242 case t_base_type::TYPE_VOID:
1243 throw "compiler error: cannot serialize void field in a struct: " +
1244 name;
1245 break;
1246 case t_base_type::TYPE_STRING:
1247 out << "readString()";
1248 break;
1249 case t_base_type::TYPE_BOOL:
1250 out << "readBool()";
1251 break;
1252 case t_base_type::TYPE_BYTE:
1253 out << "readByte()";
1254 break;
1255 case t_base_type::TYPE_I16:
1256 out << "readI16()";
1257 break;
1258 case t_base_type::TYPE_I32:
1259 out << "readI32()";
1260 break;
1261 case t_base_type::TYPE_I64:
1262 out << "readI64()";
1263 break;
1264 case t_base_type::TYPE_DOUBLE:
1265 out << "readDouble()";
1266 break;
1267 default:
1268 throw "compiler error: no JS name for base type " + t_base_type::t_base_name(tbase);
1269 }
1270 } else if (type->is_enum()) {
1271 out << "readI32()";
1272 }
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001273
1274 if (!gen_node_) {
1275 out << ".value";
1276 }
1277
Roger Meier8430d502011-03-11 12:38:54 +00001278 out << ";" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001279 } else {
1280 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
1281 tfield->get_name().c_str(), type->get_name().c_str());
1282 }
1283}
1284
1285/**
1286 * Generates an unserializer for a variable. This makes two key assumptions,
1287 * first that there is a const char* variable named data that points to the
1288 * buffer for deserialization, and that there is a variable protocol which
1289 * is a reference to a TProtocol serialization object.
1290 */
1291void t_js_generator::generate_deserialize_struct(ofstream &out,
1292 t_struct* tstruct,
1293 string prefix) {
1294 out <<
Roger Meier8430d502011-03-11 12:38:54 +00001295 indent() << prefix << " = new " << js_type_namespace(tstruct->get_program())<<tstruct->get_name() << "();" << endl <<
1296 indent() << prefix << ".read(input);" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001297
1298}
1299
1300void t_js_generator::generate_deserialize_container(ofstream &out,
1301 t_type* ttype,
1302 string prefix) {
T Jake Luciani322caa22010-02-15 03:24:55 +00001303 string size = tmp("_size");
1304 string ktype = tmp("_ktype");
1305 string vtype = tmp("_vtype");
1306 string etype = tmp("_etype");
Roger Meierda6e6ae2011-03-15 09:55:33 +00001307 string rtmp3 = tmp("_rtmp3");
T Jake Luciani322caa22010-02-15 03:24:55 +00001308
1309 t_field fsize(g_type_i32, size);
1310 t_field fktype(g_type_byte, ktype);
1311 t_field fvtype(g_type_byte, vtype);
1312 t_field fetype(g_type_byte, etype);
1313
Roger Meier8430d502011-03-11 12:38:54 +00001314 out << indent() << "var " << size << " = 0;" << endl;
Roger Meierda6e6ae2011-03-15 09:55:33 +00001315 out << indent() << "var " << rtmp3 << ";" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001316
1317
1318 // Declare variables, read header
1319 if (ttype->is_map()) {
1320 out <<
Roger Meier8430d502011-03-11 12:38:54 +00001321 indent() << prefix << " = {};" << endl <<
1322 indent() << "var " << ktype << " = 0;" << endl <<
1323 indent() << "var " << vtype << " = 0;" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001324
Roger Meierda6e6ae2011-03-15 09:55:33 +00001325 out << indent() << rtmp3 << " = input.readMapBegin();" << endl;
1326 out << indent() << ktype << " = " << rtmp3 << ".ktype;" << endl;
1327 out << indent() << vtype << " = " << rtmp3 << ".vtype;" << endl;
1328 out << indent() << size << " = " << rtmp3 << ".size;" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001329
1330
1331 } else if (ttype->is_set()) {
1332
1333 out <<
Roger Meier8430d502011-03-11 12:38:54 +00001334 indent() << prefix << " = [];" << endl <<
1335 indent() << "var " << etype << " = 0;" << endl <<
Roger Meierda6e6ae2011-03-15 09:55:33 +00001336 indent() << rtmp3 << " = input.readSetBegin();" << endl <<
1337 indent() << etype << " = " << rtmp3 << ".etype;"<<endl<<
1338 indent() << size << " = " << rtmp3 << ".size;"<<endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001339
1340 } else if (ttype->is_list()) {
1341
1342 out <<
Roger Meier8430d502011-03-11 12:38:54 +00001343 indent() << prefix << " = [];" << endl <<
1344 indent() << "var " << etype << " = 0;" << endl <<
Roger Meierda6e6ae2011-03-15 09:55:33 +00001345 indent() << rtmp3 << " = input.readListBegin();" << endl <<
1346 indent() << etype << " = " << rtmp3 << ".etype;"<<endl<<
1347 indent() << size << " = " << rtmp3 << ".size;"<<endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001348 }
1349
1350 // For loop iterates over elements
1351 string i = tmp("_i");
1352 indent(out) <<
1353 "for (var " <<
1354 i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
1355
1356 scope_up(out);
1357
1358 if (ttype->is_map()) {
1359 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
1360 } else if (ttype->is_set()) {
1361 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
1362 } else if (ttype->is_list()) {
1363 generate_deserialize_list_element(out, (t_list*)ttype, prefix);
1364 }
1365
1366 scope_down(out);
1367
1368
1369 // Read container end
1370 if (ttype->is_map()) {
Roger Meier8430d502011-03-11 12:38:54 +00001371 indent(out) << "input.readMapEnd();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001372 } else if (ttype->is_set()) {
Roger Meier8430d502011-03-11 12:38:54 +00001373 indent(out) << "input.readSetEnd();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001374 } else if (ttype->is_list()) {
Roger Meier8430d502011-03-11 12:38:54 +00001375 indent(out) << "input.readListEnd();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001376 }
T Jake Luciani322caa22010-02-15 03:24:55 +00001377}
1378
1379
1380/**
1381 * Generates code to deserialize a map
1382 */
1383void t_js_generator::generate_deserialize_map_element(ofstream &out,
1384 t_map* tmap,
1385 string prefix) {
1386 string key = tmp("key");
1387 string val = tmp("val");
1388 t_field fkey(tmap->get_key_type(), key);
1389 t_field fval(tmap->get_val_type(), val);
1390
1391 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001392 declare_field(&fkey, false, false) << ";" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001393 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001394 declare_field(&fval, false, false) << ";" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001395
1396 generate_deserialize_field(out, &fkey);
1397 generate_deserialize_field(out, &fval);
1398
1399 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001400 prefix << "[" << key << "] = " << val << ";" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001401}
1402
1403void t_js_generator::generate_deserialize_set_element(ofstream &out,
1404 t_set* tset,
1405 string prefix) {
1406 string elem = tmp("elem");
1407 t_field felem(tset->get_elem_type(), elem);
1408
1409 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001410 "var " << elem << " = null;" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001411
1412 generate_deserialize_field(out, &felem);
1413
1414 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001415 prefix << ".push(" << elem << ");" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001416}
1417
1418void t_js_generator::generate_deserialize_list_element(ofstream &out,
1419 t_list* tlist,
1420 string prefix) {
1421 string elem = tmp("elem");
1422 t_field felem(tlist->get_elem_type(), elem);
1423
1424 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001425 "var " << elem << " = null;" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001426
1427 generate_deserialize_field(out, &felem);
1428
1429 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001430 prefix << ".push(" << elem << ");" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001431}
1432
1433
1434/**
1435 * Serializes a field of any type.
1436 *
1437 * @param tfield The field to serialize
1438 * @param prefix Name to prepend to field name
1439 */
1440void t_js_generator::generate_serialize_field(ofstream &out,
1441 t_field* tfield,
1442 string prefix) {
1443 t_type* type = get_true_type(tfield->get_type());
1444
1445 // Do nothing for void types
1446 if (type->is_void()) {
1447 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
1448 prefix + tfield->get_name();
1449 }
1450
1451 if (type->is_struct() || type->is_xception()) {
1452 generate_serialize_struct(out,
1453 (t_struct*)type,
1454 prefix +tfield->get_name() );
1455 } else if (type->is_container()) {
1456 generate_serialize_container(out,
1457 type,
1458 prefix + tfield->get_name());
1459 } else if (type->is_base_type() || type->is_enum()) {
1460
1461 string name = tfield->get_name();
1462
1463 //Hack for when prefix is defined (always a hash ref)
1464 if(!prefix.empty())
1465 name = prefix + tfield->get_name();
1466
1467 indent(out) << "output.";
1468
1469 if (type->is_base_type()) {
1470 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1471 switch (tbase) {
1472 case t_base_type::TYPE_VOID:
1473 throw
1474 "compiler error: cannot serialize void field in a struct: " + name;
1475 break;
1476 case t_base_type::TYPE_STRING:
1477 out << "writeString(" << name << ")";
1478 break;
1479 case t_base_type::TYPE_BOOL:
1480 out << "writeBool(" << name << ")";
1481 break;
1482 case t_base_type::TYPE_BYTE:
1483 out << "writeByte(" << name << ")";
1484 break;
1485 case t_base_type::TYPE_I16:
1486 out << "writeI16(" << name << ")";
1487 break;
1488 case t_base_type::TYPE_I32:
1489 out << "writeI32(" << name << ")";
1490 break;
1491 case t_base_type::TYPE_I64:
1492 out << "writeI64(" << name << ")";
1493 break;
1494 case t_base_type::TYPE_DOUBLE:
1495 out << "writeDouble(" << name << ")";
1496 break;
1497 default:
1498 throw "compiler error: no JS name for base type " + t_base_type::t_base_name(tbase);
1499 }
1500 } else if (type->is_enum()) {
1501 out << "writeI32(" << name << ")";
1502 }
Roger Meier8430d502011-03-11 12:38:54 +00001503 out << ";" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001504
1505 } else {
1506 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
1507 prefix.c_str(),
1508 tfield->get_name().c_str(),
1509 type->get_name().c_str());
1510 }
1511}
1512
1513/**
1514 * Serializes all the members of a struct.
1515 *
1516 * @param tstruct The struct to serialize
1517 * @param prefix String prefix to attach to all fields
1518 */
1519void t_js_generator::generate_serialize_struct(ofstream &out,
1520 t_struct* tstruct,
1521 string prefix) {
Roger Meier3b771a12010-11-17 22:11:26 +00001522 (void) tstruct;
Roger Meier8430d502011-03-11 12:38:54 +00001523 indent(out) << prefix << ".write(output);" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001524}
1525
1526/**
1527 * Writes out a container
1528 */
1529void t_js_generator::generate_serialize_container(ofstream &out,
1530 t_type* ttype,
1531 string prefix) {
T Jake Luciani322caa22010-02-15 03:24:55 +00001532 if (ttype->is_map()) {
1533 indent(out) <<
1534 "output.writeMapBegin(" <<
1535 type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
1536 type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
Roger Meier8430d502011-03-11 12:38:54 +00001537 "Thrift.objectLength(" << prefix << "));" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001538 } else if (ttype->is_set()) {
1539 indent(out) <<
1540 "output.writeSetBegin(" <<
1541 type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
Roger Meier8430d502011-03-11 12:38:54 +00001542 prefix << ".length);" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001543
1544 } else if (ttype->is_list()) {
1545
1546 indent(out) <<
1547 "output.writeListBegin(" <<
1548 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
Roger Meier8430d502011-03-11 12:38:54 +00001549 prefix << ".length);" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001550
1551 }
1552
T Jake Luciani322caa22010-02-15 03:24:55 +00001553 if (ttype->is_map()) {
1554 string kiter = tmp("kiter");
1555 string viter = tmp("viter");
Roger Meier8430d502011-03-11 12:38:54 +00001556 indent(out) << "for (var "<<kiter<<" in "<<prefix<<")" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001557 scope_up(out);
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001558 indent(out) << "if ("<<prefix<<".hasOwnProperty("<<kiter<<"))" <<endl;
1559 scope_up(out);
Roger Meier8430d502011-03-11 12:38:54 +00001560 indent(out) << "var "<<viter<<" = "<<prefix<<"["<<kiter<<"];"<<endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001561 generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
1562 scope_down(out);
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001563 scope_down(out);
T Jake Luciani322caa22010-02-15 03:24:55 +00001564
1565
1566 } else if (ttype->is_set()) {
1567 string iter = tmp("iter");
1568 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001569 "for (var "<<iter<<" in " << prefix << ")" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001570 scope_up(out);
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001571 indent(out) << "if ("<<prefix<<".hasOwnProperty("<<iter<<"))" <<endl;
1572 scope_up(out);
Roger Meier8430d502011-03-11 12:38:54 +00001573 indent(out) << iter << " = " << prefix << "[" << iter << "];"<< endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001574 generate_serialize_set_element(out, (t_set*)ttype, iter);
1575 scope_down(out);
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001576 scope_down(out);
T Jake Luciani322caa22010-02-15 03:24:55 +00001577
1578
1579 } else if (ttype->is_list()) {
1580 string iter = tmp("iter");
1581 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001582 "for (var "<<iter<<" in "<< prefix << ")" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001583 scope_up(out);
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001584 indent(out) << "if ("<<prefix<<".hasOwnProperty("<<iter<<"))" <<endl;
1585 scope_up(out);
Roger Meier8430d502011-03-11 12:38:54 +00001586 indent(out) << iter << " = " << prefix << "[" << iter << "];"<< endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001587 generate_serialize_list_element(out, (t_list*)ttype, iter);
1588 scope_down(out);
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001589 scope_down(out);
T Jake Luciani322caa22010-02-15 03:24:55 +00001590 }
1591
T Jake Luciani322caa22010-02-15 03:24:55 +00001592 if (ttype->is_map()) {
1593 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001594 "output.writeMapEnd();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001595 } else if (ttype->is_set()) {
1596 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001597 "output.writeSetEnd();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001598 } else if (ttype->is_list()) {
1599 indent(out) <<
Roger Meier8430d502011-03-11 12:38:54 +00001600 "output.writeListEnd();" << endl;
T Jake Luciani322caa22010-02-15 03:24:55 +00001601 }
T Jake Luciani322caa22010-02-15 03:24:55 +00001602}
1603
1604/**
1605 * Serializes the members of a map.
1606 *
1607 */
1608void t_js_generator::generate_serialize_map_element(ofstream &out,
1609 t_map* tmap,
1610 string kiter,
1611 string viter) {
1612 t_field kfield(tmap->get_key_type(), kiter);
1613 generate_serialize_field(out, &kfield);
1614
1615 t_field vfield(tmap->get_val_type(), viter);
1616 generate_serialize_field(out, &vfield);
1617}
1618
1619/**
1620 * Serializes the members of a set.
1621 */
1622void t_js_generator::generate_serialize_set_element(ofstream &out,
1623 t_set* tset,
1624 string iter) {
1625 t_field efield(tset->get_elem_type(), iter);
1626 generate_serialize_field(out, &efield);
1627}
1628
1629/**
1630 * Serializes the members of a list.
1631 */
1632void t_js_generator::generate_serialize_list_element(ofstream &out,
1633 t_list* tlist,
1634 string iter) {
1635 t_field efield(tlist->get_elem_type(), iter);
1636 generate_serialize_field(out, &efield);
1637}
1638
1639/**
1640 * Declares a field, which may include initialization as necessary.
1641 *
1642 * @param ttype The type
1643 */
1644string t_js_generator::declare_field(t_field* tfield, bool init, bool obj) {
1645 string result = "this." + tfield->get_name();
1646
1647 if(!obj){
Roger Meier5860f882011-05-22 09:59:34 +00001648 result = "var " + tfield->get_name();
T Jake Luciani322caa22010-02-15 03:24:55 +00001649 }
1650
1651 if (init) {
1652 t_type* type = get_true_type(tfield->get_type());
1653 if (type->is_base_type()) {
1654 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1655 switch (tbase) {
1656 case t_base_type::TYPE_VOID:
1657 break;
1658 case t_base_type::TYPE_STRING:
T Jake Luciani322caa22010-02-15 03:24:55 +00001659 case t_base_type::TYPE_BOOL:
T Jake Luciani322caa22010-02-15 03:24:55 +00001660 case t_base_type::TYPE_BYTE:
1661 case t_base_type::TYPE_I16:
1662 case t_base_type::TYPE_I32:
1663 case t_base_type::TYPE_I64:
T Jake Luciani322caa22010-02-15 03:24:55 +00001664 case t_base_type::TYPE_DOUBLE:
Roger Meier421dfbe2010-10-15 19:12:44 +00001665 result += " = null";
T Jake Luciani322caa22010-02-15 03:24:55 +00001666 break;
1667 default:
1668 throw "compiler error: no JS initializer for base type " + t_base_type::t_base_name(tbase);
1669 }
1670 } else if (type->is_enum()) {
Roger Meier421dfbe2010-10-15 19:12:44 +00001671 result += " = null";
T Jake Luciani322caa22010-02-15 03:24:55 +00001672 } else if (type->is_map()){
Roger Meier421dfbe2010-10-15 19:12:44 +00001673 result += " = null";
T Jake Luciani322caa22010-02-15 03:24:55 +00001674 } else if (type->is_container()) {
Roger Meier421dfbe2010-10-15 19:12:44 +00001675 result += " = null";
T Jake Luciani322caa22010-02-15 03:24:55 +00001676 } else if (type->is_struct() || type->is_xception()) {
1677 if (obj) {
Roger Meierdd0c3282011-02-16 19:25:05 +00001678 result += " = new " +js_type_namespace(type->get_program()) + type->get_name() + "()";
T Jake Luciani322caa22010-02-15 03:24:55 +00001679 } else {
1680 result += " = null";
1681 }
1682 }
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001683 } else {
1684 result += " = null";
T Jake Luciani322caa22010-02-15 03:24:55 +00001685 }
1686 return result;
1687}
1688
1689/**
1690 * Renders a function signature of the form 'type name(args)'
1691 *
1692 * @param tfunction Function definition
1693 * @return String of rendered function definition
1694 */
1695string t_js_generator::function_signature(t_function* tfunction,
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001696 string prefix,
1697 bool include_callback) {
T Jake Luciani322caa22010-02-15 03:24:55 +00001698
1699 string str;
1700
1701 str = prefix + tfunction->get_name() + " = function(";
1702
Roger Meier08b30992011-04-06 21:30:53 +00001703 str += argument_list(tfunction->get_arglist(), include_callback);
T Jake Luciani322caa22010-02-15 03:24:55 +00001704
1705 str += ")";
1706 return str;
1707}
1708
1709/**
1710 * Renders a field list
1711 */
Roger Meier08b30992011-04-06 21:30:53 +00001712string t_js_generator::argument_list(t_struct* tstruct,
1713 bool include_callback) {
T Jake Luciani322caa22010-02-15 03:24:55 +00001714 string result = "";
1715
1716 const vector<t_field*>& fields = tstruct->get_members();
1717 vector<t_field*>::const_iterator f_iter;
1718 bool first = true;
1719 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1720 if (first) {
1721 first = false;
1722 } else {
1723 result += ", ";
1724 }
1725 result += (*f_iter)->get_name();
1726 }
Roger Meier08b30992011-04-06 21:30:53 +00001727
1728 if (include_callback) {
1729 if (!fields.empty()) {
1730 result += ", ";
1731 }
1732 result += "callback";
1733 }
1734
T Jake Luciani322caa22010-02-15 03:24:55 +00001735 return result;
1736}
1737
1738/**
1739 * Converts the parse type to a C++ enum string for the given type.
1740 */
1741string t_js_generator ::type_to_enum(t_type* type) {
1742 type = get_true_type(type);
1743
1744 if (type->is_base_type()) {
1745 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1746 switch (tbase) {
1747 case t_base_type::TYPE_VOID:
1748 throw "NO T_VOID CONSTRUCT";
1749 case t_base_type::TYPE_STRING:
1750 return "Thrift.Type.STRING";
1751 case t_base_type::TYPE_BOOL:
1752 return "Thrift.Type.BOOL";
1753 case t_base_type::TYPE_BYTE:
1754 return "Thrift.Type.BYTE";
1755 case t_base_type::TYPE_I16:
1756 return "Thrift.Type.I16";
1757 case t_base_type::TYPE_I32:
1758 return "Thrift.Type.I32";
1759 case t_base_type::TYPE_I64:
1760 return "Thrift.Type.I64";
1761 case t_base_type::TYPE_DOUBLE:
1762 return "Thrift.Type.DOUBLE";
1763 }
1764 } else if (type->is_enum()) {
1765 return "Thrift.Type.I32";
1766 } else if (type->is_struct() || type->is_xception()) {
1767 return "Thrift.Type.STRUCT";
1768 } else if (type->is_map()) {
1769 return "Thrift.Type.MAP";
1770 } else if (type->is_set()) {
1771 return "Thrift.Type.SET";
1772 } else if (type->is_list()) {
1773 return "Thrift.Type.LIST";
1774 }
1775
1776 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
1777}
1778
1779
Roger Meier08b30992011-04-06 21:30:53 +00001780THRIFT_REGISTER_GENERATOR(js, "Javascript",
1781" jquery: Generate jQuery compatible code.\n"
T Jake Luciani0c124bb2011-01-08 03:49:16 +00001782" node: Generate node.js compatible code.\n")
Roger Meier0069cc42010-10-13 18:10:18 +00001783