예제 #1
0
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
예제 #2
0
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)