def emit_message_send( message_send_node,next_to_call_node,seq_globals_node, endpoint_name,ast_root, fdep_dict,emit_ctx): ''' @param {AstNode} seq_globals_node --- Has label AST_MESSAGE_SEQUENCE_GLOBALS....In message send, we initialize the values of all sequence global variables. Use this to do that. ''' method_arg_names = get_method_arg_names(message_send_node) seq_local_init_prefix = ''' _first_msg = False if not _context.set_msg_send_initialized_bit_true(): # we must load all arguments into sequence local data and perform # initialization on sequence local data....start by loading # arguments into sequence local data # below tells the message send that it must serialize and # send all sequence local data. _first_msg = True ''' seq_local_init_prefix += emit_utils.indent_str( convert_args_to_waldo(message_send_node,True)) # now emit the sequence global initializations and declarations # (this will also emit for the return nodes). seq_local_init_prefix += emit_utils.indent_str(emit_statement.emit_statement( seq_globals_node,endpoint_name,ast_root,fdep_dict,emit_ctx)) seq_local_init_prefix += emit_utils.indent_str('\npass\n') seq_local_init_prefix += '\n' # when message send ends, it must grab the sequence local data # requested to return. To control for jumps, any time we jump, we # take whatever text is in emit_ctx's message_seq_return_txt and # insert it. (For a message send function, this will return # sequence local data. For a message receive function, this will # just be a return.) This way, can insure that do not continue # executing after jump. return_var_name_nodes = get_message_send_return_var_names( message_send_node) msg_send_return_txt = '\nreturn ' for counter in range(0,len(return_var_name_nodes)): var_name_node = return_var_name_nodes[counter] msg_send_return_txt += ( '_context.sequence_local_store.get_var_if_exists("%s")' % var_name_node) if counter != (len(return_var_name_nodes) -1): msg_send_return_txt += ',' emit_ctx.in_message_send = True emit_ctx.message_seq_return_txt = msg_send_return_txt # a message send function should look the same as a private # internal method (if we name it a little # differently...name_mangler arg takes care of this; and we # keep track of the return statement to issue on jump calls) msg_send_txt = emit_private_method_interface( message_send_node,endpoint_name,ast_root,fdep_dict,emit_ctx, lib_util.partner_endpoint_msg_call_func_name,seq_local_init_prefix) # issue call for what to call next msg_send_txt += '\n' msg_send_txt += emit_utils.indent_str( emit_message_node_what_to_call_next(next_to_call_node,emit_ctx)) # takes care of fall-through return (ie, message send has # completed) msg_send_txt += emit_utils.indent_str(msg_send_return_txt) msg_send_txt += '\n' emit_ctx.in_message_send = False emit_ctx.message_seq_return_txt = '' return msg_send_txt
def emit_private_method_interface( method_node,endpoint_name,ast_root,fdep_dict,emit_ctx, name_mangler=lib_util.endpoint_call_func_name,prefix=None): ''' @param {AstNode} method_node --- Either a public method node or a private method node. If it's a public method, then we emit the internal method that gets called from the public interface of the method. We emit private versions of public methods for two reasons: 1: The public versions of the methods do some very basic bookkeeping (copy args in, check for backout and retry, etc.) 2: When issuing an endpoint call, endpoint call gets issued to private part of function, which does most of the work. @param {Function} name_mangler --- Takes in a string and returns a string. The compiler uses different internal names for functions than appear in the Waldo source text. This is so that users are less likely to accidentally call into unsafe functions. This function should translate the name of the function from the source to an internal function. @param {String or None} prefix --- If we are emitting a message send function, there are some initialization operations that it must do. Instead of copying the function arguments, we use the string provided in prefix. Also can be called to emit a message send or message receive function. ''' name_node_index = 0 if emit_utils.is_message_sequence_node(method_node): name_node_index = 1 method_name_node = method_node.children[name_node_index] src_method_name = method_name_node.value internal_method_name = name_mangler(src_method_name) # When returning, check if it was a call from an outside-Waldo # function into this function... if it was (ie, # _returning_to_public_ext_array is not None), then we must # de-waldo-ify the return values before returning. The values of # _returning_to_public_ext_array correspond to which return values # should be returned as externals (ie, we do not de-waldo-ify # them). method_arg_names = ['_returning_to_public_ext_array=None'] if method_node.label == AST_MESSAGE_SEND_SEQUENCE_FUNCTION: # will fill in the default value of None in reduce method_arg_names = ['_returning_to_public_ext_array'] if method_node.label != AST_MESSAGE_RECEIVE_SEQUENCE_FUNCTION: # message receives take no arguments method_arg_names = get_method_arg_names(method_node) + method_arg_names if method_node.label != AST_MESSAGE_SEND_SEQUENCE_FUNCTION: comma_sep_arg_names = reduce ( lambda x, y : x + ',' + y, method_arg_names,'') else: # provide default values for all argument sequence local data. # That way, jumps are easier (we do not have to match # of # arguments when jumping). comma_sep_arg_names = reduce ( lambda x, y : x + ',' + y + '=None', method_arg_names,'') private_header = ''' def %s(self,_active_event,_context%s): ''' % (internal_method_name, comma_sep_arg_names) # actually emit body of function private_body = '\n' if method_node.label != AST_MESSAGE_RECEIVE_SEQUENCE_FUNCTION: if prefix == None: private_body = convert_args_to_waldo(method_node) else: # we are in a message send function: this means that # instead of copying in args, we must test if we've # already been initialized (to handle jumps properly). # Similarly, we must initialize other sequence global # data. private_body = prefix method_body_node = get_method_body_node_from_method_node(method_node) emitted_something = False for statement_node in method_body_node.children: emitted_something = True private_body += emit_statement.emit_statement( statement_node,endpoint_name,ast_root,fdep_dict,emit_ctx) private_body += '\n' if private_body.strip() == '': # in case of empty functions private_body += 'pass\n' return private_header + emit_utils.indent_str(private_body)