|
4 | 4 | import sys, os, json, subprocess, glob, re |
5 | 5 | S='/tmp/claude-0/-home-user/8a9da608-aa27-5449-8306-1fae9426f9b9/scratchpad'; R='/home/user/Own.NET' |
6 | 6 | pid=sys.argv[1]; d=f'{S}/lab/disc/libs/{pid}'; acq=json.load(open(f'{d}/acquire.json')) |
| 7 | +open(f'{d}/src/__GlobalUsings.cs','w').write('// synthesised for the discovery derivation: the SDK implicit usings (ImplicitUsings=enable) the fetched files rely on\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.IO;\nglobal using System.Linq;\nglobal using System.Net.Http;\nglobal using System.Threading;\nglobal using System.Threading.Tasks;\n') |
7 | 8 | src=sorted(glob.glob(f'{d}/src/**/*.cs', recursive=True)) |
8 | 9 | env={**os.environ,'PATH':'/root/.dotnet:'+os.environ['PATH'],'DOTNET_NOLOGO':'1','DOTNET_CLI_TELEMETRY_OPTOUT':'1','PYTHONPATH':R, |
9 | 10 | 'OWEN_RE_BODY':'1','OWEN_RE_MINTED_RETURN':'1','OWEN_RE_MIXED_RETURN':'1','OWEN_RE_DUMP_EFFECTS':f'{d}/dump.json'} |
|
16 | 17 | summ=subprocess.run(['python3','-m','ownlang','summaries',f'{d}/facts.json'],cwd=R,capture_output=True,text=True,env=env).stdout |
17 | 18 | try: summaries=json.loads(summ)['summaries'] |
18 | 19 | except Exception: summaries=[] |
| 20 | +# per-file union (E1/E2 proofs are local to a method body; a curated source SUBSET can make a created type's |
| 21 | +# declaration incomplete and lose the whole-set record, so each file is also derived alone against the package |
| 22 | +# assembly and the fresh/release results are unioned; the provenance stays BODY_PROVED) |
| 23 | +perfile_fresh=set(); perfile_rel=[] |
| 24 | +for f in src: |
| 25 | + argv1=['dotnet',f'{R}/frontend/roslyn/OwnSharp.Extractor/bin/Release/net8.0/ownsharp-extract.dll','--flow-locals',f,'-o',f'{d}/facts.one.json'] |
| 26 | + if refdir: argv1+=['--ref-dir',refdir] |
| 27 | + e1={**env,'OWEN_RE_DUMP_EFFECTS':f'{d}/dump.one.json'} |
| 28 | + subprocess.run(argv1,cwd=R,capture_output=True,text=True,env=e1) |
| 29 | + s1=subprocess.run(['python3','-m','ownlang','summaries',f'{d}/facts.one.json'],cwd=R,capture_output=True,text=True,env=env).stdout |
| 30 | + try: |
| 31 | + for s in json.loads(s1)['summaries']: |
| 32 | + if s.get('returns',{}).get('owned')=='fresh': perfile_fresh.add(s['method']) |
| 33 | + except Exception: pass |
| 34 | + try: |
| 35 | + for e in json.load(open(f'{d}/dump.one.json')).get('receiver_release',[]): |
| 36 | + if e.get('releases'): perfile_rel.append(e) |
| 37 | + except Exception: pass |
| 38 | +whole_fresh={s['method'] for s in summaries if s.get('returns',{}).get('owned')=='fresh'} |
| 39 | +for m in sorted(perfile_fresh-whole_fresh): |
| 40 | + summaries.append({'method':m,'returns':{'owned':'fresh'},'source':'inferred (per-file run)'}) |
19 | 41 | api=json.load(open(f'{d}/api.json')) if os.path.exists(f'{d}/api.json') else {'factories':[],'release_name_candidates':[],'types':[]} |
20 | 42 | public_callables={f['callable'] for f in api['factories']} | {r['callable'] for r in api['release_name_candidates']} | {f"{t['type']}.Dispose" for t in api['types']} |
21 | 43 | public_types={t['type'] for t in api['types']} |
|
29 | 51 | if m in public_callables and (m,'fresh') not in seen: |
30 | 52 | seen.add((m,'fresh')); rows.append({'callable':m,'effect':'return_fresh_owned','provenance':'BODY_PROVED','assembly':{'name':asm,'mvid':mvid},'derived_from':f"{acq.get('repository_url')}@{acq.get('repository_commit')} via E1/E3 ({s.get('source')})"}) |
31 | 53 | dump=json.load(open(f'{d}/dump.json')) if os.path.exists(f'{d}/dump.json') else {} |
| 54 | +seen_rel={(e['callable'],e.get('arity')) for e in dump.get('receiver_release',[])} |
| 55 | +for e in perfile_rel: |
| 56 | + if (e['callable'],e.get('arity')) not in seen_rel: dump.setdefault('receiver_release',[]).append(e); seen_rel.add((e['callable'],e.get('arity'))) |
32 | 57 | for e in dump.get('receiver_release',[]): |
33 | 58 | if e.get('releases') and e['callable'] in public_callables and not e['callable'].endswith('.Dispose') and (e['callable'],e.get('arity')) not in seen: |
34 | 59 | seen.add((e['callable'],e.get('arity'))); rows.append({'callable':e['callable'],'effect':'receiver_terminal_release','arity':e.get('arity'),'provenance':'BODY_PROVED','assembly':{'name':asm,'mvid':mvid},'derived_from':f"{acq.get('repository_url')}@{acq.get('repository_commit')} via E2"}) |
|
38 | 63 | fresh_all=[s['method'] for s in summaries if s.get('returns',{}).get('owned')=='fresh'] |
39 | 64 | fresh_public_missing=[s['method'] for s in summaries if s.get('returns',{}).get('owned')=='fresh' and s['method'].split('(')[0] not in public_callables] |
40 | 65 | rel_all=[e['callable'] for e in dump.get('receiver_release',[]) if e.get('releases')] |
41 | | -json.dump({'source_files':len(src),'extractor_stats':stats,'re_body_census':census.group(1) if census else None,'fresh_summaries_all':fresh_all,'receiver_release_all':rel_all,'fresh_not_public_surface':fresh_public_missing,'instance_methods_evaluated':dump.get('instance_methods_evaluated'),'public_rows':len(rows)},open(f'{d}/derive-summary.json','w'),indent=1) |
| 66 | +json.dump({'source_files':len(src),'perfile_union_added_fresh':sorted(perfile_fresh-whole_fresh),'extractor_stats':stats,'re_body_census':census.group(1) if census else None,'fresh_summaries_all':fresh_all,'receiver_release_all':rel_all,'fresh_not_public_surface':fresh_public_missing,'instance_methods_evaluated':dump.get('instance_methods_evaluated'),'public_rows':len(rows)},open(f'{d}/derive-summary.json','w'),indent=1) |
42 | 67 | print(json.dumps({'package':pid,'files':len(src),'stats':stats,'census':census.group(1) if census else None,'fresh_all':len(fresh_all),'release_all':len(rel_all),'public_rows':len(rows)})) |
43 | 68 | for x in rows: print(' ROW', x['effect'], x['callable'], x.get('arity','')) |
0 commit comments