From: Christopher Piro Date: Wed, 25 Jul 2007 22:41:00 +0000 (+0000) Subject: [thrift] maps, lists, sets, and service inheritance for Erlang X-Git-Tag: 0.2.0~1297 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=5f5fdf3a20f2459eabbee771e6eff4159c6f2bca;p=common%2Fthrift.git [thrift] maps, lists, sets, and service inheritance for Erlang Reviewed by: cpiro Test Plan: tested wit tutorial/tutorial.thrift Revert Plan: ok git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665175 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/compiler/cpp/src/generate/t_erl_generator.cc b/compiler/cpp/src/generate/t_erl_generator.cc index ba662479..5779078b 100644 --- a/compiler/cpp/src/generate/t_erl_generator.cc +++ b/compiler/cpp/src/generate/t_erl_generator.cc @@ -205,13 +205,15 @@ string t_erl_generator::render_const_value(t_type* type, t_const_value* value) { } } else if (type->is_enum()) { indent(out) << value->get_integer(); - } else if (type->is_struct() || type->is_xception()) { // TODO - out << type->get_name() << "({" << endl; - indent_up(); + + } else if (type->is_struct() || type->is_xception()) { + out << "#" << type->get_name() << "{"; const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; + + bool first = true; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = NULL; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { @@ -222,59 +224,74 @@ string t_erl_generator::render_const_value(t_type* type, t_const_value* value) { if (field_type == NULL) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } - out << indent(); - out << render_const_value(g_type_string, v_iter->first); - out << " => "; + + if (first) { + first = false; + } else { + out << ","; + } + out << v_iter->first->get_string(); + out << " = "; out << render_const_value(field_type, v_iter->second); - out << "," << endl; } indent_down(); - indent(out) << "})"; - } else if (type->is_map()) { // TODO + indent(out) << "}"; + + } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); - out << "{" << endl; - indent_up(); const map& val = value->get_map(); map::const_iterator v_iter; + + bool first = true; + out << "dict:from_list(["; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { - out << indent(); - out << render_const_value(ktype, v_iter->first); - out << " => "; - out << render_const_value(vtype, v_iter->second); - out << "," << endl; + if (first) { + first=false; + } else { + out << ","; + } + out << "(" + << render_const_value(ktype, v_iter->first) << "," + << render_const_value(vtype, v_iter->second) << ")"; } - indent_down(); - indent(out) << "}"; - } else if (type->is_list() || type->is_set()) { // TODO + out << "])"; + + } else if (type->is_set()) { t_type* etype; - if (type->is_list()) { - etype = ((t_list*)type)->get_elem_type(); - } else { - etype = ((t_set*)type)->get_elem_type(); - } - if (type->is_set()) { - out << "{"; - } else { - out << "[" << endl; - } - indent_up(); + etype = ((t_set*)type)->get_elem_type(); + + bool first = true; const vector& val = value->get_list(); vector::const_iterator v_iter; + out << "sets:from_list(["; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { - out << indent(); - out << render_const_value(etype, *v_iter); - if (type->is_set()) { - out << " => true"; + if (first) { + first=false; + } else { + out << ","; } - out << "," << endl; + out << "(" << render_const_value(etype, *v_iter) << ",true)"; } - indent_down(); - if (type->is_set()) { - indent(out) << "}"; - } else { - indent(out) << "]"; + out << "])"; + + } else if (type->is_list()) { + t_type* etype; + etype = ((t_list*)type)->get_elem_type(); + out << "["; + + bool first = true; + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + if (first) { + first=false; + } else { + out << ","; + } + out << render_const_value(etype, *v_iter); } + out << "]"; } return out.str(); } @@ -364,7 +381,7 @@ void t_erl_generator::generate_erl_struct_reader(ostream& out, string name = type_name(tstruct) + "_read"; - if(out == f_types_) { // OH HAI MR. HORRIBLE + if (out == f_types_) { // OH HAI MR. HORRIBLE export_types_string(name, 1); } else { export_string(name, 1); @@ -379,11 +396,10 @@ void t_erl_generator::generate_erl_struct_reader(ostream& out, // empty struct out << "#" << type_name(tstruct) << "{}"; - out << ")," << endl << indent() << "?R0(Iprot, readStructEnd)," << endl << indent() << "Str." << endl; - + indent_down(); indent(out) << @@ -439,7 +455,7 @@ void t_erl_generator::generate_erl_struct_writer(ostream& out, string fname = type_name(tstruct) + "_write"; - if(out == f_types_) { // OH HAI MR. HORRIBLE + if (out == f_types_) { // OH HAI MR. HORRIBLE export_types_string(fname, 2); } else { export_string(fname, 2); @@ -453,7 +469,6 @@ void t_erl_generator::generate_erl_struct_writer(ostream& out, indent() << "?R1(Oprot, writeStructBegin, \"" << name << "\")," << endl; string prefix = string("Str#") + type_name(tstruct) + "."; - for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { // Write field header indent(out) << @@ -746,7 +761,7 @@ void t_erl_generator::generate_service_client(t_service* tservice) { indent() << " X = tApplicationException:new()," << endl << indent() << " tApplicationException:read(X, Iprot)," << endl << indent() << " ?R0(Iprot, readMessageEnd), " << endl << - indent() << " {error, X};" << endl << + indent() << " throw(X);" << endl << indent() << " true ->" << endl << indent() << " Result = " << resultname << "_read(Iprot)," << endl << indent() << " ?R0(Iprot, readMessageEnd)," << endl << @@ -761,7 +776,7 @@ void t_erl_generator::generate_service_client(t_service* tservice) { if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << indent() << " " << result << "success /= nil ->" << endl << - indent() << " {ok, " << result << "success};" << endl; + indent() << " " << result << "success;" << endl; } t_struct* xs = (*f_iter)->get_xceptions(); // TODO(cpiro) @@ -770,19 +785,18 @@ void t_erl_generator::generate_service_client(t_service* tservice) { for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << indent() << " " << result << (*x_iter)->get_name() << " /= nil -> " << endl << - indent() << " {error, " << result << (*x_iter)->get_name() << "};" << endl; + indent() << " throw(" << result << (*x_iter)->get_name() << ");" << endl; } // Careful, only return _result if not a void function if ((*f_iter)->get_returntype()->is_void()) { - indent(f_service_) << - indent() << " Result," << endl << - indent() << " true -> {ok, nil}" << endl << + f_service_ << + indent() << " true -> nil" << endl << indent() << " end" << endl; } else { f_service_ << indent() << " true -> " << endl << - indent() << " {error, tApplicationException:new(?tApplicationException_MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\")}" << endl << + indent() << " throw(tApplicationException:new(?tApplicationException_MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\"))" << endl << indent() << " end" << endl; } @@ -847,6 +861,7 @@ void t_erl_generator::generate_service_server(t_service* tservice) { */ export_string("process", 3); + export_string("proc", 6); // Generate the server implementation indent(f_service_) << @@ -854,7 +869,13 @@ void t_erl_generator::generate_service_server(t_service* tservice) { indent_up(); f_service_ << - indent() << "{ Name, _Type, Seqid } = ?R0(Iprot, readMessageBegin)," << endl; + indent() << "{ Name, _Type, Seqid } = ?R0(Iprot, readMessageBegin)," << endl << + indent() << "proc(Name, _Type, Seqid, HandlerModule, Iprot, Oprot)." << endl; + + indent_down(); + indent(f_service_) << + "proc(Name, _Type, Seqid, HandlerModule, Iprot, Oprot) ->" << endl; + indent_up(); // TODO(mcslee): validate message @@ -866,35 +887,24 @@ void t_erl_generator::generate_service_server(t_service* tservice) { for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_service_ << indent() << " \"" << (*f_iter)->get_name() << "\" -> process_" << (*f_iter)->get_name() << "(HandlerModule, Seqid, Iprot, Oprot);" << endl; - } - - indent(f_service_) << " %% TODO(cpiro): pass to super" << endl; - indent(f_service_) << " _UnknownFunction ->" << endl << - indent() << " ?R1(Iprot, skip, ?tType_STRUCT)," << endl << - indent() << " ?R0(Iprot, readMessageEnd)," << endl << - indent() << " X = tApplicationException:new(?tApplicationException_UNKNOWN_METHOD, \"Unknown function \" ++ Name)," << endl << - indent() << " ?R3(Oprot, writeMessageBegin, Name, ?tMessageType_EXCEPTION, Seqid)," << endl << - indent() << " tApplicationException:write(X, Oprot)," << endl << - indent() << " ?R0(Oprot, writeMessageEnd)," << endl << - indent() << " Trans = ?R1(Oprot, get, trans)," << endl << - indent() << " ?R0(Trans, effectful_flush)," << endl << - indent() << " {error, X} % what's the retval in this case?" << endl << - indent() << "end." << endl; + } - /* - indent() << "if (@processMap.has_key?(name))" << endl << - indent() << " @processMap[name].call(seqid, iprot, oprot)" << endl << - indent() << "else" << endl << - indent() << " iprot.skip(TType::STRUCT)" << endl << - indent() << " iprot.readMessageEnd()" << endl << - indent() << " x = TApplicationException.new(TApplicationException::UNKNOWN_METHOD, 'Unknown function '+name)" << endl << - indent() << " oprot.writeMessageBegin(name, TMessageType::EXCEPTION, seqid)" << endl << - indent() << " x.write(oprot)" << endl << - indent() << " oprot.writeMessageEnd()" << endl << - indent() << " oprot.trans.flush()" << endl << - indent() << " return" << endl << - indent() << "end" << endl; - */ + indent(f_service_) << " _ -> % unknown function" << endl; + if (tservice->get_extends() != NULL) { + indent(f_service_) << " " << extends << ":proc(Name,_Type,Seqid,HandlerModule, Iprot, Oprot)" << endl; + } else { + f_service_ << + indent() << " ?R1(Iprot, skip, ?tType_STRUCT)," << endl << + indent() << " ?R0(Iprot, readMessageEnd)," << endl << + indent() << " X = tApplicationException:new(?tApplicationException_UNKNOWN_METHOD, \"Unknown function \" ++ Name)," << endl << + indent() << " ?R3(Oprot, writeMessageBegin, Name, ?tMessageType_EXCEPTION, Seqid)," << endl << + indent() << " tApplicationException:write(X, Oprot)," << endl << + indent() << " ?R0(Oprot, writeMessageEnd)," << endl << + indent() << " Trans = ?R1(Oprot, get, trans)," << endl << + indent() << " ?R0(Trans, effectful_flush)," << endl << + indent() << " {error, X} % what's the retval in this case?" << endl; + } + f_service_ << indent() << "end." << endl; indent_down(); @@ -945,21 +955,24 @@ void t_erl_generator::generate_process_function(t_service* tservice, if (!tfunction->is_async()) { } - // Try block for a function with exceptions - // if (xceptions.size() > 0) { - // f_service_ << - // indent() << "try" << endl; - // indent_up(); - // } - // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; + indent(f_service_) << "Result = "; + if (xceptions.size() > 0) { + f_service_ << "try" << endl; + } else { + f_service_ << "begin" << endl; + } + indent_up(); + f_service_ << indent(); - f_service_ << - "Retval = HandlerModule:" << tfunction->get_name() << "("; + if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) { + f_service_<< "Res = "; + } + f_service_ << "HandlerModule:" << tfunction->get_name() << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { @@ -971,33 +984,24 @@ void t_erl_generator::generate_process_function(t_service* tservice, f_service_ << "_Args#" << tfunction->get_name() << "_args." << (*f_iter)->get_name(); } f_service_ << ")," << endl; - - indent(f_service_) << "Result = case Retval of" << endl; - indent_up(); - indent(f_service_) << "{ok, Value} ->" << endl; - indent_up(); - indent(f_service_) << "Value, % suppress unused warnings" << endl; - if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) { - indent(f_service_) << "#" << resultname << "{success=Value};" << endl; + indent(f_service_) << "#" << resultname << "{success=Res}" << endl; } else{ - indent(f_service_) << "#" << resultname << "{};" << endl; + indent(f_service_) << "#" << resultname << "{}" << endl; } indent_down(); - if (!tfunction->is_async() && xceptions.size() > 0) { + indent(f_service_) << "catch" << endl; + indent_up(); for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { - indent(f_service_) << "{error, E} when is_record(E, " << uncapitalize((*x_iter)->get_type()->get_name()) << ") ->" << endl; + indent(f_service_) << "E when is_record(E," << uncapitalize((*x_iter)->get_type()->get_name()) << ") ->" << endl; indent_up(); - indent(f_service_) << "#" << resultname << "{" << (*x_iter)->get_name() << " = E};" << endl; - indent_down(); } + indent(f_service_) << "dummy -> dummy % TODO: only for the semicolon's sake" << endl; + indent_down(); } - - indent(f_service_) << "dummy -> dummy % TODO: only for the semicolon's sake" << endl; - indent_down(); indent(f_service_) << "end," << endl; if (tfunction->is_async()) { @@ -1101,7 +1105,7 @@ void t_erl_generator::generate_deserialize_field(ostream &out, * Serialize a container by writing out the header followed by * data and then a footer. */ -void t_erl_generator::generate_deserialize_container(ostream &out, // TODO +void t_erl_generator::generate_deserialize_container(ostream &out, t_type* ttype, string prefix) { string size = tmp("_size"); @@ -1116,50 +1120,66 @@ void t_erl_generator::generate_deserialize_container(ostream &out, // TODO // Declare variables, read header if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + string key = tmp("_key"); + string val = tmp("_val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + out << - indent() << prefix << " = {}" << endl << - indent() << "(" << ktype << ", " << vtype << ", " << size << " ) = iprot.readMapBegin() " << endl; + indent() << "{" << ktype << ", " << vtype << ", " << size << " } = ?R0(Iprot,readMapBegin)," << endl; + out << + indent() << prefix << " = dict:from_list(thrift_utils:tabulate(" << size << "," << endl; + indent_up(); + out << indent() << "fun (_) ->" << endl; + indent_up(); + generate_deserialize_field(out, &fkey,key); + generate_deserialize_field(out, &fval,val); + out << indent() << "{" << key << "," << val << "}" << endl; + indent_down(); + out << indent() << "end))," << endl; + indent_down(); + out << indent() << "?R0(Iprot,readMapEnd)," << endl; + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); out << - indent() << prefix << " = {}" << endl << - indent() << "(" << etype << ", " << size << ") = iprot.readSetBegin()" << endl; - } else if (ttype->is_list()) { + indent() << "{" << etype << ", " << size << "} = ?R0(Iprot,readSetBegin)," << endl; out << - indent() << prefix << " = []" << endl << - indent() << "(" << etype << ", " << size << ") = iprot.readListBegin()" << endl; - } - - // For loop iterates over elements - string i = tmp("_i"); - indent(out) << - "for " << i << " in (1.." << size << ")" << endl; - + indent() << prefix << " = sets:from_list(thrift_utils:tabulate(" << size << "," << endl; indent_up(); - - if (ttype->is_map()) { - generate_deserialize_map_element(out, (t_map*)ttype, prefix); - } else if (ttype->is_set()) { - generate_deserialize_set_element(out, (t_set*)ttype, prefix); - } else if (ttype->is_list()) { - generate_deserialize_list_element(out, (t_list*)ttype, prefix); - } - + out << indent() << "fun (_) ->" << endl; + indent_up(); + generate_deserialize_field(out,&felem,elem); + out << indent() << elem << endl; + indent_down(); + out << indent() << "end)),"; indent_down(); - indent(out) << "end" << endl; + out << indent() << "?R0(Iprot,readSetEnd)," << endl; - // Read container end - if (ttype->is_map()) { - indent(out) << "iprot.readMapEnd()" << endl; - } else if (ttype->is_set()) { - indent(out) << "iprot.readSetEnd()" << endl; } else if (ttype->is_list()) { - indent(out) << "iprot.readListEnd()" << endl; - } + t_list* tlist = (t_list*)ttype; + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + out << indent() << "{" << etype << ", " << size << "} = ?R0(Iprot,readListBegin)," << endl; + out << indent() << prefix << " = thrift_utils:tabulate(" << size << "," << endl; + indent_up(); + out << indent() << "fun (_) ->" << endl; + indent_up(); + generate_deserialize_field(out,&felem,elem); + out << indent() << elem << endl; + indent_down(); + out << indent() << "end)," << endl; + indent_down(); + out << indent() << "?R0(Iprot,readListEnd)," << endl; + } } /** - * Generates code to deserialize a map + * Generates code to deserialize a map UNUSED */ void t_erl_generator::generate_deserialize_map_element(ostream &out, // TODO t_map* tmap, @@ -1177,7 +1197,7 @@ void t_erl_generator::generate_deserialize_map_element(ostream &out, // TODO } /** - * Write a set element + * Read a set element UNUSED */ void t_erl_generator::generate_deserialize_set_element(ostream &out, // TODO t_set* tset, @@ -1192,7 +1212,7 @@ void t_erl_generator::generate_deserialize_set_element(ostream &out, // TODO } /** - * Write a list element + * Read a list element UNUSED */ void t_erl_generator::generate_deserialize_list_element(ostream &out, // TODO t_list* tlist, @@ -1304,12 +1324,12 @@ void t_erl_generator::generate_serialize_container(ostream &out, // TODO indent(out) << "?R3(Oprot, writeMapBegin, " << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << - type_to_enum(((t_map*)ttype)->get_val_type()) << ", length(" << + type_to_enum(((t_map*)ttype)->get_val_type()) << ", thrift_utils:dict_size(" << prefix << "))," << endl; } else if (ttype->is_set()) { indent(out) << "?R2(Oprot, writeSetBegin, " << - type_to_enum(((t_set*)ttype)->get_elem_type()) << ", length(" << + type_to_enum(((t_set*)ttype)->get_elem_type()) << ", sets:size(" << prefix << "))," << endl; } else if (ttype->is_list()) { indent(out) << @@ -1319,31 +1339,33 @@ void t_erl_generator::generate_serialize_container(ostream &out, // TODO } if (ttype->is_map()) { - string kiter = tmp("kiter"); - string viter = tmp("viter"); + string kiter = tmp("_kiter"); + string viter = tmp("_viter"); indent(out) << - prefix << ".each do |" << kiter << ", " << viter << "|" << endl; + "dict:fold(fun ("<< kiter << ", " << viter << ",_)->" << endl; indent_up(); generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); + indent(out) << "nil" << endl; indent_down(); - indent(out) << "end" << endl; + indent(out) << "end, nil," << prefix << ")," << endl; } else if (ttype->is_set()) { - string iter = tmp("iter"); - string t = tmp("true"); + string iter = tmp("_iter"); indent(out) << - prefix << ".each do |" << iter << ", " << t << "|" << endl; + "sets:fold(fun ("<< iter << ",_)->" << endl; indent_up(); generate_serialize_set_element(out, (t_set*)ttype, iter); + indent(out) << "nil" << endl; indent_down(); - indent(out) << "end" << endl; + indent(out) << "end, nil," << prefix << ")," << endl; } else if (ttype->is_list()) { - string iter = tmp("iter"); + string iter = tmp("_iter"); indent(out) << - prefix << ".each do |" << iter << "|" << endl; + "lists:foldl(fun (" << iter << ",_)->" << endl; indent_up(); generate_serialize_list_element(out, (t_list*)ttype, iter); + indent(out) << "nil" << endl; indent_down(); - indent(out) << "end" << endl; + indent(out) << "end,nil," << prefix << ")," << endl; } if (ttype->is_map()) { @@ -1429,7 +1451,7 @@ string t_erl_generator::function_signature(t_function* tfunction, * Add a function to the exports list */ void t_erl_generator::export_string(string name, int num) { - if(export_lines_first_) { + if (export_lines_first_) { export_lines_first_ = false; } else { export_lines_ << ", "; @@ -1447,7 +1469,7 @@ void t_erl_generator::export_types_function(t_function* tfunction, } void t_erl_generator::export_types_string(string name, int num) { - if(export_types_lines_first_) { + if (export_types_lines_first_) { export_types_lines_first_ = false; } else { export_types_lines_ << ", "; @@ -1497,7 +1519,7 @@ string t_erl_generator::type_name(t_type* ttype) { string name = ttype->get_name(); - if (ttype->is_struct() || ttype->is_xception()) { + if (ttype->is_struct() || ttype->is_xception() || ttype->is_service()) { name = uncapitalize(ttype->get_name()); } diff --git a/lib/erl/lib/thrift/server.sh b/lib/erl/lib/thrift/server.sh index 4247c984..0ea4a6b2 100755 --- a/lib/erl/lib/thrift/server.sh +++ b/lib/erl/lib/thrift/server.sh @@ -2,7 +2,7 @@ if ! [ -d tutorial/gen-erl ]; then echo generating gen-erl cd tutorial - thrift -erl -r tutorial.thrift + thrift -erl -rb -r tutorial.thrift cd .. fi echo "Compiling user/ and tutorial/gen-erl/..." diff --git a/lib/erl/lib/thrift/src/oop.erl b/lib/erl/lib/thrift/src/oop.erl index bb6f34f6..3e6da054 100644 --- a/lib/erl/lib/thrift/src/oop.erl +++ b/lib/erl/lib/thrift/src/oop.erl @@ -88,7 +88,7 @@ call(Obj, Method) -> call_loop(Obj, Method, Args, TryModule, TriedRev, FirstObj) -> try - %% io:format("call_loop~n ~p~n ~p~n ~p~n ~p~n ~n", [Obj, Method, Args, TryModule]), + %% io:format("call_loop~n ~p~n ~p~n ~p~n ~p~n ~n", [inspect(Obj), Method, Args, TryModule]), apply(TryModule, Method, Args) catch error:Kind when Kind == undef; Kind == function_clause -> diff --git a/lib/erl/lib/thrift/src/thrift_utils.erl b/lib/erl/lib/thrift/src/thrift_utils.erl new file mode 100644 index 00000000..c1c6a259 --- /dev/null +++ b/lib/erl/lib/thrift/src/thrift_utils.erl @@ -0,0 +1,11 @@ +-module(thrift_utils). + +-export([tabulate/2,dict_size/1]). + +tabulateh(N,M,_) when N==M -> []; +tabulateh(N,M,F) -> [F(N)|tabulateh(N+1,M,F)]. +tabulate(N,F) -> tabulateh(0,N,F). + +% makin me sad +dict_size(Dict) -> + dict:fold(fun (_,_,I) -> I+1 end,0,Dict). diff --git a/tutorial/erl/server.erl b/tutorial/erl/server.erl index c924589b..0d5c1a91 100644 --- a/tutorial/erl/server.erl +++ b/tutorial/erl/server.erl @@ -9,34 +9,38 @@ -include("calculator.hrl"). --export([start/0, stop/1, ping/0, add/2, calculate/2, getStruct/1, zip/0]). + +-export([start/0, start/1, stop/1, ping/0, add/2, calculate/2, getStruct/1, zip/0]). ping() -> io:format("ping()~n",[]), - {ok, nil}. + nil. add(N1, N2) -> io:format("add(~p,~p)~n",[N1,N2]), - {ok, N1+N2}. + N1+N2. calculate(Logid, Work) -> { Op, Num1, Num2 } = { Work#work.op, Work#work.num1, Work#work.num2 }, io:format("calculate(~p, {~p,~p,~p})~n", [Logid, Op, Num1, Num2]), case Op of - ?ADD -> {ok, Num1 + Num2}; - ?SUBTRACT -> {ok, Num1 - Num2}; - ?MULTIPLY -> {ok, Num1 * Num2}; - ?DIVIDE -> - if Num2 == 0 -> {error, #invalidOperation{what=Op, why="Cannot divide by 0"}}; - true -> {ok, Num1 / Num2} - end; - true -> - {error, #invalidOperation{what=Op, why="Invalid operation"}} + ?tutorial_ADD -> Num1 + Num2; + ?tutorial_SUBTRACT -> Num1 - Num2; + ?tutorial_MULTIPLY -> Num1 * Num2; + + ?tutorial_DIVIDE when Num2 == 0 -> + throw(#invalidOperation{what=Op, why="Cannot divide by 0"}); + ?tutorial_DIVIDE -> + Num1 div Num2; + + _Else -> + throw(#invalidOperation{what=Op, why="Invalid operation"}) + end. getStruct(Key) -> io:format("getStruct(~p)~n", [Key]), - {ok, get(Key)}. + #sharedStruct{key=Key, value="RARG"}. zip() -> io:format("zip~n"). @@ -44,9 +48,11 @@ zip() -> %% start() -> - Handler = ?MODULE, % cpiro: or generated handler? + start(9090). + +start(Port) -> + Handler = ?MODULE, Processor = calculator, - Port = 9090, TF = tBufferedTransportFactory:new(), PF = tBinaryProtocolFactory:new(), @@ -63,4 +69,3 @@ start() -> stop(Server) -> ?C0(Server, stop), ok. - diff --git a/tutorial/rb/RubyClient.rb b/tutorial/rb/RubyClient.rb index bcf13009..9ee6e794 100755 --- a/tutorial/rb/RubyClient.rb +++ b/tutorial/rb/RubyClient.rb @@ -2,27 +2,40 @@ $:.push('../gen-rb') -require 'thrift/transport/tsocket' -require 'thrift/protocol/tbinaryprotocol' +require 'thrift/transport/tsocket.rb' +require 'thrift/protocol/tbinaryprotocol.rb' require 'Calculator' begin + port = ARGV[0] || 9090 - transport = TBufferedTransport.new(TSocket.new('localhost', 9090)) + transport = TBufferedTransport.new(TSocket.new('localhost', port)) protocol = TBinaryProtocol.new(transport) client = Calculator::Client.new(protocol) - + transport.open() - + client.ping() print "ping()\n" - + sum = client.add(1,1) print "1+1=", sum, "\n" - + + sum = client.add(1,4) + print "1+4=", sum, "\n" + work = Work.new() - + + work.op = Operation::SUBTRACT + work.num1 = 15 + work.num2 = 10 + diff = client.calculate(1, work) + print "15-10=", diff, "\n" + + log = client.getStruct(1) + print "Log: ", log.value, "\n" + begin work.op = Operation::DIVIDE work.num1 = 1 @@ -32,16 +45,10 @@ begin rescue InvalidOperation => io print "InvalidOperation: ", io.why, "\n" end - - work.op = Operation::SUBTRACT - work.num1 = 15 - work.num2 = 10 - diff = client.calculate(1, work) - print "15-10=", diff, "\n" - - log = client.getStruct(1) - print "Log: ", log.value, "\n" - + + client.zip() + print "zip\n" + transport.close() rescue TException => tx