def project(projector, node_): src = get_source(node_) dests = get_destinations(node_) if src == projector.role or projector.role in dests: child = get_message_child(node_) message = None if util.get_node_type(child) == constants.MESSAGE_SIGNATURE_NODE_TYPE: message = messagesignature_pretty_print( child) # FIXME: string hack else: message = parameter_get_name(child) # FIXME: string hack if src == projector.role: if projector.role in dests: util.report_error("Self communication not supported.") #new_dests = util.replace_in_list(dests, projector.rolemap) new_dests = dests return projector.nf.localsend(projector.role, new_dests, message) if projector.role in dests: if src == projector.role: util.report_error("Self communication not supported.") #new_src = util.replace_in_list([src], projector.rolemap)[0] new_src = src return projector.nf.localreceive(projector.role, new_src, message) else: return None # OK to use None as "empty projection"?
def check_wellformedness(checker, node_): context_ = checker.get_context() sigs = get_message_children(node_) subj = get_role(node_) # Section 4.6.9 -- bound interrupt role if not context_.is_role_declared(subj): util.report_error("Bad interrupt role: " + subj) tmp = context_.get_operators().items() for sig in sigs: if util.get_node_type(sig) == constants.MESSAGE_SIGNATURE_NODE_TYPE: #tmp = context_.get_operators().items() # Section 4.6.9 -- well-formed message signature messagesignature_check_wellformedness(checker, sig) op = context_.get_current_scope() + '.' \ + messagesignature_get_operator(sig) # interrupt sig belongs to the scope of the interruptible for (src, _), ops in tmp: if op in ops: # Section 4.6.9 -- op is not in any potential ops set of # block for subj if subj == src: util.report_error("Bad interrupt operator: " + op) #context_ = context_.add_operator() # FIXME: can't do currently: interrupt messages have no # specific dest (need to look up all possible # destinations, or could make a special broadcast value # constant?) -- top-level interruptible inside a choice # block can also be an enabling op else: raise RuntimeError("TODO: " + parameter_get_parameter_name(sig))
def project(projector, node_): src = get_source(node_) dests = get_destinations(node_) if src == projector.role or projector.role in dests: child = get_message_child(node_) message = None if util.get_node_type(child) == constants.MESSAGE_SIGNATURE_NODE_TYPE: message = messagesignature_pretty_print(child) # FIXME: string hack else: message = parameter_get_name(child) # FIXME: string hack if src == projector.role: if projector.role in dests: util.report_error("Self communication not supported.") #new_dests = util.replace_in_list(dests, projector.rolemap) new_dests = dests return projector.nf.localsend(projector.role, new_dests, message) if projector.role in dests: if src == projector.role: util.report_error("Self communication not supported.") #new_src = util.replace_in_list([src], projector.rolemap)[0] new_src = src return projector.nf.localreceive(projector.role, new_src, message) else: return None # OK to use None as "empty projection"?
def check_wellformedness_visit(checker, node_): #context_ = checker.get_context() visited = _context_visit_children_and_cache_contexts(checker, node_) contexts = _peek_cached_contexts(visited) subj = get_subject(visited) # string # Here we first do the checks involving just the information collected from # this choice (push_globalchoice clears enabledroles). Information from # parent is carried over to the new context later below. # # Map from role_ name (string) to set of enabling op (Section 4.6.6 -- # initial operators) names (strings) -- values set in globalmessagetransfer enabled = collections.clone_collection(contexts[0].get_enabled_roles()) for c in contexts[1:]: tmp = c.get_enabled_roles() # Section 4.6.6 -- same set of roles occur in each block if set(tmp.keys()) != set(enabled.keys()): util.report_error("Bad choice block: " + ' ' + str(enabled.keys()) + str(tmp.keys())) # + "\n" + util.pretty_print(c.getnode())) for role_, ops in tmp.items(): #if not(ops == None): if role_ != subj: # Should be generalised for all roles that are already enabled, # not just the subject? # No: already taken care of by the fact # that enabled records only the initial enabling ops (added in # globalmessagetransfer), not all operators # So here maybe # better to use "if not enabled"? for op in ops: # Section 4.6.6 -- initial operators in each block for each # role_ are disjoint if op in enabled[role_]: util.report_error("Bad choice operator: " + op) enabled[role_].add(op) return visited
def _parse_command_line_args(argv): # Could use argparse (or ANTLR) args = { _SOURCE: [], _IMPORT_PATH: [], _PAYLOAD_TYPE_PATH: [], _PROJECT_PROTOCOL: None, _PROJECT_DIR: None } if len(argv) > 1: iter = argv[1:].__iter__() for arg in iter: if arg == '-ip' or arg == '-importpath': # Factor out constants path = iter.next().split(';') args[_IMPORT_PATH].extend(path) elif arg == '-pp' or arg == '-payloadpath': path = iter.next().split(';') args[_PAYLOAD_TYPE_PATH].extend(path) elif arg == '-project': args[_PROJECT_PROTOCOL] = iter.next() args[_PROJECT_ROLE] = iter.next() elif arg == '-o': args[_PROJECT_DIR] = iter.next() else: if arg.startswith('-'): util.report_error("Bad argument flag: " + arg) if len(args[_SOURCE]) > 0: util.report_error("Specify a single module: " + arg) args[_SOURCE].append(arg) if '.' not in args[_IMPORT_PATH]: # factor out current directory args[_IMPORT_PATH].append('.') return args
def parameter_kind_to_string(kind): if kind == constants.KIND_MESSAGE_SIGNATURE: return constants.SIG_KW elif kind == constants.KIND_PAYLOAD_TYPE: return constants.TYPE_KW else: util.report_error("Unknown parameter kind: ", kind)
def check_wellformedness_enter(checker, node_): context = checker.get_context() #contlab = get_label(node_) contlab = context.get_current_scope() + '.' + get_label(node_) # FIXME: factor out with globalrecursion and Context if not context.is_recursion_label_declared(contlab): util.report_error("Bad continue label: " + contlab)
def main(argv, otherArg=None): args = _parse_command_line_args(sys.argv) if not args[_SOURCE]: util.report_error("No input file specified.") filepath = args[_SOURCE][0] # The full module name as a string # FIXME: hardcoded to 0-index only importpath = args[_IMPORT_PATH] ext = util.parse_file_extension_from_filepath(filepath) if ext != constants.SCRIBBLE_FILE_EXTENSION: util.report_error("Bad file extension: " + ext) module_ = util.load_file_and_parse_module(filepath) # Returns an antlr3.tree.CommonTree with the module as the root # Section 4.2 -- module dependencies. Load all the modules that the target # module_ may depend on Initial Context is outside of the AST (no # parent/node) -- these fields are initialised on entering the AST from the # root module node context_ = Context(args[_IMPORT_PATH], args[_PAYLOAD_TYPE_PATH]) context_ = load_modules(context_, filepath, module_) # TODO: import members not supported yet # Next passes can do transformations on the raw AST # Insert implicit scopes in each protocol of each module_ context_ = _insert_scopes(context_) # Raw transformations finished; next record individual members (for # convenience -- currently only used by projection; ContextVisitor passes # use visibility) context_ = load_members(context_, filepath, module_) # Context built up to now is the base context. Subsequent ContextVisitor # passes each start from the base Context and build/manipulate the # pass-specific Context as appropriate # Section 4.2 -- well-formedness of primary module. Separately build the # visibility context_ for each dependency (it can be different for each) and # check the well-formedness conditions that must hold for each dependency # checks well-formedness conditions on each in-context_ module (these are # the loaded modules, which are the dependencies of the primary module) _check_wellformedness(context_) # Here the Context has only modules and members loaded, no # visibility built (Context was not retained from well-formedness checking). # The returned context_ holds all the projections context_ = _project_all(context_) # Check reachability at the local protocol level _check_reachability(context_) proto = args[_PROJECT_PROTOCOL] if proto is not None: localrole = args[_PROJECT_ROLE] dir = args[_PROJECT_DIR] #context_ = _project(context_, proto, localrole, dir) _output_projections_to_modules(context_, proto, localrole, dir)
def check_reachability_visit(self, checker): visited = [] for child in self.get_children(): context_ = checker.get_context() if not context_.has_exit(): util.report_error("Bad sequence: " + child.pretty_print()) visited.append(checker.visit(child)) return checker.nf.localinteractionsequence(self.local_role, visited)
def check_filename(filepath, moduledecl_): smn_from_filepath = util.parse_simple_module_name_from_filepath(filepath) fmn_from_moduledecl = get_full_name(moduledecl_) smn_from_moduledecl = util.get_simple_module_name_from_full_module_name(fmn_from_moduledecl) if smn_from_filepath != smn_from_moduledecl: util.report_error("Bad module declaration/file name: declaration=" + \ smn_from_moduledecl + ", path=" + filepath)
def check_wellformedness_enter(checker, node_): context_ = checker.get_context() # Section 4.6.7 -- global recursion must specify a recursion label that is # not bound #reclab = get_label(node_) reclab = context_.get_current_scope() + '.' + get_label(node_) if reclab in context_.peek_recursion_labels().keys(): util.report_error("Bad recursion label: " + reclab)
def check_filename(filepath, moduledecl_): smn_from_filepath = util.parse_simple_module_name_from_filepath(filepath) fmn_from_moduledecl = get_full_name(moduledecl_) smn_from_moduledecl = util.get_simple_module_name_from_full_module_name( fmn_from_moduledecl) if smn_from_filepath != smn_from_moduledecl: util.report_error("Bad module declaration/file name: declaration=" + \ smn_from_moduledecl + ", path=" + filepath)
def _check_for_errornode_aux(self, node_): if type(node_) == CommonErrorNode: # that's just the way Antlr is working? (error nodes as first child?) #if (type(node.getChild(0)) == CommonErrornode_): util.report_error(child.toString()) for child in node_.getChildren(): if type(child) == CommonErrorNode: util.report_error(child.toString()) return node_
def clone_dict_aux(dict_): if dict_ is None: return None if not isinstance(dict_, dict): util.report_error("Expected dict, not: " + type(dict_)) clone = {} for k in dict_.keys(): clone[clone_collection(k)] = clone_collection(dict_[k]) return clone
def clone_set_aux(set_): if set_ is None: return None if not isinstance(set_, set): util.report_error("Expected set, not: " + set) clone = set([]) for x in set_: clone.add(clone_collection(x)) return clone
def get_full_name_from_visible_name(context_, globalproto): gpd = context_.get_visible_global(globalproto) if gpd is None: # Should never happen? util.report_error("Bad protocol reference: " + target) module_ = gpd.getParent() modulefullname = moduledecl_get_full_name( module_get_moduledecl_child(module_)) protofullname = modulefullname + '.' + globalprotocoldecl_get_name(gpd) return protofullname
def clone_list_aux(list_): if list_ is None: return None if not isinstance(list_, list): util.report_error("Expected list, not: " + list) clone = [] for x in list_: clone.append(clone_collection(x)) return clone
def check_wellformedness_enter(checker, node_): context_ = checker.get_context() roles = [] for rd in get_roledecl_children(node_): role = roledecl_get_declaration_name(rd) # Section 4.6 -- Global protocol header: distinct role declaration names if role in roles: util.report_error("Bad role declaration name: " + role) roles.append(role)
def check_wellformedness_enter(checker, node_): context = checker.get_context() # Section 4.6.6 -- at-role of choice is bound # # This condition needs to be checked here before performing the # choice-specific Context push subj = get_subject(node_) if not context.is_role_declared(subj): util.report_error("Bad choice subject: " + subj) if not context.is_role_enabled(subj): util.report_error("Choice subject not enabled: " + subj)
def check_wellformedness_visit(checker, node_): visited = context_visitor_visit(checker, node_) interrupts = get_interrupt_children(visited) seen = [] for i in interrupts: globalinterrupt_check_wellformedness(checker, i) subj = globalinterrupt_get_role(i) # Section 4.6.9 -- distinct interrupt roles (bound role checked inside # globalinterrupt) if subj in seen: util.report_error("Bad interrupt role: " + subj) seen.append(subj) return visited
def check_wellformedness_enter(checker, node_): context_ = checker.get_context() parameters = [] for pd in get_parameterdecl_children(node_): kind = parameterdecl_get_kind(pd) param = parameterdecl_get_declaration_name(pd) # Section 4.6 -- Global protocol header: distinct param declaration # names if param in parameters or \ param in context_.get_visible_payloads().keys(): scrib_util.report_error("Bad param declaration name: " + \ param) parameters.append(param)
def _get_self_visibility(context, module_): for ptd in module_get_payloadtypedecl_children(module_): n = payloadtypedecl_get_declaration_name(ptd) context = context.add_visible_payload(n, ptd) for gpd in module_get_globalprotocoldecl_children(module_): n = globalprotocoldecl_get_name(gpd) context = context.add_visible_global(n, gpd) for lpd in module_get_localprotocoldecl_children(module_): n = localprotocoldecl_get_name(lpd) context = context.add_visible_local(n, lpd) importmembers = module_get_importmember_children(module_) for im in importmembers: util.report_error("TODO: member import: " + im) # FIXME: members return context
def traverse(traverser, node_): traversed = [] moduledecl = get_moduledecl_child(node_) traversed.append(traverser.traverse(moduledecl)) for im in get_importmodule_children(node_): traversed.append(traverser.traverse(im)) for im in get_importmember_children(node_): util.report_error("Member Import not supported yet.") # FIXME: also members for ptd in get_payloadtypedecl_children(node_): traversed.append(traverser.traverse(ptd)) for gpd in get_globalprotocoldecl_children(node_): traversed.append(traverser.traverse(gpd)) for lpd in get_localprotocoldecl_children(node_): traversed.append(traverser.traverse(lpd)) # rebuild using new children return util.antlr_dupnode_and_replace_children(node_, traversed)
def _add_all_members(context_, fmn, module_): for ptd in module_get_payloadtypedecl_children(module_): n = payloadtypedecl_get_declaration_name(ptd) f = fmn + '.' + n context_ = context_.add_member(f, ptd) for gpd in module_get_globalprotocoldecl_children(module_): n = globalprotocoldecl_get_name(gpd) f = fmn + '.' + n context_ = context_.add_member(f, gpd) for lpd in module_get_localprotocoldecl_children(module_): n = localprotocoldecl_get_name(lpd) f = fmn + '.' + n context_ = context_.add_member(f, lpd) importmembers = module_get_importmember_children(module_) for im in importmembers: # TODO: members util.report_error("TODO member import: " + im) return context_
def _add_all_members(context_, fmn, module_): for ptd in module_get_payloadtypedecl_children(module_): n = payloadtypedecl_get_declaration_name(ptd) f = fmn + "." + n context_ = context_.add_member(f, ptd) for gpd in module_get_globalprotocoldecl_children(module_): n = globalprotocoldecl_get_name(gpd) f = fmn + "." + n context_ = context_.add_member(f, gpd) for lpd in module_get_localprotocoldecl_children(module_): n = localprotocoldecl_get_name(lpd) f = fmn + "." + n context_ = context_.add_member(f, lpd) importmembers = module_get_importmember_children(module_) for im in importmembers: # TODO: members util.report_error("TODO member import: " + im) return context_
def _get_module_members(context, dn, module_): for ptd in module_get_payloadtypedecl_children(module_): n = payloadtypedecl_get_declaration_name(ptd) f = dn + '.' + n context = context.add_visible_payload(f, ptd) #context = context.add_visible_payload(n, ptd) for gpd in module_get_globalprotocoldecl_children(module_): n = globalprotocoldecl_get_name(gpd) f = dn + '.' + n context = context.add_visible_global(f, gpd) #context = context.add_visible_global(n, gpd) for lpd in module_get_localprotocoldecl_children(module_): n = localprotocoldecl_get_name(lpd) f = dn + '.' + n context = context.add_visible_local(f, lpd) #context = context.add_visible_local(n, gpd) importmembers = module_get_importmember_children(module_) for im in importmembers: util.report_error("TODO member import: " + im) # TODO: members return context
def check_wellformedness(checker, node_): context = checker.get_context() payloads = get_payloadelement_children(node_) for payload in payloads: annot = payloadelement_get_annotation(payload) payloadtype = payloadelement_get_type(payload) # TODO: annotation well-formedness will be further specified in langref # when annotations framework is added if annot != payloadelement_EMPTY_ANNOTATION: # Section 4.6.2 -- distinct annotation names if annot in context.get_annotationss(): util.report_error("Bad annotation: " + annot) context = context.add_annotation(annot) # Section 4.5 -- Visible payload types if payloadtype not in context.get_visible_payloads().keys(): # "type" parameters # Section 4.5 -- Bound (type) parameter if payloadtype not in context.get_parameters().keys(): util.report_error("Bad payload type: " + payloadtype) # Section 4.5 -- type parameter if context.get_parameter(payloadtype) != \ constants.KIND_PAYLOAD_TYPE: util.report_error("Bad payload type parameter: " + \ payloadtype) checker.set_context(context)
def check_wellformedness(context_, target, node_): ris = get_roleinstantiation_children(node_) tree = context_.get_visible_global(target) rparamlist = roledecllist_get_roledecl_children( globalprotocoldecl_get_roledecllist_child(tree)) # Section 4.6.3 -- lengts of role-instantiation-list and target # role-decl-list are the same if len(ris) != len(rparamlist): util.report_error("Bad number of role arguments, expected: " + \ str(len(rparamlist))) croles = context_.get_roles() rparams = rparamlist.__iter__() rolemap = {} # params -> args (as strings -- # maybe should do ROLE node_, as for argmap) for ri in ris: ours = roleinstantiation_get_arg(ri) next = rparams.next() theirs = roledecl_get_role_name(next) # Section 4.6.3 -- every role argument is bound and distinct if (ours not in croles) or ours in rolemap.values(): util.report_error("Bad role argument: " + ours) if roleinstantiation_has_parameter_child(ri): tmp = roleinstantiation_get_parameter(ri) if theirs != tmp: # Section 4.6.3 -- every instantiation parameter corresponds to # the declared parameter in the protocol declaration util.report_error("Bad role parameter: " + theirs + ", " +tmp) rolemap[roledecl_get_declaration_name(next)] = ours return rolemap
def check_wellformedness_enter(checker, node_): context_ = checker.get_context() scope = get_scope(node_) target = get_target(node_) # Should be a visible protocol name, but not necessarily the full name # Section 4.6.2 -- distinct scope names if scope != EMPTY_SCOPE_NAME and scope in context_.get_current_scopes(): util.report_error("Bad scope: " + scope) # Section 4.6.10 -- target protocol must be visible globals = context_.get_visible_globals() if target not in globals.keys(): #tmp = context_.get_current_module() + '.' + target # All visible globals should already be collected by # VisibilityBuilder now #if not(tmp in globals.keys()): util.report_error("Bad protocol reference: " + target) # Section 4.6.2 -- Distinct scope checked above # # Checking for bad recursive-do from within parallel (FIXME: not currently # specified in langref) # # No way for a recursive-do to be good inside a parallel, unless it's a # singleton parallel, but ignoring that special case for now do_stack = context_.peek_do_chain() fullname = get_target_full_name(context_, node_) if fullname in do_stack.keys(): # Recursive-do to this protocol has been forbidden by entering a # parallel context_ if not do_stack[fullname]: util.report_error("Bad do: " + fullname) """if scope == EMPTY_SCOPE_NAME: # Is this needed?
def check_wellformedness(checker, node_): context = checker.get_context() payloads = get_payloadelement_children(node_) for payload in payloads: annot = payloadelement_get_annotation(payload) payloadtype = payloadelement_get_type(payload) # TODO: annotation well-formedness will be further specified in langref # when annotations framework is added if annot != payloadelement_EMPTY_ANNOTATION: # Section 4.6.2 -- distinct annotation names if annot in context.get_annotationss(): util.report_error("Bad annotation: " + annot) context = context.add_annotation(annot) # Section 4.5 -- Visible payload types if payloadtype not in context.get_visible_payloads().keys(): # "type" parameters # Section 4.5 -- Bound (type) parameter if payloadtype not in context.get_parameters().keys(): util.report_error("Bad payload type: " + payloadtype) # Section 4.5 -- type parameter if context.get_parameter(payloadtype) != constants.KIND_PAYLOAD_TYPE: util.report_error("Bad payload type parameter: " + payloadtype) checker.set_context(context)
def project(projector, node_): projections = projector.context.get_projections() fmn = get_full_module_name(node_) # Check if this import is referring to one of the subprotocol modules. # "target" is the local target name # # FIXME: make precise about which subprotocols are actually needed (use # SubprotocolCollector again for the current target) for target in projector.subprotocols: gmn = util.get_global_module_name_from_projected_member_name(target) if fmn == gmn: if not has_alias(node_): localmodulename = \ util.get_full_module_name_from_full_member_name(target) return projector.nf.importmodule(localmodulename, None) else: util.report_error("[Projector] importmodule TODO: " + \ get_declaration_name(node_)) #else: # util.report_error("[Projector] importmodule TODO: " + target)""" return None
def check_wellformedness_visit(checker, node_): context = checker.get_context() visited = _context_visit_children_and_cache_contexts(checker, node_) contexts = _peek_cached_contexts(visited) # Section 4.6.8 -- potential operators and sig parameters ops = collections.clone_collection(contexts[0].get_operators()) # includes sig parameters for c in contexts[1:]: tmp = c.get_operators() for (src, dest) in tmp.keys(): if (src, dest) in ops.keys(): us = ops[(src, dest)] them = tmp[(src, dest)] # Section 4.6.8 -- potential operators and parameters disjoint # between each block if not us.isdisjoint(them): util.report_error("Bad parallel operator(s): " + \ str(us & them)) ops[(src, dest)] = us | them # set union else: ops[(src, dest)] = tmp[(src, dest)] return visited
def _output_projections_to_modules(context_, target_globalname, localrole, dir): members = context_.get_members() if target_globalname not in members.keys(): util.report_error("[Projection] Unknown protocol: " + \ target_globalname) #+ ", " + str(members)) gpd = context_.get_member(target_globalname) if util.get_node_type(gpd) != constants.GLOBAL_PROTOCOL_DECL_NODE_TYPE: util.report_error("[Projection] Not a global protocol declaration: " + target_globalname) if localrole not in globalprotocoldecl_get_role_names(gpd): util.report_error("[Projection] Projection role not declared: " + localrole) target_localname = globaldo_get_projected_member_name(target_globalname, localrole) todo = [target_localname] lpd = context_.get_projection(target_localname) subprotos = SubprotocolCollector(context_).collect_subprotocols(lpd, True) todo.extend(subprotos) # Includes target_globalname (even if not used recursively) # Write each subprotocol to a separately projected module for subproto in todo: globalmodulename = \ util.get_global_module_name_from_projected_member_name(subproto) # FIXME: not working if member/role names contain underscores; but # good to run subprotocol collection on local protocol. best way may # be to record a mapping between projected names and the global/role # names they come from globalmodule = context_.get_module(globalmodulename) projector = Projector() lm = projector.project_module(context_, globalmodule, subproto, todo) # subproto is the full local name lm = lm.addlocalprotocoldecl(context_.get_projection(subproto)) fmn = lm.get_full_name() filepath = None if dir is None: # FIXME: factor out with e.g. globaldo and importmodule projection filename = util.get_simple_module_name_from_full_module_name(fmn) \ + '.' + constants.SCRIBBLE_FILE_EXTENSION sp = context_.get_source(globalmodulename) filepath = util.parse_directory_from_filepath(sp) + '/' + filename # FIXME: double slashes being introduced somewhere else: filepath = dir + '/' + \ util.convert_full_module_name_to_filepath(fmn) _write_module(lm, filepath) """print '[DEBUG] Projection of ' + target_globalname + ' for ' + \
def context_visitor_leave(cv, node_): # Still the "original context" on entering the Choice (not yet updated with # any information from visiting block children) # # Perhaps instead clone the parent context (the context before entering this # choice)? clone = cv.get_context().clone() subj = get_subject(node_) # string contexts = _remove_cached_contexts(node_) # Update enabled roles (initial ops) map (Section 4.6.6 -- initial operators) prev = clone.parent.get_enabled_roles() # Get information from parent context (enabledroles was originally cleared # by push_globalchoice to visit this choice) # # Can factor out to sequencing? Maybe not: this is an instance of generally # carrying information over from the parent context, not just sequencing # sitations ##clone._enabled_roles = {} # HACK (1) for role_, ops in prev.items(): for op in ops: # Carry "initial ops" over from parent context clone = clone.enable_role(role_, op) # Update context with information from visiting this choice's blocks enabled = collections.clone_collection(contexts[0].get_enabled_roles()) for c in contexts[1:]: tmp = c.get_enabled_roles() for role_, ops in tmp.items(): if role_ != subj: enabled[role_] |= ops for role_, ops in enabled.items(): # We only want the "intial ops", so if role_ was already enabled before # this choice, we don't need to record the ops we saw here if role_ not in prev.keys(): for op in ops: clone = clone.enable_role(role_, op) # Update potental operators (Section 4.6.8) map # # N.B. "potential operators" for parallel well-formedness; not "enabling # operators" (already treated above) potops = clone.get_operators() for c in contexts: # New potential operators from visiting blocks, add them all to the # existing map for (src, dest), ops in c.get_operators().items(): for op in ops: if (src, dest) not in potops.keys() or op not in potops[(src, dest)]: # need to collect all operators (for parallel check) from # each choice block as a set clone = clone.add_operator(src, dest, op) #Update reclabs? -- no: don't need to do reclabs because any in-scope #contlab should have been declared in an outer context; any contlab declared #inside the choice cannot possibly be carried over here for c in contexts: for lab in c.get_continue_labels(): clone = clone.add_continue_label(lab) # Reachability and (tail) recursion checks -- this needs to be revised to # properly conform to the langref rec_exitable = False # "Possibly exitable": choice has an exit for c in contexts: if c.get_rec_exitable(): rec_exitable = True break clone = clone.set_rec_exitable(rec_exitable) do_exitable = True for c in contexts: if not c.get_do_exitable(): do_exitable = False break clone = clone.set_do_exitable(do_exitable) for c in contexts: for contlab in c.get_continue_labels(): clone = clone.add_continue_label(contlab) scopes = clone.get_current_scopes() new = [] for c in contexts: for scope in c.get_current_scopes() - scopes: if scope in new: util.report_error("Bad scope: " + scope) new.append(scope) clone = clone.add_scope(scope) cv.set_context(clone.pop_globalchoice(node_))