File size: 12,707 Bytes
2e4432d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | """Primitive numeric/metadata registry shared by independent execution engines.
No I/O, FFI, shell, eval or dynamic import is exposed by the language.
"""
import hashlib,json,math,operator
class ICLError(Exception):
def __init__(self,code,message,span=None):
self.code=code;self.message=message;self.span=span
super().__init__(f'{code}: {message}')
def as_dict(self):return {'code':self.code,'message':self.message,'span':self.span}
def canonical(x):return json.dumps(x,sort_keys=True,separators=(',',':'),ensure_ascii=False,allow_nan=False)
def digest(x):return hashlib.sha256(canonical(x).encode()).hexdigest()
DEFAULT_LIMITS={'max_steps':100000,'max_stack':128,'max_items':100000,'max_output':1000000,'max_tensor':4096}
class RuntimeContext:
def __init__(self,limits=None,policy=None):
self.limits=dict(DEFAULT_LIMITS)
if limits:
for k,v in limits.items():
if k not in self.limits or type(v)!=int or v<1 or v>DEFAULT_LIMITS[k]:raise ICLError('RESOURCE_POLICY','limits may only reduce defaults')
self.limits[k]=v
self.policy={} if policy is None else policy
if not isinstance(self.policy,dict):raise ICLError('RESOURCE_POLICY','policy must be object')
for action,permission in self.policy.items():
if not isinstance(action,str) or not isinstance(permission,dict) or set(permission)-{'allow','human_required','human_approved'}:raise ICLError('RESOURCE_POLICY','invalid policy descriptor')
if any(type(v)!=bool for v in permission.values()):raise ICLError('RESOURCE_POLICY','policy flags require strict booleans')
self.steps=0;self.trace=[];self.effects=[];self.prng=1
def step(self,op='',inputs=None,output=None):
self.steps+=1
if self.steps>self.limits['max_steps']:raise ICLError('FUEL_EXHAUSTED','step budget exceeded')
self.trace.append({'run_id':'deterministic','step':self.steps,'op_id':op,'input_hash':digest(inputs),'output_hash':digest(output),'state_ref':None,'effect_request':None,'effect_decision':None,'recovery_ref':None,'error_code':None,'clock_mode':'logical'})
def check_value(self,value):
count=0
def walk(v,depth=0):
nonlocal count
count+=1
if depth>128 or count>self.limits['max_items']:raise ICLError('MEMORY_LIMIT','value size/depth limit')
if isinstance(v,(list,tuple)):
for x in v:walk(x,depth+1)
elif isinstance(v,dict):
for x in v.values():walk(x,depth+1)
elif isinstance(v,float) and not math.isfinite(v):raise ICLError('NONFINITE','NaN/Inf forbidden')
elif type(v)==int and not -(1<<63)<=v<(1<<63):raise ICLError('OVERFLOW','Int64 overflow')
elif isinstance(v,str) and len(v.encode())>self.limits['max_output']:raise ICLError('OUTPUT_LIMIT','string too large')
walk(value)
if len(canonical(value).encode())>self.limits['max_output']:raise ICLError('OUTPUT_LIMIT','serialized value too large')
return value
def checked_num(v):
if type(v)==int and not -(1<<63)<=v<(1<<63):raise ICLError('OVERFLOW','Int64 overflow')
if isinstance(v,float) and not math.isfinite(v):raise ICLError('NONFINITE','NaN/Inf forbidden')
return v
def checked_binary(op,a,b):
if op in ('&&','||'):
if type(a)!=bool or type(b)!=bool:raise ICLError('TYPE','Bool operands required')
return a and b if op=='&&' else a or b
if op in ('==','!='):
if type(a)!=type(b):raise ICLError('TYPE','same types required')
return a==b if op=='==' else a!=b
if op in ('<','<=','>','>='):
if type(a) not in (int,float,str) or type(a)!=type(b):raise ICLError('TYPE','homogeneous ordered scalar operands required')
return {'<':operator.lt,'<=':operator.le,'>':operator.gt,'>=':operator.ge}[op](a,b)
if op=='+' and type(a)==type(b)==str:return a+b
if type(a) not in (int,float) or type(a)!=type(b):raise ICLError('TYPE','homogeneous numeric operands required')
if op in ('/','%') and b==0:raise ICLError('DIVISION_BY_ZERO','zero divisor')
if op=='+':v=a+b
elif op=='-':v=a-b
elif op=='*':v=a*b
elif op=='/':v=(abs(a)//abs(b))*(-1 if (a<0)!=(b<0) else 1) if type(a)==int else a/b
elif op=='%':v=a-((abs(a)//abs(b))*(-1 if (a<0)!=(b<0) else 1))*b if type(a)==int else math.fmod(a,b)
else:raise ICLError('UNSUPPORTED_OP',op)
return checked_num(v)
def checked_unary(op,a):
if op=='!' and type(a)==bool:return not a
if op=='-' and type(a) in (int,float):return checked_num(-a)
raise ICLError('TYPE','invalid unary operand')
def tensor(data,shape,ctx):
if not isinstance(shape,list) or not 1<=len(shape)<=3 or any(type(x)!=int or x<1 for x in shape):raise ICLError('SHAPE','rank 1..3, positive dimensions required')
n=math.prod(shape)
if n>ctx.limits['max_tensor']:raise ICLError('TENSOR_LIMIT','tensor element limit')
if not isinstance(data,list) or n!=len(data):raise ICLError('SHAPE','data length mismatch')
if any(type(x)!=float or not math.isfinite(x) for x in data):raise ICLError('TYPE','finite Float64 tensor data required')
return {'shape':shape[:],'data':data[:]}
def istensor(x):return isinstance(x,dict) and set(x)=={'shape','data'}
def validate_tensor(x,ctx):
if not istensor(x):raise ICLError('TYPE','Tensor required')
return tensor(x['data'],x['shape'],ctx)
def _builtin(name,args,ctx):
def n(count):
if len(args)!=count:raise ICLError('TYPE',f'{name} expects {count} arguments')
if name=='len':n(1);return len(args[0])
if name=='abs':n(1);return checked_num(abs(args[0]))
if name in ('min','max'):n(2);return min(args) if name=='min' else max(args)
if name=='to_float':n(1);return float(args[0])
if name=='tensor':n(2);return tensor(args[0],args[1],ctx)
if name in ('matmul','add','sub','mul'):
n(2);a,b=[validate_tensor(x,ctx) for x in args]
if name=='matmul':
if len(a['shape'])!=2 or len(b['shape'])!=2 or a['shape'][1]!=b['shape'][0]:raise ICLError('SHAPE','matmul dimensions')
m,k=a['shape'];_,p=b['shape']
if m*p>ctx.limits['max_tensor']:raise ICLError('TENSOR_LIMIT','matmul output exceeds tensor limit before allocation')
return tensor([float(sum(a['data'][i*k+t]*b['data'][t*p+j] for t in range(k))) for i in range(m) for j in range(p)],[m,p],ctx)
if a['shape']!=b['shape']:raise ICLError('SHAPE','elementwise shapes differ')
op={'add':operator.add,'sub':operator.sub,'mul':operator.mul}[name]
return tensor([op(x,y) for x,y in zip(a['data'],b['data'])],a['shape'],ctx)
if name in ('relu','tanh','normalize','softmax'):
n(1);a=validate_tensor(args[0],ctx);d=a['data'];w=a['shape'][-1]
if name=='relu':d=[max(0.0,x) for x in d]
elif name=='tanh':d=[math.tanh(x) for x in d]
else:
out=[]
for j in range(0,len(d),w):
r=d[j:j+w]
if name=='softmax':z=[math.exp(x-max(r)) for x in r];s=sum(z);out.extend(x/s for x in z)
else:
mean=checked_num(sum(r)/w)
var=checked_num(sum((x-mean)**2 for x in r)/w)
out.extend((x-mean)/math.sqrt(var+1e-5) for x in r)
d=out
return tensor(d,a['shape'],ctx)
if name=='reshape':n(2);a=validate_tensor(args[0],ctx);return tensor(a['data'],args[1],ctx)
if name=='sum':n(1);a=validate_tensor(args[0],ctx);return checked_num(float(sum(a['data'])))
if name=='some':n(1);return {'tag':'Some','value':args[0]}
if name=='none_int':n(0);return {'tag':'None','value':None}
if name=='ok':n(1);return {'tag':'Ok','value':args[0]}
if name=='err_int':n(1);return {'tag':'Err','error':args[0]}
if name=='unwrap':
n(1);a=args[0]
if a.get('tag') not in ('Some','Ok'):raise ICLError('UNWRAP','empty/Err cannot unwrap')
return a['value']
if name=='is_some':n(1);return args[0]['tag']=='Some'
if name=='observer':n(1);return {'tag':'Observer','id':args[0]}
if name=='context':n(2);return {'tag':'Context','frame':args[0],'unit':args[1]}
if name=='provenance':n(1);return {'tag':'ProvenanceRef','source_id':args[0],'verified':False}
if name=='represent':
n(4);v,o,f,u=args
return {'tag':'Representation','value':v,'observer':o,'frame':f,'unit':u,'source_hash':digest(v),'provenance':{'status':'LOCAL_COMPUTATION','claim':'hash_is_integrity_only'}}
if name=='repr_value':n(1);return args[0]['value']
if name=='repr_add':
n(2);a,b=args
for field,code in [('observer','OBSERVER_MISMATCH'),('frame','FRAME_MISMATCH'),('unit','UNIT_MISMATCH')]:
if a[field]!=b[field]:raise ICLError(code,field+' mismatch; explicit conversion required')
return builtin('represent',[checked_binary('+',a['value'],b['value']),a['observer'],a['frame'],a['unit']],ctx)
if name=='convert_frame':
n(4);r,new,offset,protocol=args
if protocol!='affine_translation_v1':raise ICLError('NEEDS_EVIDENCE','unregistered transform protocol')
out=builtin('represent',[checked_binary('+',r['value'],offset),r['observer'],new,r['unit']],ctx)
out['provenance']={'source_hash':digest(r),'protocol':protocol,'offset':offset};return out
if name=='observe_mod':
n(3);x,m,o=args
if m<=0:raise ICLError('DOMAIN','positive modulus required')
r=builtin('represent',[x%m,o,'scalar','dimensionless'],ctx);r['modulus']=m;r['source_hash']=None;r['ambiguous']=True;return r
if name=='make_witness':
n(2);x,m=args
if m<=0:raise ICLError('DOMAIN','positive modulus required')
payload={'tag':'RecoveryWitness','quotient':x//m,'modulus':m,'remainder':x%m};payload['sha256']=digest(payload);payload['payload_bytes']=len(canonical(payload).encode());return payload
if name=='recover':
n(2);r,w=args
if w.get('tag')!='RecoveryWitness':raise ICLError('WITNESS_MISSING','witness required')
p={k:w[k] for k in ('tag','quotient','modulus','remainder')}
if digest(p)!=w.get('sha256'):raise ICLError('WITNESS_CORRUPT','witness checksum')
if r.get('modulus')!=w['modulus'] or r['value']!=w['remainder']:raise ICLError('WITNESS_CORRUPT','witness measurement mismatch')
return {'tag':'Exact','value':checked_num(w['quotient']*w['modulus']+w['remainder']),'witness_bytes':w['payload_bytes'],'scope':'declared_integer_modulo_protocol'}
if name=='recover_without_witness':n(1);raise ICLError('NON_IDENTIFIABLE','measurement has multiple compatible sources')
if name=='exact_value':n(1);return args[0]['value']
if name=='approx':
n(2)
if args[1]<0:raise ICLError('DOMAIN','nonnegative error bound required')
return {'tag':'Approx','value':args[0],'error_bound':args[1]}
if name=='approx_value':n(1);return args[0]['value']
if name=='request_effect':
n(2);action,payload=args;permission=ctx.policy.get(action,{})
allowed=action=='journal' and permission.get('allow') is True
if permission.get('human_required') is True and permission.get('human_approved') is not True:allowed=False;code='HUMAN_APPROVAL_REQUIRED'
else:code='EFFECT_DENIED'
event={'action':action,'payload_hash':digest(payload),'decision':'ALLOWED_LOCAL_JOURNAL' if allowed else 'DENIED','external_executed':False}
ctx.effects.append(event)
if not allowed:raise ICLError(code,'trusted host policy denied action')
return True
if name=='random_int':
n(1)
if args[0]<=0:raise ICLError('DOMAIN','positive PRNG range')
ctx.prng=(1103515245*ctx.prng+12345)%(1<<31);return ctx.prng%args[0]
raise ICLError('NAME','unknown builtin '+name)
def builtin(name,args,ctx):
"""Convert host primitive failures into bounded language diagnostics."""
try:return _builtin(name,args,ctx)
except (OverflowError,ZeroDivisionError):
raise ICLError('NONFINITE','numeric primitive overflow or undefined finite result') from None
except (TypeError,ValueError,KeyError,IndexError,AttributeError):
raise ICLError('TYPE','malformed primitive input for '+str(name)) from None
BUILTINS={'len','abs','min','max','to_float','tensor','matmul','add','sub','mul','relu','tanh','normalize','softmax','reshape','sum','some','none_int','ok','err_int','unwrap','is_some','observer','context','provenance','represent','repr_value','repr_add','convert_frame','observe_mod','make_witness','recover','recover_without_witness','exact_value','approx','approx_value','request_effect','random_int'}
|