float_library_extract.py (3888B)
1 #!/usr/bin/env python3 2 """Extract library declarations while preserving executable bodies. 3 4 Token dependency scanning conservatively includes matching names, including names 5 shadowed by local binders. Run explicitly to prepare an extraction and review its 6 output against the maintained library sources before accepting the changes. 7 """ 8 import hashlib 9 import json 10 from pathlib import Path 11 import re 12 13 ROOT=Path(__file__).resolve().parent.parent 14 SOURCES={ 15 'boundary':'bench/float-boundary.tri','working':'bench/float-working.tri', 16 'chains':'bench/float-chains.tri','ieee':'bench/float-ieee.tri', 17 'product_quotient':'bench/float-finite-product-quotient.tri', 18 'finite':'bench/float-finite.tri','adders':'bench/float-adders.tri', 19 'multiply':'bench/float-multiply.tri','near':'bench/float-near-jam.tri', 20 'aligned':'bench/float-aligned-quantize.tri','fast':'bench/float-quantize-fast.tri', 21 'quantize':'bench/float-quantize.tri','pipelines':'bench/float-pipelines.tri', 22 'kernels':'bench/float-significands.tri','layouts':'bench/float-layouts.tri'} 23 24 25 def parsed(path): 26 text=(ROOT/path).read_text() 27 imports=dict((alias,module) for module,alias in re.findall(r'^!import (\w+) as (\w+)$',text,re.M)) 28 exports=re.findall(r'^!export ([\w?]+)$',text,re.M) 29 # Keep executable text verbatim; omit historical benchmark commentary. 30 body='\n'.join(line for line in text.splitlines() if line and not line.startswith(('!','--')))+'\n' 31 starts=list(re.finditer(r'^([A-Za-z][\w?]*)[ \t]+[^\n=]*=',body,re.M)) 32 assert starts and starts[0].start()==0,path 33 defs={m[1]:body[m.start():starts[i+1].start() if i+1<len(starts) else len(body)] for i,m in enumerate(starts)} 34 assert len(defs)==len(starts),path 35 return imports,exports,defs 36 37 38 def extract(): 39 modules={m:parsed(p) for m,p in SOURCES.items()} 40 needed=set();external={m:set() for m in modules};pending=[('boundary',n) for n in modules['boundary'][1]] 41 external['boundary'].update(modules['boundary'][1]) 42 while pending: 43 m,n=pending.pop() 44 if (m,n) in needed:continue 45 needed.add((m,n));imports,_,defs=modules[m];body=defs[n] 46 for alias,name in re.findall(r'\b(\w+)\.([\w?]+)',body): 47 target=imports[alias] 48 if target=='native_math':continue 49 external[target].add(name);pending.append((target,name)) 50 unqualified=re.sub(r'\b\w+\.[\w?]+','',body) 51 for name in re.findall(r'[A-Za-z][\w?]*',unqualified): 52 if name in defs:pending.append((m,name)) 53 report={} 54 for m,(imports,_,defs) in modules.items(): 55 selected={n:body for n,body in defs.items() if (m,n) in needed} 56 if not selected:continue 57 body=''.join(selected.values());used={a for a,_ in re.findall(r'\b(\w+)\.([\w?]+)',body)} 58 header='-- Pure binary64 implementation; trusted internal helpers.\n' 59 if m=='boundary':header='-- Binary64 facade: checked word boundaries, trusted constructed values.\n' 60 for alias,target in imports.items(): 61 if alias in used:header+=f'!import {target if target=="native_math" else "binary64_"+target} as {alias}\n' 62 for name in sorted(external[m]):header+=f'!export {name}\n' 63 path='lib/math/binary64.tri' if m=='boundary' else f'lib/math/binary64/{m}.tri' 64 file=ROOT/path;file.parent.mkdir(parents=True,exist_ok=True);file.write_text(header+'\n'+body) 65 report[m]=dict(path=path,source=SOURCES[m],source_sha256=hashlib.sha256((ROOT/SOURCES[m]).read_bytes()).hexdigest(), 66 sha256=hashlib.sha256(file.read_bytes()).hexdigest(),declarations=list(selected),exports=sorted(external[m])) 67 (ROOT/'test/float-library-extraction.json').write_text(json.dumps(report,indent=2)+'\n') 68 print('Extracted',sum(len(r['declarations']) for r in report.values()),'declarations in',len(report),'modules') 69 70 if __name__=='__main__':extract()