Example #1
0
def emit_endpoint_global_and_peered_variable_store(
    endpoint_name,host_uuid_var_name,ast_root,fdep_dict,emit_ctx):
    '''
    For params, @see emit_single_endpoint

    Returns a string that initializes the global variable store
    contained in self._global_var_store.
    '''
    
    endpoint_global_decl_nodes = get_endpoint_global_decl_nodes(
        endpoint_name,ast_root)
    peered_decl_nodes = get_peered_decl_nodes(ast_root)

    var_store_loading_text = '_active_event = None'
    var_store_loading_text += '''
_context = %s(
    self._global_var_store,
    # not using sequence local store
    %s(_host_uuid))
''' % (
        emit_utils.library_transform('ExecutingEventContext'),
        emit_utils.library_transform('VariableStore'))

    var_store_loading_text += create_wvariables_array(
        host_uuid_var_name,endpoint_global_decl_nodes,False,
        endpoint_name,ast_root,fdep_dict,emit_ctx)
    
    var_store_loading_text += create_wvariables_array(
        host_uuid_var_name,peered_decl_nodes,True,
        endpoint_name,ast_root,fdep_dict,emit_ctx)

    return var_store_loading_text
Example #2
0
def emit_endpoint_init(
    endpoint_name,ast_root,fdep_dict,emit_ctx):
    '''
    For params and return, @see emit_single_endpoint
    '''
    oncreate_argument_string = ''
    oncreate_node = get_oncreate_node(endpoint_name,ast_root)
    if oncreate_node != None:
        oncreate_arg_names = get_method_arg_names(oncreate_node)
        oncreate_argument_string = reduce (
            lambda x, y : x + ',' + y,
            oncreate_arg_names,'')

    init_header = (
        'def __init__(self,_waldo_classes,_host_uuid,_conn_obj%s):\n' % oncreate_argument_string)

    # create endpoint and peered variable store
    
    # should initialize variable store before entering into _Endpoint
    # super class initializer: super class initializer registers the
    # _Endpoint with connection object.  
    endpoint_global_and_peered_variable_store_load_txt = (
        emit_endpoint_global_and_peered_variable_store(
            endpoint_name,'_host_uuid',ast_root,fdep_dict,emit_ctx))

    # actually initialize super class
    init_body = '''
# a little ugly in that need to pre-initialize _host_uuid, because
# code used for initializing variable store may rely on it.  (Eg., if
# initializing nested lists.)
self._waldo_classes = _waldo_classes
self._host_uuid = _host_uuid
self._global_var_store = %s(_host_uuid)
%s
%s.__init__(self,_waldo_classes,_host_uuid,_conn_obj,self._global_var_store)

''' % (emit_utils.library_transform('VariableStore'),
       endpoint_global_and_peered_variable_store_load_txt,
       emit_utils.library_transform('Endpoint'))


    # emit call to oncreate method
    init_body += emit_oncreate_call(endpoint_name,ast_root)

    return init_header + emit_utils.indent_str(init_body)
Example #3
0
def emit_message_node_what_to_call_next(next_to_call_node,emit_ctx):
    '''
    @param {AstNode or None} next_to_call_node --- A message receive
    node or None.  At the end of a message send or message receive
    function, execution should "fall through" to the following message
    receive block.  This function emits the code that handles this
    logic.  Ie, it requests active event to issue a request to execute
    a message sequence block.  (Note: if next_to_call_node is None,
    then that means that we were at the end of a sequence and do not
    have any other blocks to execute: return empty string.
    '''

    if next_to_call_node == None:
        return ''

    # FIXME: seems to reproduce a lot of work already done in
    # emit_message_receive.
    
    next_message_name_node = next_to_call_node.children[1]
    next_message_name = next_message_name_node.value

    issue_call_is_first_txt = 'False'
    if emit_ctx.in_message_send:
        # allows us to determine if this is the first message in a
        # sequence block that is being sent.  If it is, then we need
        # to force sequence local data to be synchronized.  If it's
        # not, we only need to synchronize modified sequence local data.
        issue_call_is_first_txt = '_first_msg'

    
    return  '''
_threadsafe_queue = %s.Queue()
_active_event.issue_partner_sequence_block_call(
    _context,'%s',_threadsafe_queue, '%s')
_queue_elem = _threadsafe_queue.get()

if isinstance(_queue_elem,%s):
    raise %s()

_context.set_to_reply_with(_queue_elem.reply_with_msg_field)

# apply changes to sequence variables.  (There shouldn't
# be any, but it's worth getting in practice.)  Note: that
# the system has already applied deltas for global data.
_context.sequence_local_store.incorporate_deltas(
    _active_event,_queue_elem.sequence_local_var_store_deltas)

# send more messages
_to_exec_next = _queue_elem.to_exec_next_name_msg_field
if _to_exec_next != None:
    # means that we do not have any additional functions to exec
    _to_exec = getattr(self,_to_exec_next)
    _to_exec(_active_event,_context)
else:
    # end of sequence: reset to_reply_with_uuid in context.  we do
    # this so that if we go on to execute another message sequence
    # following this one, then the message sequence will be viewed as
    # a new message sequence, rather than the continuation of a
    # previous one.
    _context.reset_to_reply_with()

''' % (emit_utils.library_transform('Queue'),
       next_message_name, # the name of the message receive func to
                          # exec on other side in plain text
       issue_call_is_first_txt,
       emit_utils.library_transform('BackoutBeforeReceiveMessageResult'),
       emit_utils.library_transform('BackoutException'),
       )
Example #4
0
def emit_message_receive(
    message_receive_node,next_to_call_node,endpoint_name,ast_root,
    fdep_dict,emit_ctx):
    '''
    @param {AstNode or None} next_to_call_node --- If AstNode, then
    has label AST_MESSAGE_RECEIVE_FUNCTION.  If None, means that this
    is the last message receive node in sequence and should tell other
    side to issue a block call with target None.
    '''

    msg_recv_node_name_node = message_receive_node.children[1]
    msg_recv_name = msg_recv_node_name_node.value
    
    emit_ctx.in_message_receive = True
    emit_ctx.message_seq_return_txt = '\nreturn '

    msg_receive_txt = emit_private_method_interface(
        message_receive_node,endpoint_name,ast_root,fdep_dict,emit_ctx,
        lib_util.partner_endpoint_msg_call_func_name)
    msg_receive_txt += '\n'
    
    emit_ctx.in_message_receive = False
    emit_ctx.message_seq_return_txt = ''

    ## Ends by telling the opposite side what to do next
    next_to_call_txt = 'None'
    if next_to_call_node != None:
        # the name of the next sequence block to execute, as it
        # appears in the source Waldo text, ie, before mangling.
        next_sequence_block_src_name = next_to_call_node.children[1].value
        
        next_to_call_txt = '"' + lib_util.partner_endpoint_msg_call_func_name(
            next_sequence_block_src_name) + '"'
        

        
    # note that we must wait on receiving a response from the other
    # side before we can continue on, or the original sender may
    # return too early. We should not wait on the last message that we
    # send however, because, we do not expect any response to it.
    # (Ie, if next_to_call_txt == 'None', then do not wait.)
    next_sequence_txt = '''

_threadsafe_queue = %s.Queue()
_active_event.issue_partner_sequence_block_call(
    _context,%s,_threadsafe_queue,False)
# must wait on the result of the call before returning

if %s != None:
    # means that we have another sequence item to execute next

    _queue_elem = _threadsafe_queue.get()


''' % (emit_utils.library_transform('Queue'),
       next_to_call_txt,
       next_to_call_txt)



    next_sequence_txt += '''

    if isinstance(_queue_elem,%s):
        # back everything out
        raise %s()

    _context.set_to_reply_with(_queue_elem.reply_with_msg_field)

    # apply changes to sequence variables.  Note: that
    # the system has already applied deltas for global data.
    _context.sequence_local_store.incorporate_deltas(
        _active_event,_queue_elem.sequence_local_var_store_deltas)

    # send more messages
    _to_exec_next = _queue_elem.to_exec_next_name_msg_field
    if _to_exec_next != None:
        # means that we do not have any additional functions to exec
        _to_exec = getattr(self,_to_exec_next)
        _to_exec(_active_event,_context)

''' % (emit_utils.library_transform('BackoutBeforeReceiveMessageResult'),
       emit_utils.library_transform('BackoutException'))


    msg_receive_txt += emit_utils.indent_str(next_sequence_txt)
    return msg_receive_txt
Example #5
0
def emit_public_method_interface(
    public_method_node,endpoint_name,ast_root,fdep_dict,emit_ctx):
    '''
    @param {AstNode} public_method_node --- An AstNode with label
    AST_PUBLIC_FUNCTION
    '''
    method_name_node = public_method_node.children[0]
    method_name = method_name_node.value

    method_arg_names = get_method_arg_names(public_method_node)
    # turns the array of argnames above into a single string of csv
    # arg names
    comma_sep_arg_names = reduce (
        lambda x, y : x + ',' + y,
        method_arg_names,'')

    public_header = '''
def %s(self%s):
''' % (method_name, comma_sep_arg_names)

    # wait until ready initialization for node has completed before
    # continuing
    public_body = '''
# ensure that both sides have completed their onCreate calls
# before continuing
self._block_ready()
'''
    
    #### Deep copy non-external args
    # non_ext_arg_names is an array of strings
    non_ext_arg_names = get_non_external_arg_names_from_func_node(
        public_method_node)
                
    # do not need to copy arguments in: each function call does so on
    # its own.

    # Each element in this list is an index for a return parameter
    # that should be de-waldo-ified before returning.  We pass this
    # argument to the internal function that the internal function
    # knows which returns need to be de-waldo-ified before being
    # returned and which do not.
    list_return_external_positions = (
        get_external_return_positions_from_func_node(public_method_node))

    #### create a root event + ctx for event, call internal, and reurn
    internal_method_name = lib_util.endpoint_call_func_name(method_name)
    public_body += '''
while True:  # FIXME: currently using infinite retry 
    _root_event = self._act_event_map.create_root_event()
    _ctx = %s(
        self._global_var_store,
        # not using sequence local store
        %s(self._host_uuid))

    # call internal function... note True as last param tells internal
    # version of function that it needs to de-waldo-ify all return
    # arguments (while inside transaction) so that this method may
    # return them....if it were false, might just get back refrences
    # to Waldo variables, and de-waldo-ifying them outside of the
    # transaction might return over-written/inconsistent values.
    _to_return = self.%s(_root_event,_ctx %s,%s)
    # try committing root event
    _root_event.request_commit()
    _commit_resp = _root_event.event_complete_queue.get()
    if isinstance(_commit_resp,%s):
        # means it isn't a backout message: we're done
        return _to_return
''' % (emit_utils.library_transform('ExecutingEventContext'),
       emit_utils.library_transform('VariableStore'),
       internal_method_name,
       comma_sep_arg_names,
       str(list_return_external_positions),
       emit_utils.library_transform('CompleteRootCallResult'))

    return public_header + emit_utils.indent_str(public_body)
Example #6
0
def emit_oncreate_call(endpoint_name,ast_root):
    '''
    Inside of each endpoint's initializer, we may need to emit a call
    to an onCreate initializer method.  Below emits the text that
    actually calls the initializer method.
    
    @returns {String}
    '''
    oncreate_node = get_oncreate_node(endpoint_name,ast_root)
    
    if oncreate_node != None:
        oncreate_arglist = get_method_arg_names(oncreate_node)
        comma_sep_arg_names = reduce (
            lambda x, y : x + ',' + y,
            oncreate_arglist,'')

        # run the initializer
        oncreate_call_txt = '''
while True:  # FIXME: currently using infinite retry 
    _root_event = self._act_event_map.create_root_event()
    _ctx = %s(
        self._global_var_store,
        # not using sequence local store
        %s(self._host_uuid))

    # call internal function... note True as last param tells internal
    # version of function that it needs to de-waldo-ify all return
    # arguments (while inside transaction) so that this method may
    # return them....if it were false, might just get back refrences
    # to Waldo variables, and de-waldo-ifying them outside of the
    # transaction might return over-written/inconsistent values.
    _to_return = self.%s(_root_event,_ctx %s,[])
    # try committing root event
    _root_event.request_commit()
    _commit_resp = _root_event.event_complete_queue.get()
    if isinstance(_commit_resp,%s):
        # means it isn't a backout message: we're done

        # local endpoint's initialization has succeeded, tell other side that
        # we're done initializing.
        self._this_side_ready()

        return _to_return

    ''' % (emit_utils.library_transform('ExecutingEventContext'),
           emit_utils.library_transform('VariableStore'),
           lib_util.internal_oncreate_func_call_name('onCreate'),
           comma_sep_arg_names,
           emit_utils.library_transform('CompleteRootCallResult'))

    else:
        oncreate_call_txt = '\n'

    # local endpoint's initialization has succeeded, tell other side
    # that we're done initializing.  note: we don't hit this section
    # of code if we actually had an oncreate node, so it's okay that
    # we list self._this_side_ready() twice: only one of them will
    # ever be called.
    oncreate_call_txt += '''
# local endpoint's initialization has succeeded, tell other side that
# we're done initializing.
self._this_side_ready()
'''
    return oncreate_call_txt