Ejemplo n.º 1
0
        def make_varmgr(istoplevel=False):
            """Return a variable manager instance."""
            appfmt = syslx.View(module.apps.get(
                args.project).attrs)['appfmt'].s
            appfmt = diagutil.parse_fmt(appfmt)

            def new_var(var, name):
                """Outputs a new definition when VarManager makes a new variable."""

                #TODO dodgy, should be using context (look at syslseqs)
                if istoplevel:
                    template = 'state "{}" as X{}{} {{'
                else:
                    template = '  state "{}" as {}{}'
                    (_, _, name) = name.partition(' : ')

                app = module.apps[name]
                write(
                    template,
                    appfmt(appname=name,
                           **diagutil.attr_fmt_vars(app.attrs)).replace(
                               '\n', r'\n'), var,
                    ' <<highlight>>' if name in highlights else '')

            return diagutil.VarManager(new_var)
Ejemplo n.º 2
0
        def make_varmgr():
            """Return a variable manager instance."""
            appfmt = syslx.View(module.apps.get(
                args.project).attrs)['appfmt'].s
            appfmt = diagutil.parse_fmt(appfmt)

            def new_var(var, name):
                """Outputs a new definition when VarManager makes a new variable."""

                app = module.apps[name]
                write(
                    '[{}] as {}{}',
                    appfmt(appname=name_map.get(name, name),
                           **diagutil.attr_fmt_vars(app.attrs)).replace(
                               '\n', r'\n'), var,
                    ' <<highlight>>' if name in highlights else '')

            return diagutil.VarManager(new_var)
Ejemplo n.º 3
0
def _make_varmgr(module, appname, write):
    """Return a variable manager instance."""
    def new_var(var, name):
        """Outputs a new definition when VarManager makes a new variable."""
        app = module.apps[name]
        write('class "{}" as {} << (D,orchid) >> {{', name, var)
        typespec = module.apps.get(appname).types.get(name)
        assert typespec.WhichOneof('type') == 'tuple'
        fields = sorted(typespec.tuple.attr_defs.iteritems(),
                        key=_attr_sort_key)
        for (fieldname, fieldtype) in fields:
            which = fieldtype.WhichOneof('type')
            suffix = ''
            prefix = ''
            while which == 'list':
                fieldtype = fieldtype.list.type
                which = fieldtype.WhichOneof('type')
                suffix = '[]' + suffix

            if which == 'set':
                fieldtype = fieldtype.set
                which = fieldtype.WhichOneof('type')
                prefix = 'set <'
                suffix = '>' + suffix

            bold = False
            if which == 'primitive':
                typestr = fieldtype.Primitive.Name(fieldtype.primitive).lower()
            elif which == 'type_ref':
                typestr = '.'.join(fieldtype.type_ref.ref.path)
                bold = True
            else:
                typestr = '<color red>**{}**</color>'.format(which)
            typestr = prefix + typestr + suffix
            if bold:
                typestr = '**{}**'.format(typestr)
            write('+ {} : {}', fieldname, typestr)
        write('}}')

    return diagutil.VarManager(new_var)
Ejemplo n.º 4
0
def sequence_diag(module, params, log_integration=None):
    """Generate a sequence diagram.

  Params:
    module: sysl_pb2.Module
    params: SequenceDiagParams
    log_call: invoked for each visited call.
      def(app=sysl_pb2.Application(),
        stmt=sysl_pb2.Stmt(),
        patterns={str})
  """
    blackboxes = params.blackboxes or []
    already_visited = collections.defaultdict(int)

    write = _Writer(params.activations)
    var_names = []

    def new_var(var, appname):
        """Outputs a new definition when VarManager makes a new variable."""
        app = module.apps[appname]
        has_category = syslx.patterns(
            app.attrs) & {'human', 'cron', 'db', 'external', 'ui'}
        assert len(has_category) <= 1
        (order, agent) = {
            'human': (0, 'actor'),
            'ui': (1, 'boundary'),
            'cron': (2, 'control'),
            'db': (4, 'database'),
            'external': (5, 'control'),
        }.get(''.join(has_category), (3, 'control'))
        label = params.appfmt(appname=appname,
                              **diagutil.attr_fmt_vars(app.attrs)).replace(
                                  u'\n', ur'\n')
        var_names.append(
            ((order, int(var[1:])), u'{} "{}" as {}'.format(agent, label,
                                                            var)))

    var_name = diagutil.VarManager(new_var)

    def visit_endpoint(from_app,
                       appname,
                       epname,
                       uptos,
                       sender_patterns,
                       stmt=None,
                       deactivate=None):
        """Recursively visit an endpoint."""
        if from_app:
            sender = var_name(syslx.fmt_app_name(from_app.name))
        else:
            sender = '['
        agent = var_name(appname)
        app = module.apps.get(appname)
        endpt = app.endpoints.get(epname)
        assert endpt

        def visit_stmts(stmts, deactivate, last_parent_stmt):
            """Recursively visit a stmt list."""
            def block(last_stmt, block_stmts, fmt, *args):
                """Output a compound block."""
                write(fmt, *args)
                with write.indent():
                    return visit_stmts(block_stmts, deactivate, last_stmt)

            def block_with_end(last_stmt, block_stmts, fmt, *args):
                """Output a compound block, including the 'end' clause."""
                payload = block(last_stmt, block_stmts, fmt, *args)
                write('end')
                return payload

            payload = None

            for (i, stmt) in enumerate(stmts):
                last_stmt = last_parent_stmt and i == len(stmts) - 1
                if stmt.HasField('call'):
                    with write.indent():
                        payload = visit_endpoint(
                            app, syslx.fmt_app_name(stmt.call.target),
                            stmt.call.endpoint, uptos, app_patterns, stmt,
                            last_stmt and deactivate)
                elif stmt.HasField('action'):
                    write('{0} -> {0} : {1}', agent,
                          r'\n'.join(textwrap.wrap(stmt.action.action, 40)))
                elif stmt.HasField('cond'):
                    payload = block_with_end(last_stmt, stmt.cond.stmt,
                                             'opt {}', stmt.cond.test)
                elif stmt.HasField('loop'):
                    payload = block_with_end(
                        last_stmt, stmt.loop.stmt, 'loop {} {}',
                        stmt.loop.Mode.Name(stmt.loop.mode),
                        stmt.loop.criterion)
                elif stmt.HasField('loop_n'):
                    payload = block_with_end(last_stmt, stmt.loop_n.stmt,
                                             'loop {} times',
                                             stmt.loop_n.count)
                elif stmt.HasField('foreach'):
                    payload = block_with_end(last_stmt, stmt.foreach.stmt,
                                             'loop for each {}',
                                             stmt.foreach.collection)
                elif stmt.HasField('group'):
                    payload = block_with_end(last_stmt, stmt.group.stmt,
                                             'group {}', stmt.group.title)
                elif stmt.HasField('alt'):
                    prefix = 'alt'
                    for (j, choice) in enumerate(stmt.alt.choice):
                        last_alt_stmt = last_stmt and j == len(
                            stmt.alt.choice) - 1
                        payload = block(last_alt_stmt, choice.stmt, '{} {}',
                                        prefix, choice.cond)
                        prefix = 'else'
                    write('end')
                elif stmt.HasField('ret'):
                    write('{}<--{} : {}', sender, agent, stmt.ret.payload)
                else:
                    raise Exception('No statement!')

            return payload

        app_patterns = syslx.patterns(app.attrs)
        target_patterns = syslx.patterns(endpt.attrs)

        patterns = target_patterns

        human = 'human' in app_patterns
        human_sender = 'human' in sender_patterns
        cron = 'cron' in sender_patterns
        needs_int = not (human or human_sender or cron) and sender != agent
        # pdb.set_trace()
        label = re.sub(ur'^.*? -> ', u' ⬄ ',
                       r'\n'.join(textwrap.wrap(unicode(epname), 40)))

        cron = 'cron' in app_patterns

        if stmt:
            assert stmt.HasField('call')

            # pdb.set_trace()
            patterns = syslx.patterns(stmt.attrs) or patterns

            label = params.epfmt(
                epname=label,
                human='human' if human else '',
                human_sender='human sender' if human_sender else '',
                needs_int='needs_int' if needs_int else '',
                args=', '.join(p.name for p in stmt.call.arg),
                patterns=', '.join(sorted(patterns)),
                **diagutil.attr_fmt_vars(stmt.attrs)).replace('\n', r'\n')

        if not ((human and sender == '[') or cron):
            ep_patterns = syslx.patterns(endpt.attrs)

            icon = '<&timer> ' if 'cron' in ep_patterns else ''
            # pdb.set_trace()
            write('{}->{} : {}{}', sender, agent, icon, label)
            if log_integration and stmt:
                log_integration(app=from_app, stmt=stmt, patterns=patterns)

        payload = syslalgo.return_payload(endpt.stmt)
        calling_self = from_app and syslx.fmt_app_name(
            from_app.name) == appname
        if not calling_self and not payload and deactivate:
            deactivate()

        if len(endpt.stmt):
            hit_blackbox = False
            for (upto, comment) in itertools.chain(uptos.iteritems(),
                                                   already_visited.keys()):
                # Compare the common prefix of the current endpt and upto.
                upto_parts = upto.split(' <- ')
                if [appname, epname][:len(upto_parts)] == upto_parts:
                    hit_blackbox = True
                    if payload:
                        write.activate(agent)
                        if comment is not None:
                            write('note over {}: {}', agent, comment
                                  or 'see below')
                    else:
                        if comment is not None:
                            write('note {}: {}',
                                  'left' if sender > agent else 'right',
                                  comment or 'see below')
                    if payload:
                        write('{}<--{} : {}', sender, agent, payload)
                        write.deactivate(agent)
                    break

            if not hit_blackbox:
                with write.activated(agent, human or cron) as deactivate:
                    visiting = (appname + ' <- ' + epname, None)  #'see above')
                    already_visited[visiting] += 1
                    try:
                        return visit_stmts(endpt.stmt, deactivate, True)
                    finally:
                        already_visited[visiting] -= 1
                        if not already_visited[visiting]:
                            del already_visited[visiting]

    with write.uml():
        #write('scale max 8192 height')
        if params.title:
            write('title {}', params.title)

        app_eps = [
            re.match(r'(.*?)\s*<-\s*(.*?)(?:\s*\[upto\s+(.*)\])*$',
                     endpt).groups() for endpt in params.endpoints
        ]

        # Treat each endpoint as a blackbox for the other endpoints.
        uptos = {appname + ' <- ' + epname for (appname, epname, _) in app_eps}

        # Global blackboxes
        blackboxes = {app: comment for (app, comment) in blackboxes}

        for (appname, epname, upto) in app_eps:
            write('== {} <- {} ==', appname, epname)
            bbs = blackboxes.copy()
            for bbox in ({upto} if upto else
                         set()) | uptos - {appname + ' <- ' + epname}:
                bbs[bbox] = 'see below'
            already_visited.clear()
            visit_endpoint(None, appname, epname, bbs, [])
            write.deactivate_all()

        for (_, var) in sorted(var_names):
            write.head('{}', var)

    return str(write)