#!/usr/bin/env python3
"""Analyze the synthetic single-step traces into per-opcode summaries."""
import collections, json, re, sys

PATH = sys.argv[1] if len(sys.argv) > 1 else '/tmp/opencode/exec2.txt'


def load(path):
    tests = {}
    cur = None
    for line in open(path):
        f = line.rstrip('\n').split('\t')
        if f[0] == 'B':
            cur = (int(f[2]), f[3])
            tests[cur] = {'id': int(f[1]), 'cursor0': int(f[4]), 'ev': []}
        elif f[0] == 'E' and cur:
            tid = int(f[1])
            tests[cur]['ev'].append(f[2:])
    return tests


def summarize(ev):
    out = {'pc': [], 'reads': [], 'writes': [], 'k': [], 'sidx': [], 'idx': [],
           'ops': [], 'state': [], 'err': None, 'cursor': None, 'raw': []}
    seen_pc = False
    for e in ev:
        kind = e[0]
        if kind == 'PC':
            seen_pc = True
            out['pc'].append(int(e[1]))
        elif not seen_pc:
            continue
        elif kind == 'R':
            out['reads'].append(int(e[1]))
        elif kind == 'W':
            out['writes'].append((int(e[1]), e[2]))
        elif kind in ('K7', 'K8', 'K9'):
            out['k'].append((kind, int(e[1]), e[2]))
        elif kind == 'SIDX':
            out['sidx'].append((e[1], e[2], e[3]))
        elif kind == 'IDX':
            out['idx'].append((e[1], e[2]))
        elif kind == 'OP':
            out['ops'].append(e[1])
        elif kind == 'S':
            out['state'].append((int(e[1]), int(e[2])))
        elif kind == 'ERR':
            out['err'] = e[1] if len(e) > 1 else ''
        elif kind == 'CURSOR':
            out['cursor'] = (int(e[1]), int(e[2]))
        elif kind == 'CALL':
            out['ops'].append('call(%s args)' % e[2])
    return out


def main():
    tests = load(PATH)
    ops = sorted({op for op, _ in tests})
    rows = []
    for op in ops:
        p = summarize(tests[(op, 'proxy')]['ev'])
        n = summarize(tests[(op, 'num')]['ev'])
        s = summarize(tests[(op, 'str')]['ev'])
        b = summarize(tests[(op, 'buf')]['ev'])
        pc = p['pc'][1] if len(p['pc']) > 1 else None
        rows.append((op, p, n, s, b, pc))
    json.dump({str(op): {'proxy': p, 'num': n, 'str': s, 'buf': b, 'pc': pc}
               for op, p, n, s, b, pc in rows},
              open('/tmp/opencode/exec_summary.json', 'w'), indent=0)
    for op, p, n, s, b, pc in rows:
        reads = ','.join(str(x) for x in sorted(set(p['reads'])))
        writes = ' '.join('%d<=%s' % (k, v) for k, v in p['writes'])
        k = ' '.join('%s[%d]=%s' % (a, b_, c) for a, b_, c in p['k'])
        st = ' '.join('S%d/%d' % x for x in p['state'])
        ops = ','.join(p['ops'])
        idx = ' '.join('%s[%s]' % x for x in p['idx'])
        sidx = ' '.join('%s[%s]=%s' % x for x in p['sidx'])
        err = p['err'] or ''
        print('%3d pc%-6s r[%s] %s | %s | %s | %s | idx %s | sidx %s | %s'
              % (op, pc, reads, writes, k, st, ops, idx, sidx, err[:60]))


if __name__ == '__main__':
    main()
