PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB`Mini Shell

HOME


Mini Shell 1.0
DIR:/proc/thread-self/root/opt/cloudlinux/venv/lib/python3.11/site-packages/guppy/gsl/
Upload File :
Current File : //proc/thread-self/root/opt/cloudlinux/venv/lib/python3.11/site-packages/guppy/gsl/Main.py
from guppy.etc.Descriptor import property_nondata
from guppy.gsl.Exceptions import *


class SpecEnv:
    def __init__(self, mod):
        self.mod = mod
        self.imported_packages = {}
        self.importing_packages = {}
        self.error_reports = []
        self.num_errors = 0
        self.num_warnings = 0

    def errmsg_context(self, context):
        linetext = ''
        filename = '<unknown file>'
        if context is not None:
            node = context      # Assume it's a node - that's all we use for now
            lineno = node.index + 1
            src = node.src
            if src is not None:
                filename = src.filename
                linetext = src.get_line(index=context.index)
            print('%s:%s:' % (filename, lineno))
            if linetext:
                print('    %r' % linetext)

    def error(self, message, context=None, exception=ReportedError, more=(), harmless=0):
        self.error_reports.append(
            (message, context, exception, more, harmless))
        if harmless:
            self.num_warnings += 1
        else:
            self.num_errors += 1

        self.errmsg_context(context)
        if harmless:
            print('*   %s' % message)
        else:
            print('*** %s' % message)
        print()

        for msg, ctx in more:
            self.errmsg_context(ctx)
            print('    %s' % msg)
            print()

        if self.debug:
            import pdb
            pdb.set_trace()
        else:
            if self.num_errors >= self.max_errors:
                raise TooManyErrors('Too many errors, giving up')
            if exception is not None:
                raise exception

    def get_filers(self, documents):
        filers = []
        for d in documents:
            filers.extend(d.get_filers(self.output_dir))
        return filers

    def import_package(self, name, context):
        pac = self.imported_packages.get(name)
        if pac is None:
            if name in self.importing_packages:
                self.error('Invalid mutual import involving packages %r' % (
                    list(self.importing_packages.keys()),), context)
            self.importing_packages[name] = 1
            filename = name.replace('.', self.mod.IO.path.sep)+'.gsl'
            ip = self.package_of_filename(filename, name)
            pac = self.mkPackage(ip)
            self.imported_packages[name] = pac
            del self.importing_packages[name]
        return pac

    def link_documents(self, documents):
        defines = {}

        links = {}

        def walk(node):
            t = node.tag
            if t == 'link_to':
                name = node.arg.strip()
                links.setdefault(name, []).append((d, node))
            elif t == 'define':
                name = node.arg.strip()
                defines.setdefault(name, []).append((d, node))
            elif t == 'to_tester_only':
                return
            for ch in node.children:
                walk(ch)

        for d in documents:
            node = d.get_result()
            walk(node)

        for name, ds in list(defines.items()):
            if len(ds) > 1:
                print('Duplicate definition of name %r, defined in:' % name)
                for (d, node) in ds:
                    print('    %s line %s' % (d.get_doc_name(), node.index+1))
                print('Will use the first one.')

        nodefs = []

        for name, ds in list(links.items()):
            if name not in defines:
                used = {}
                for (d, node) in ds:
                    used[d.get_doc_name()] = 1
                    node.tag = 'link_to_unresolved'
                used = list(used.keys())
                used.sort()
                used = ', '.join(used)
                nodefs.append('%s used in %s' % (name, used))
            else:
                defd, defnode = defines[name][0]
                for (d, node) in ds:
                    if d is defd:
                        node.tag = 'link_to_local'
                    else:
                        node.tag = 'link_to_extern'
                        node.children = (defd.doc_name_node,)+node.children
        if nodefs:
            nodefs.sort()
            print('Unresolved links:')
            for nd in nodefs:
                print('  ', nd)

    def mkPackage(self, sub):
        pac = PackageDescription(self, sub, sub)
        pac.output_dir = self.output_dir
        pac.resolve_all()
        return pac

    def package_of_filename(self, filename, packname=None, nostrip=1, input_string=None):
        mod = self.mod
        if packname is None:
            if filename.endswith('.gsl'):
                packname = filename[:-4]
            else:
                packname = filename
            packname = packname.replace(mod.IO.path.sep, '.')
        if self.input_dir:
            filename = mod.IO.path.join(self.input_dir, filename)
        else:
            filename = mod.IO.path.abspath(filename)
        if input_string is not None:
            data = input_string
        else:
            data = mod.IO.read_file(filename)
        md5 = mod.md5()
        md5.update(b'.filename: %s\n' % filename.encode('utf-8'))
        md5.update(b'.packname: : %s\n' % packname.encode('utf-8'))
        md5.update(data.encode('utf-8'))
        digest = md5.digest()
        if digest in mod.package_cache:
            return mod.package_cache[digest]

        node = mod.SpecNodes.node_of_string(data, filename, nostrip=nostrip)
        numerr = self.num_errors
        print('Making package subject %r' % packname)
        package = PackageSubject(mod, self, node, packname, filename)
        if numerr == self.num_errors:
            mod.package_cache[digest] = package
        return package

    def process_main(self, filename, input_dir=None, output_dir=None, debug=False, max_errors=None,
                     process_despite_errors=False, raise_at_errors=False,
                     input_string=None
                     ):
        if input_dir is None:
            input_dir = self.mod.input_dir
        self.input_dir = input_dir
        if output_dir is None:
            output_dir = '/tmp'
        self.output_dir = output_dir
        self.debug = debug
        if max_errors is None:
            max_errors = self.mod.max_errors
        self.max_errors = max_errors

        try:
            pac = self.mkPackage(self.package_of_filename(
                filename, input_string=input_string))
            documents = pac.get_documents()
            if not documents:
                self.error('No documents specified.',
                           exception=None, harmless=1)
            if not self.num_errors or process_despite_errors:
                print('Linking')
                self.link_documents(documents)
            if not self.num_errors or process_despite_errors:
                filers = self.get_filers(documents)
        except TooManyErrors:
            giving_up = ' giving up --'
        else:
            giving_up = ''
        if not self.num_errors:
            for filer in filers:
                f = self.mod.Filer.filer(filer)
                print('Writing: ', ', '.join(list(f.writefile_names)))
                f.write()
        if self.num_warnings:
            print('*   %d warning%s reported.' % (
                self.num_warnings, 's'[:self.num_warnings > 1]))
        if self.num_errors:
            print('*** %d error%s reported --%s no files written.' % (
                self.num_errors, 's'[:self.num_errors > 1], giving_up))
            if raise_at_errors:
                raise HadReportedError('Some error has been reported.')


class UntypedDescription:
    def __init__(self, env, tgt, src):
        self.env = env
        self.pac = env.pac
        self.mod = env.mod
        self.tgt = tgt
        self.src = src

    def combine_with_subject(self, subject):
        self.combined_subjects.append(subject)

    def resolve_all(self):
        self.resolve_primary()
        self.resolve_lookuped()

    def resolve_primary(self):
        self.resolve_type()
        self.resolve_tgt()

    def resolve_type(self):
        dc = self.tgt.description_class
        if not hasattr(dc, 'd_tag'):
            self.d_tag = self.tgt.tag
        self.tgtfullname = self.mod.tgt_prefix+self.tgt.fullname
        self.tgtnode = self.tgt.node
        self.tgtlastname = self.tgt.lastname
        self.srcnode = self.tgt.node
        self.srcfullname = self.src.fullname
        self.srclastname = self.tgt.lastname

        self.__class__ = dc


class Description:
    d_max_occur = None  # Max occurence as an aspect if a number
    d_sub = ()  # Tags of allowed sub-aspects
    d_type = 'other'
    d_is_def = 0
    is_lookuped = False
    is_synthetic = False  # Set if it was made not to correspond with a user node
    the_less_specific_descr = None
    args = ()

    def aspects_extend(self, as_):
        for asp in as_:
            try:
                k = asp.src.definame
                # k = asp.tgt.definame # Humm
                if k:
                    w = self.localview.get(k)
                    if w:
                        if w is asp:
                            # May happen eg as in test16, for a product
                            # But it is somewhat mystical.
                            continue
                        self.error('Duplicate aspect %r (may be correct in future).' % (k,),
                                   w.src.node,
                                   DuplicateError)
                    self.localview[k] = asp
                bn = self.aspects_by_tag.setdefault(asp.d_tag, [])
                oc = asp.d_max_occur
                if oc is not None:
                    if len(bn) + 1 > oc:
                        self.error('More than %d %r aspects.' % (
                            oc, asp.d_tag), asp.src.node)
                bn.append(asp)
                self.aspects.append(asp)
            except ReportedError:
                pass

    def aspects_extend_by_subjects(self, subjects):
        for v in subjects:
            try:
                asp = UntypedDescription(self, v, v)
                asp.resolve_primary()
                self.aspects_extend((asp,))
            except ReportedError:
                pass

    def deftgt(self, forme=None):
        if forme is None:
            forme = self

        try:
            tgtview = self.tgtview
        except AttributeError:
            self.env.deftgt(forme)
        else:
            if forme.tgtfullname in tgtview:
                self.error('Duplicate definition of %r' %
                           forme.tgtfullname, forme.src.node)
            tgtview[forme.tgtfullname] = forme

    def error(self, msg, node=None, exception=ReportedError, **kwds):
        return self.pac.env.error(msg, node, exception, **kwds)

    def resolve_lookuped(self):
        if not self.is_lookuped:
            self.is_lookuped = 1
            self.resolve_aspects()

    def resolve_tgt(self):
        self.deftgt()

    def find_aspects(self, tag='*', *tags):
        al = []
        tag = tag.replace(' ', '_')
        if tag in ('*', 'arg'):
            for a in self.args:
                a.resolve_lookuped()
                al.append(a)
            if tag == '*':
                for a in self.aspects:
                    a.resolve_lookuped()
                    al.append(a)
                return al
        tags = (tag,) + tags
        for a in self.aspects:
            if a.d_tag in tags:
                a.resolve_lookuped()
                al.append(a)
        return al

    def find_arg_aspects(self):
        al = []
        for a in self.args:
            a.resolve_lookuped()
            al.append(a)
        for a in self.aspects:
            if a.d_tag in ('arg', 'seq', 'repeat', 'alt', 'args', 'optionals', 'key_arg',
                           'draw', 'no_arg'):
                a.resolve_lookuped()
                al.append(a)
        return al

    def find_kind_aspects(self):
        kas = []
        for asp in self.find_aspects('*'):
            if asp.d_tag in ('attribute', 'mapping', 'kind', 'either', 'kind_of', 'superkind',
                             'superkind_of'):
                kas.append(asp)
            else:
                pass
        return kas

    def merge_policy(self, descrs):
        return descrs

    def get_descr_for_aspect(self, aspect):
        if not self.aspects and self.the_less_specific_descr is not None:
            return self.the_less_specific_descr.get_descr_for_aspect(aspect)
        return self

    def get_atom_beams(self):
        aspects = self.find_aspects('*')
        aks = []
        for asp in aspects:
            if asp.d_tag in ('attribute', 'mapping', 'either',  'operator',
                             'inplace_operator', 'reverse_operator', 'function_operator',
                             'delitem', 'getitem', 'setitem',
                             ):
                aks.append(beam(self, asp))
            elif asp.d_tag in ('kind', 'kind_of', 'subkind_of') and asp is not self:
                a = beam(self, asp)
                for b in asp.get_atom_beams():
                    aks.append(a + b)
        return aks

    def get_aspects_kind(self, aspects=None):
        if aspects is None:
            aspects = self.find_aspects('*')
        aks = []
        for asp in aspects:
            if asp.d_tag in ('attribute', 'mapping', 'either',
                             'operator', 'inplace_operator', 'reverse_operator', 'function_operator',
                             'delitem', 'getitem', 'setitem',
                             ):
                aks.append(asp)
            elif asp.d_tag in ('kind', 'kind_of', 'subkind_of') and asp is not self:
                aks.extend(asp.get_atom_kinds())
        return aks

    def get_atom_kinds(self):
        return self.get_aspects_kind([self] + self.find_aspects('*'))

    def get_examples(self, get_all=False):
        examples = []
        exs = self.find_aspects('example')
        for ex in exs:
            examples.extend(ex.get_examples())
        return examples

    def get_re(self, opt):
        if opt.get('get_examples'):
            exres = [self.mod.RE.Single(x) for x in self.get_examples()]
            if not exres:
                self.error('Test coverage error: no examples specified.',
                           self.tgt.node,
                           CoverageError)
            return self.mod.RE.Union(*exres)
        else:
            return self.mod.RE.Single(self)

    def get_most_specific_descrs(self, descrs):
        nds = []
        for d in descrs:
            nds = [x for x in nds if not d.is_more_specific_than(x)]
            for x in nds:
                if x is d:
                    break
                if x.is_more_specific_than(d):
                    break
            else:
                nds.append(d)
        return nds

    def get_package(self):
        return self.pac

    def is_more_specific_than(self, d):
        r = self.the_less_specific_descr
        return r is d or (r is not None and r.is_more_specific_than(d))

    def get_self_name(self):
        def find(e):
            sa = e.find_aspects('self')
            if sa:
                # length = 1, has been checked
                assert len(sa) == 1
                return sa[0].src.node.arg.strip()
            if e.d_tag != 'package':
                return find(e.env)
            return None
        return find(self)

    def gen_description_doc(self, out):
        ds = self.find_aspects('description')
        if not ds:
            out.gen_text('<NO DESCRIPTION OF %r>' % self.tgtfullname)
        else:
            for d in ds:
                d.gen_doc(out)

    def get_id_name(self):
        return self.tgtfullname

    def get_link_name(self):
        return self.tgtfullname

    def get_local_name(self):
        return self.srclastname

    def get_test_name(self):
        return self.tgtfullname

    def get_name(self):
        return self.tgtfullname

    def get_Name(self):
        # To be used in Name of doc.
        n = self.find_aspects('name')
        if not n:
            name = self.tgtlastname
        else:
            name = n.tgt.node.arg.strip()
        return name

    def get_descr_by_subject(self, subject):
        return self.pac.get_descr_by_subject(subject)

    def init_localview(self, only_vars=0):
        self.localview = {}
        self.aspects = []
        self.aspects_by_tag = {}

        if not only_vars:
            self.aspects_extend_by_subjects(self.tgt.aspects)

    def resolve_aspects(self):
        self.init_localview()
        if self.src.args:
            self.args = [self.env.get_descr_by_subject(
                arg) for arg in self.src.args]
        self.resolve_special()

    def resolve_special(self):
        # To be overridden with special checks etc.
        pass

    def get_the_one_argument(self):
        arg = self.src.node.arg.strip()
        if self.aspects:
            'No children expected for %r' % self.node.tag
        return arg

    def make_and_test_kind(self, kinds):
        ks = []

        def flatten(k):
            if k.d_tag == 'kind':
                for k1 in k.find_kind_aspects():
                    flatten(k1)
            else:
                ks.append(k)

        if (len(kinds) == 1 and kinds[0].d_tag == 'kind'):
            return kinds[0]
        for k in kinds:
            flatten(k)
        kinds = ks

        k = Kind()
        k.d_tag = 'kind'
        k.aspects = kinds
        k.tgtfullname = '(%s)' % ('&'.join([x.tgtfullname for x in kinds]))
        k.is_lookuped = 1
        return k

    def make_and_kind(self, kinds):
        if (len(kinds) == 1 and kinds[0].d_tag in('kind', 'kind_of')):
            return kinds[0]

        k = Kind()
        k.d_tag = 'kind'
        k.aspects = kinds
        k.tgtfullname = '(%s)' % ('&'.join([x.tgtfullname for x in kinds]))
        k.is_lookuped = True
        k.is_synthetic = True
        return k

    def make_or_kind(self, kinds):
        if len(kinds) == 1:
            return kinds[0]
        else:
            k = Superkind()
            k.d_tag = 'kind'
            k.aspects = kinds
            k.tgtfullname = '(%s)' % ('|'.join([x.tgtfullname for x in kinds]))
            k.is_lookuped = True
            k.is_synthetic = True
            return k


class Definition(Description):
    d_is_def = 1
    d_type = 'definition'

    def export_aspects(self, src):
        src.__class__ = self.__class__
        if src.d_tag == 'import':
            src.d_tag = self.d_tag
        else:
            if src.d_tag != self.d_tag:
                # Can't think of how this would happen -
                # so not yet converted to .error()
                raise ImportError('Different description tag')
        src.aspects_extend(self.aspects)


class DescriptionDescription(Description):
    d_sub = ('text', )
    d_tag = 'description'

    def gen_doc(self, out):
        self.srcnode.arg_accept(out)


class Default(DescriptionDescription):
    def gen_doc(self, out):
        arglines = self.srcnode.arg.strip().split('\n')
        default = arglines[0]
        rest = '\n'.join(arglines[1:])
        out.open('dl')
        out.open('dt')
        out.open('strong')
        out.gen_text('Default: ')
        out.close()
        out.gen_text(default)
        out.close()
        out.open('dd')
        out.gen_text(rest)
        self.srcnode.children_accept(out)
        out.close()
        out.close('dl')


class DescriptionWithHeader(DescriptionDescription):
    def gen_doc(self, out):
        arglines = self.srcnode.arg.strip().split('\n')
        header = arglines[0]
        rest = '\n'.join(arglines[1:])

        out.open('dl')
        out.gen_outer_dt(header)
        out.open('dd')
        out.gen_text(rest)
        self.srcnode.children_accept(out)
        out.close()
        out.close()


class Comment(DescriptionDescription):
    d_tag = 'comment'
    pass


class Either(Description):
    d_type = 'with_args'

    def get_atom_beams(self):
        return [beam(self)]

    def get_atom_kinds(self):
        return [self]

    def get_alt_kinds(self):
        return self.find_kind_aspects()


class Import(Definition):
    d_sub = ('from', 'resolve_by', 'using',
             'attribute', 'condition', 'description', 'comment', 'constructor',
             'mapping', 'method',
             'operator', 'inplace_operator', 'reverse_operator', 'function_operator',
             'delitem', 'getitem', 'setitem',
             'self',
             'subkind_of',
             )

    def resolve_tgt(self):
        self.is_lookuped = 1
        using_name, using_node = self.src.imp_using_map.get(
            self.src.definame, (self.src.definame, self.src.node))
        import_node = self.src.node
        ds = [self.pac.import_package(from_name, from_node).
              get_descr_by_name(using_name, using_node)
              for (from_name, from_node) in self.src.imp_froms]

        if len(ds) == 1:
            d = ds[0]
        else:
            d = Product(self, ds, ProductSubject([x.src for x in ds]),
                        self.src.imp_resolve_mode)

        self.tgt = d.tgt
        self.tgtfullname = self.mod.tgt_prefix+self.tgt.fullname
        self.the_less_specific_descr = d

        self.init_localview(only_vars=1)
        d.export_aspects(self)
        self.aspects_extend_by_subjects(self.src.aspects)
        self.deftgt()

    def resolve_aspects(self):
        pass


class Product(Description):
    def __init__(self, env, ds, src, mode):
        self.env = env
        self.mod = env.mod
        self.src = src
        self.mode = mode
        self.pac = env.pac

        tgt = ds[0].tgt
        for d in ds[1:]:
            if d.tgt is not tgt:
                self.error('Import error when importing from multiple packages:\n' +
                           '  Can not make a product of %r (tgt = %r) with %r (tgt = %r)\n' % (
                               d.src.fullname, d.tgt.fullname, ds[0].src.fullname, ds[0].tgt.fullname) +
                           '  because of different targets.',
                           d.src.node)

        self.tgt = tgt
        self.ds = ds

    def export_aspects(self, src):
        for d in self.ds:
            d.export_aspects(src)

    def is_more_specific_than(self, d):
        for x in self.ds:
            if x is d or x.is_more_specific_than(d):
                return True
        return False


class PackageDescription(UntypedDescription):
    def __init__(self, env, tgt, src):
        self.env = env
        self.pac = self
        self.mod = env.mod
        self.tgt = tgt
        self.src = src


class ErrorDescription:
    d_tag = 'error'

    def __init__(self, env):
        self.env = env

    def get_id_name(self):
        return '<error>.<error>'


class Package(Description):
    d_sub = ('and', 'comment', 'condition', 'document', 'import', 'kind', 'macro',
             'superkind',
             )

    def get_tgtdicts(self):
        seen = {id(self.tgtview): 1}
        tgtdicts = [self.tgtview]
        for p in list(self.imported_packages.values()):
            sds = p.get_tgtdicts()
            for sd in sds:
                if id(sd) not in seen:
                    seen[id(sd)] = 1
                    tgtdicts.append(sd)
        return tgtdicts

    def get_descr_by_name(self, name, context=None):
        if name.startswith(self.mod.tgt_prefix):
            return self.get_descr_by_tgt_name(name, context)

        e = self
        parts = name.split('.')
        for part in parts:
            try:
                e = e.localview[part]
            except KeyError:
                assert context
                self.env.error(
                    'Undefined: %r in %r.' % (part, e.get_id_name()), context,
                    exception=UndefinedError)
            e.resolve_lookuped()
        return e

    def get_descr_by_subject(self, subject):
        name = subject.fullname
        if name.startswith(self.srcfullname+'.'):
            name = name[len(self.srcfullname)+1:].strip()
        else:
            self.error('Undefined: %r' % name, subject.node)
        return self.get_descr_by_name(name, subject.node)

    def get_descr_by_tgt_name(self, name, context=None):
        tgtdicts = self.get_tgtdicts()
        descrs = []
        for tgtdict in tgtdicts:
            if name in tgtdict:
                d = tgtdict[name]
                d.resolve_lookuped()
                d = d.get_descr_for_aspect('*')
                descrs.append(d)
        if not descrs:
            self.error('No definition of tgt %r' %
                       name, context, UndefinedError)
        descrs = self.get_most_specific_descrs(descrs)
        if len(descrs) > 1:
            descrs = self.merge_policy(descrs)
            if len(descrs) > 1:
                self.error('Conflicting descriptions of %r:%r' % (
                    name, [d.src.fullname for d in descrs]),
                    context,
                    DuplicateError)

        return descrs[0]

    def get_filename(self):
        return self.src.filename

    def get_package(self):
        return self

    def resolve_tgt(self):
        self.tgtview = {}

    def resolve_aspects(self):
        self.imported_packages = {}
        self.init_localview()

    def import_package(self, name, context):
        pac = self.imported_packages.get(name)
        if pac is None:
            pac = self.env.import_package(name, context)
            self.imported_packages[name] = pac
        return pac

    def get_documents(self):
        documents = []
        for doc in self.src.documents:
            node = doc.node
            doc = self.mod.Document.document(node, self)
            documents.append(doc)

        return documents


class Attribute(Definition):
    d_sub = ('attribute', 'comment', 'description', 'description_with_header',
             'either', 'kind_of', 'mapping', 'method', 'self')

    def export_aspects(self, src):
        src.__class__ = self.__class__
        src.aspects_extend(self.aspects)

    def get_attr_name(self):
        return self.tgtlastname

    def get_name(self):
        return self.tgtlastname

    def get_kind(self):
        kas = self.find_kind_aspects()
        return self.make_and_kind(kas)

    def get_kind_name(self):
        k = self.get_kind()
        if k.d_tag == 'kind_of':
            kas = k.find_kind_aspects()
            if len(kas) == 1:
                k = kas[0]
            else:
                raise ValueError("Don't know how to name this kind, %r" % self)
        return k.tgtfullname

    def get_link_name(self):
        # xxx needs smoother logic
        s = '%s.%s' % (self.get_descr_by_subject(
            self.tgt.parent).get_link_name(), self.tgt.lastname)
        return s

    def get_test_kind(self):
        kas = self.find_kind_aspects()
        return self.make_and_test_kind(kas)

    def is_method(self):
        return (self.find_aspects('mapping') and
                not self.find_aspects('kind_of'))

    def get_op_name(self):
        return self.get_attr_name()


class KindOf(Description):
    d_type = 'with_args'
    d_sub = ()


class SubkindOf(Description):
    d_type = 'with_args'
    d_sub = ('description',)


class Kind(Definition):
    d_sub = ('attribute', 'condition', 'description', 'comment', 'constructor',
             'example',
             'mapping', 'method',
             'operator', 'inplace_operator', 'reverse_operator', 'function_operator',
             'self',
             'subkind_of',
             'delitem', 'getitem', 'setitem',
             )

    def get_attributes(self):
        return self.find_aspects('attribute')

    def get_mappings(self):
        return self.find_aspects('mapping')


class Superkind(Definition):
    d_sub = ('comment', 'description', 'example', 'superkind_of')

    def get_local_name(self):
        return self.srclastname


class SuperkindOf(Description):
    d_type = 'with_args'

    def get_examples(self, enough=1):
        examples = Description.get_examples(self, enough)
        if len(examples) < enough:
            for ka in self.find_kind_aspects():
                if ka is self:
                    continue
                examples.extend(ka.get_examples(enough-len(examples)))
                if len(examples) >= enough:
                    break
        return examples


class Example(Description):
    d_sub = ('comment', 'description', 'in_context')
    partab = {"'''": "'''",
              '"""': '"""',
              '(': ')',
              '[': ']',
              '{': '}'
              }

    def get_ex_text(self):
        return self.src.ex_text

    def get_examples(self, get_all=False):
        return [self]

    def get_ctx_text(self):
        asp = self.find_aspects('in_context')
        if not asp:
            return ''
        # It is of length 1, has been checked.
        return asp[0].tgt.node.arg.strip()

    def get_use_text(self, x):
        return x


class InContext(Description):
    d_max_occur = 1


class Defines(Description):
    d_type = 'with_args'

    def get_defined_tgt_names(self):
        return [x.tgtfullname for x in self.find_aspects('arg')]


class Macro(Definition):
    def export_aspects(self, src):
        src.__class__ = self.__class__
        src.tgtnode = self.tgtnode

    def use(self, options):
        return self.mod.SpecNodes.node_of_taci(
            'block', '', self.tgtnode.children, self.tgtnode.index)


class Self(Description):
    d_max_occur = 1


class Mapping(Description):
    d_type = 'other'
    d_sub = ('alt', 'arg', 'args', 'comment', 'description', 'description_with_header',
             'equation',
             'draw',
             'key_arg',
             'optionals',
             'precondition', 'postcondition',
             'repeat', 'returns',
             'self',
             'seq',
             )

    def chk_num_args(self, min, max):
        re = self.get_args_re({})
        xs = re.sequni()
        for x in xs:
            try:
                if min is not None and min == max and len(x) != min:
                    self.error(
                        '%s requires %d argument%s specified, got %d.' % (
                            self.d_tag, min, 's'[min == 1:], len(x)),
                        self.src.node)

                elif min is not None and len(x) < min:
                    self.error(
                        '%s requires at least %d argument%s specified, got %d.' % (
                            self.d_tag, min, 's'[min == 1:], len(x)),
                        self.src.node)

                elif max is not None and len(x) > min:
                    self.error(
                        '%s can take at most %d argument%s specified, got %d.' % (
                            self.d_tag, max, 's'[max == 1:], len(x)),
                        self.src.node)
            except ReportedError:
                pass

    def get_arg_kinds(self):
        ak = []
        for a in self.find_aspects('args'):
            ak.extend(list(a.args))
        return ak

    def get_args_examples(self, mapname, top_kind):
        # Get arguments example, esp. for test purposes

        try:
            opt = {'get_examples': True}

            re = self.get_args_re(opt)

            coverage = 1
            try:
                xs = re.sequni()
            except self.mod.RE.InfiniteError:
                print('Infinitely long args example for %s' % self.srcfullname)
                print(
                    'Limiting by expanding each Cleene closure 0 up to %d times.' % coverage)
                re = re.limited(coverage)
                xs = re.sequni()
            examples = [ArgsExample(self, tuple(
                x), mapname, top_kind) for x in xs]
        except CoverageError:
            return []
        else:
            return examples

    def get_args_for_args(self, args, match):
        arglist = []
        for a in self.find_arg_aspects():
            t = a.d_tag
            if t == 'arg':
                name = a.get_name()
                if name in match:
                    v = args.get_arg_value(match[name])
                else:
                    ex = a.get_examples()
                    if not ex:
                        # I have been able to cause this to happen in test67.
                        self.error(
                            'Test coverage error: Can not create precondition for %r\n -- no examples specified for the argument above.' % args.mapping.tgtfullname,
                            a.src.node
                        )
                    v = ex[0]
                arglist.append(v)
            else:
                assert 0
                # raise ConditionError, 'Can not match this precondition'

        return ArgsExample(self, tuple(arglist), args.mapname, args.top_kind)

    def get_args_re(self, opt):
        re = self.mod.RE.Epsilon
        for a in self.find_arg_aspects():
            re += a.get_re(opt)
        return re

    def get_arguments(self):
        # Get the arguments subjects, for doc description purposes
        return self.find_arg_aspects()

    def get_return_kind(self):
        return self.make_and_kind([x.get_kind() for x in self.find_aspects('returns')])

    def get_return_test_kind(self):
        return self.make_and_test_kind([x.get_test_kind() for x in self.find_aspects('returns')])


class ArgsExample:
    def __init__(self, mapping, egs, mapname, top_kind):
        self.mapping = mapping
        self.egs = egs
        self.mapname = mapname
        self.top_kind = top_kind
        self.negs = [mapname(x) for x in egs]

    def __str__(self):
        return ', '.join(self.negs)

    def get_arg_value(self, name):
        i = 0
        for a in self.mapping.find_arg_aspects():
            t = a.d_tag
            if t == 'arg':
                if a.get_name() == name:
                    return self.egs[i]
            else:
                raise ConditionError('No argument matches: %r' % name)
            i += 1

    def get_preconditions(self):
        return self.mapping.find_aspects('precondition')

    def get_postconditions(self):
        return self.mapping.find_aspects('postcondition')

    def get_setups_for_preconditions(self):
        pres = self.get_preconditions()
        if not pres:
            return []
        kind = self.top_kind

        map = self.mapping

        pres = map.find_aspects('precondition')
        if pres:
            for a in kind.find_aspects('attribute'):
                for m in a.find_aspects('mapping'):
                    mpre = m.find_aspects('precondition')
                    if mpre:
                        continue
                    match = self.match_to(m.find_aspects('postcondition'))
                    if match is not None:
                        # found one
                        args = m.get_args_for_args(self, match)
                        return [SetUp(a.get_attr_name(), args)]
                        break
                else:
                    continue
                break
            else:
                # Caller will do error reporting
                return None
        return []

    def match_to_kind(self, kind):
        pass

    def match_to(self, posts):
        match = {}
        for pre in self.get_preconditions():
            for pos in posts:
                if pos.cond_id == pre.cond_id:
                    if len(pos.arg_names) != len(pre.arg_names):
                        continue
                    upd = {}
                    for a, b in zip(pos.arg_names, pre.arg_names):
                        if a in match:
                            break
                        upd[a] = b
                    else:
                        match.update(upd)
                        break
            else:
                return None
        assert ',' not in match
        return match


class SetUp:
    def __init__(self, name, args):
        self.name = name
        self.args = args

    def get_name(self):
        return self.name

    def get_args(self):
        return self.args


class Operator(Mapping):
    d_is_def = 1
    d_type = 'operator'
    d_sub = ('arg', 'comment', 'description', 'description_with_header',
             'equation',
             'postcondition', 'precondition',
             'self', 'returns', )

    def get_op_name(self):
        return self.src.node.arg.strip()

    def resolve_special(self):
        self.chk_num_args(1, 1)


class ReverseOperator(Operator):
    pass


class FunctionOperator(Operator):
    def resolve_special(self):
        self.chk_num_args(0, 0)


class InplaceOperator(Operator):
    pass


class SetItem(Mapping):
    d_type = 'other'
    d_sub = ('arg', 'comment', 'description', 'description_with_header',
             'equation',
             'postcondition', 'precondition',
             'self')

    def get_op_name(self):
        return '[]'

    def resolve_special(self):
        self.chk_num_args(2, None)


class DelItem(SetItem):
    def resolve_special(self):
        self.chk_num_args(1, None)


class GetItem(SetItem):
    d_sub = SetItem.d_sub + ('returns', )

    def resolve_special(self):
        self.chk_num_args(1, None)


class Condition(Description):
    d_is_def = 1
    d_sub = ('self', 'arg', 'comment', 'description', 'python_code')

    def get_arg_names(self):
        an = []
        for a in self.find_aspects('*'):
            if a.d_tag in ('self', 'arg'):
                an.append(a.src.node.arg.strip())
        return an

    def get_def_name(self):
        dn = self.src.lastname
        return dn

    def_name = property(get_def_name)


class PythonCode(Description):
    d_sub = ('comment', 'description', 'in_context')


class ConditionRef(Description):
    d_sub = ('comment', 'description',)

    def __repr__(self):
        try:
            return self.cond_expr
        except AttributeError:
            return Description.__repr__(self)

    def get_cond_id(self):
        cond_id = self.cond_definition.tgtfullname
        if self.is_not:
            cond_id = 'not ' + cond_id
        self.cond_id = cond_id
        return cond_id

    cond_id = property_nondata(get_cond_id)

    def get_definition(self):
        return self.cond_definition

    def resolve_special(self):
        cond_def = self.src.cond_definition
        self.cond_definition = self.env.get_descr_by_subject(cond_def)
        self.cond_doc_name = cond_def.parent.lastname + '.' + cond_def.lastname
        self.cond_expr = self.src.node.arg.strip()    # Mostly for information
        self.arg_names = self.src.arg_names
        self.is_not = self.src.is_not


class Precondition(ConditionRef):
    #doc_name = 'Before'
    doc_name = 'Precondition'


class Postcondition(ConditionRef):
    #doc_name = 'After'
    doc_name = 'Postcondition'


class PostcondCase:
    # Postcondition with specific variables
    def __init__(postcond, variables):
        self.postcond = postcond
        self.variables = variables


class Constructor(Description):
    d_type = 'with_args'
    d_sub = ('comment', 'description',)


class Equation(Description):
    d_sub = ('comment', 'description', 'precondition', 'postcondition')


class Args(Description):
    d_type = 'with_args'
    d_sub = ('comment', 'description', 'optionals', )

    def get_re(self, opt):
        re = self.mod.RE.Epsilon
        for a in self.find_arg_aspects():
            re += a.get_re(opt)
        return re


class NoArg(Description):
    def get_re(self, opt):
        return self.mod.RE.Epsilon


class Arg(Description):
    d_sub = ('comment', 'default', 'description', 'superkind_of', 'name', )

    def get_kind(self):
        return self.make_or_kind(self.find_kind_aspects())

    def get_name(self):
        try:
            return self.get_arg_name()
        except AttributeError:
            return '?'

    def get_arg_name(self):
        return self.src.specified_name

    def get_examples(self, get_all=False):
        examples = []
        exs = self.find_aspects('example')
        for ex in exs:
            examples.extend(ex.get_examples())
        if not exs or get_all:
            k = self.get_kind()
            examples.extend(k.get_examples())
        return examples


class KeyArgEG:
    def __init__(self, name, eg):
        self.name = name
        self.eg = eg

    def get_ex_text(self):
        return self.eg.get_ex_text()

    def get_ctx_text(self):
        return self.eg.get_ctx_text()

    def get_use_text(self, x):
        return '%s=%s' % (self.name, x)


class KeyArg(Arg):
    # Spec with keyarg means it is:
    # NOT to be used as positional argument
    # ONLY as keyword argument

    def get_examples(self, get_all=False):
        name = self.get_arg_name()
        return [KeyArgEG(name, eg) for eg in Arg.get_examples(self, get_all)]


class Draw(Description):
    d_sub = ('comment', 'description', 'key_arg', 'seq', )

    def get_re(self, opt):
        re = self.mod.RE.Epsilon
        for a in self.find_arg_aspects():
            re += a.get_re(opt)('?')
        return re


class Optionals(Description):
    d_sub = ('arg', 'args', 'key_arg', 'comment', 'seq', )
    d_type = 'with_args'

    def get_re(self, opt):
        def opt_ra(aspects):
            if not aspects:
                return self.mod.RE.Epsilon
            return (aspects[0].get_re(opt) + opt_ra(aspects[1:]))('?')
        return opt_ra(self.find_arg_aspects())


class Repeat(Description):
    d_sub = ('alt', 'arg', 'args', 'comment', 'description')

    def get_arg(self):
        return self.src.node.arg.strip()

    def get_re(self, opt):
        asp = self.find_arg_aspects()
        if not asp:
            self.error('No argument aspects.', self.src.node)

        re = asp[0].get_re(opt)
        for a in asp[1:]:
            re += a.get_re(opt)

        arg = self.get_arg()
        sep = '..'

        if sep in arg:
            args = arg.split(sep)
            if len(args) != 2:
                self.error('More than one %r in argument.' %
                           sep, self.src.node)
            lo, hi = [x.strip() for x in args]
            try:
                lo = int(lo)
            except ValueError:
                self.error('Expected int in lower bound.', self.src.node)
            if hi != '*':
                try:
                    hi = int(hi)
                except ValueError:
                    self.error('Expected int or * in upper bound.',
                               self.src.node)
        else:
            try:
                lo = int(arg)
            except ValueError:
                self.error(
                    'Expected int, int..int or int..* in argument.', self.src.node)
            hi = lo
        if lo < 0 or (hi != '*' and hi < 0):
            self.error('Expected non-negative repetition count.',
                       self.src.node)

        if hi == '*':
            res = re('*')
            for i in range(lo):
                res = re + res
        else:
            if hi < lo:
                self.error('Expected upper bound >= lower bound.',
                           self.src.node)

            a = self.mod.RE.Epsilon
            for i in range(lo):
                a += re
            b = self.mod.RE.Epsilon
            for i in range(lo, hi):
                b = (re + b)('?')
            res = a + b

        return res


class Seq(Description):
    d_sub = ('arg', 'comment', 'description', 'optionals',)
    d_sub += ('key_arg', )  # May perhaps be optionally disabled
    d_type = 'with_args'

    def get_re(self, opt):
        re = self.mod.RE.Epsilon
        for a in self.find_arg_aspects():
            re += a.get_re(opt)
        return re


class Alt(Description):
    d_sub = ('arg', 'comment', 'descripton', 'key_arg', 'no_arg', 'seq', )
    d_type = 'with_args'

    def get_re(self, opt):
        asp = self.find_arg_aspects()
        if not asp:
            self.error('No alternatives.', self.src.node)
        re = asp[0].get_re(opt)
        for a in asp[1:]:
            re |= a.get_re(opt)
        return re


class Returns(Description):
    d_sub = ('attribute', 'comment', 'description', 'description_with_header',
             'either', 'mapping', 'method')
    d_type = 'with_opt_args'

    def get_kind(self):
        return self.make_and_kind(self.find_kind_aspects())

    def get_test_kind(self):
        return self.make_and_test_kind(self.find_kind_aspects())

# help functions


def find_aspects_inseq(seq, tag):
    as_ = []
    for o in seq:
        as_.extend(o.find_aspects(tag))
    return as_

# Beam base class


class Beam:
    def __init__(self, k_tag, *objects):
        self.src = objects[0]
        self.tgt = objects[-1]
        self.k_tag = k_tag
        self.objects = objects

    def __add__(self, other):
        return compose(self, other)


class KindBeam(Beam):
    pass


class AtomKindBeam(Beam):
    pass


class KindMappingBeam(Beam):
    pass


class KindOpBeam(Beam):
    op_index = 1
    op_name_index = 1

    def find_equations(self):
        return find_aspects_inseq(self.get_op_seq(), 'equation')

    def find_postconditions(self):
        return find_aspects_inseq(self.get_op_seq(), 'postcondition')

    def find_preconditions(self):
        return find_aspects_inseq(self.get_op_seq(), 'precondition')

    def get_args_examples(self, mapname):
        top_kind = self.objects[0]
        return self.get_the_op().get_args_examples(mapname, top_kind)

    def get_op_id_name(self):
        return self.objects[self.op_name_index].get_id_name()

    def get_op_name(self):
        return self.objects[self.op_name_index].get_op_name()

    def get_op_seq(self):
        return self.objects[self.op_index:]

    def get_self_name(self):
        return self.get_the_op().get_self_name()

    def get_the_op(self):
        return self.objects[self.op_index]

    def get_return_test_kind(self):
        return self.get_the_op().get_return_test_kind()


class KindAttributeBeam(KindOpBeam):
    def get_the_op(self):
        assert 0


class KindAttributeMappingBeam(KindOpBeam):
    op_index = 2


class KindMappingBeam(KindOpBeam):
    def get_op_name(self):
        return '()'


class KOKOpBeam(KindOpBeam):
    op_index = 2
    op_name_index = 2


def subkind_of_kind(*objects):
    return beam(*objects[2:])


def compose(a, b):
    if a.tgt is not b.src:
        raise "Composition error, tgt %r is not src %r" % (a.tgt, b.src)

    objects = a.objects + b.objects[1:]
    return beam(*objects)


def remove_1_2(k_tag, *objects):
    return beam(objects[0], *objects[3:])


def remove_0(k_tag, *objects):
    return beam(*objects[1:])


beam_table = {
    ('attribute', 'attribute'): Beam,
    ('attribute', 'either'): Beam,
    ('attribute', 'kind_of'): Beam,
    ('attribute', 'kind_of', 'kind', 'attribute'): Beam,
    ('attribute', 'kind_of', 'kind', 'function_operator'): Beam,
    ('attribute', 'kind_of', 'kind', 'inplace_operator'): Beam,
    ('attribute', 'kind_of', 'kind', 'mapping'): Beam,
    ('attribute', 'kind_of', 'kind', 'operator'): Beam,
    ('attribute', 'kind_of', 'kind', 'reverse_operator'): Beam,
    ('attribute', 'kind_of', 'kind', 'delitem'): Beam,
    ('attribute', 'kind_of', 'kind', 'getitem'): Beam,
    ('attribute', 'kind_of', 'kind', 'setitem'): Beam,
    ('attribute', 'mapping'): Beam,
    ('either', ): Beam,
    ('either', 'kind'): Beam,
    ('either', 'kind', 'attribute'): Beam,
    ('kind', 'attribute'): Beam,
    ('kind', 'attribute', 'kind_of', 'kind', 'mapping'): KindAttributeBeam,
    ('kind', 'attribute', 'mapping'): KindAttributeMappingBeam,
    ('kind', 'either'): Beam,
    ('kind', 'function_operator'): KindOpBeam,
    ('kind', 'delitem'): KindOpBeam,
    ('kind', 'getitem'): KindOpBeam,
    ('kind', 'inplace_operator'): KindOpBeam,
    ('kind', 'kind_of'): Beam,
    ('kind', 'kind_of', 'kind', 'attribute'): Beam,
    ('kind', 'mapping'): KindMappingBeam,
    ('kind', 'operator'): KindOpBeam,
    ('kind', 'reverse_operator'): KindOpBeam,
    ('kind', 'setitem'): KindOpBeam,
    ('kind', 'subkind_of'): Beam,
    ('kind', 'subkind_of', 'kind', 'attribute'): remove_1_2,
    ('kind', 'subkind_of', 'kind', 'function_operator'): remove_1_2,
    ('kind', 'subkind_of', 'kind', 'delitem'): remove_1_2,
    ('kind', 'subkind_of', 'kind', 'getitem'): remove_1_2,
    ('kind', 'subkind_of', 'kind', 'inplace_operator'): remove_1_2,
    ('kind', 'subkind_of', 'kind', 'mapping'): remove_1_2,
    ('kind', 'subkind_of', 'kind', 'operator'): remove_1_2,
    ('kind', 'subkind_of', 'kind', 'reverse_operator'): remove_1_2,
    ('kind', 'subkind_of', 'kind', 'setitem'): remove_1_2,
    ('kind_of', 'kind'): Beam,
    ('kind_of', 'kind', 'attribute'): Beam,
    ('kind_of', 'kind', 'function_operator'): KOKOpBeam,
    ('kind_of', 'kind', 'delitem'): KOKOpBeam,
    ('kind_of', 'kind', 'getitem'): KOKOpBeam,
    ('kind_of', 'kind', 'inplace_operator'): KOKOpBeam,
    ('kind_of', 'kind', 'operator'): KOKOpBeam,
    ('kind_of', 'kind', 'reverse_operator'): KOKOpBeam,
    ('kind_of', 'kind', 'setitem'): KOKOpBeam,
    ('kind_of', 'kind', 'mapping'): Beam,
    ('subkind_of', 'kind'): Beam,
    ('subkind_of', 'kind', 'attribute'): Beam,
    ('subkind_of', 'kind', 'function_operator'): Beam,
    ('subkind_of', 'kind', 'delitem'): Beam,
    ('subkind_of', 'kind', 'getitem'): Beam,
    ('subkind_of', 'kind', 'inplace_operator'): Beam,
    ('subkind_of', 'kind', 'mapping'): Beam,
    ('subkind_of', 'kind', 'operator'): Beam,
    ('subkind_of', 'kind', 'reverse_operator'): Beam,
    ('subkind_of', 'kind', 'setitem'): Beam,

}


def beam(*objects):
    k_tag = tuple([x.d_tag for x in objects])
    C = beam_table[k_tag]
    return C(k_tag, *objects)


class ProductSubject:
    def __init__(self, subjects):
        self.subjects = subjects
        self.fullname = '(%s)' % '*'.join([x.fullname for x in subjects])


class Subject:
    args = ()
    specified_name = None

    def __init__(self, parent, node, lastname):
        self.parent = parent
        self.pac = parent.pac
        self.mod = self.pac.mod
        self.node = node
        self.filename = self.pac.filename
        self.lastname = lastname
        self.aspects = []
        self.subjects = {}
        self.node_index = 0
        self.tag = node.tag
        self.description_class = self.mod.get_description_class(node.tag)
        self.aspect_mode = None

        if self.parent is not self:
            self.fullname = self.parent.make_child_name(self.lastname)
        else:
            self.fullname = self.lastname

    def _visit_type_definition(self, node):
        names = self.get_arglist(node, min=1)
        for name in names:
            self.add_new_subject(node, name)

    def _visit_type_operator(self, node):
        shtag = self.mod.SpecNodes.reverse_node_aliases[node.tag]
        names = self.get_arglist(node, min=1)
        for name in names:
            name = '%s:%s' % (shtag, name)
            self.add_new_subject(node, name)

    def _visit_type_other(self, node):
        self.add_new_subject(node)

    def _visit_type_with_args(self, node):
        names = self.get_arglist(node)
        args = [self.find_subject(name, node) for name in names]
        subject = self.add_new_subject(node)
        if args:
            subject.args = args

    def _visit_type_with_opt_args(self, node):
        names = self.get_arglist(node, min=0)
        args = [self.find_subject(name, node) for name in names]
        subject = self.add_new_subject(node)
        if args:
            subject.args = args

    def add_new_subject(self, node, lastname=None):
        subject = self.new_subject(node, lastname)
        self.add_subject(subject)
        return subject

    def add_subject(self, subject):
        self.def_subject(subject)
        subject.add_top_node()
        return subject

    def add_top_node(self):
        node = self.node
        self._visit_children(node)

    def def_new_subject(self, node, lastname=None):
        subject = self.new_subject(node, lastname)
        self.def_subject(subject)
        return subject

    def def_subject(self, subject):
        if subject.description_class.d_is_def:
            name = subject.lastname
            if name in self.subjects:
                self.error('Redefinition of %r.' % name, subject.node,
                           more=[(
                               'Previous definition of %r.' % name,
                               self.subjects[name].node)]
                           )
                return  # For clarity; there's most certainly an exception

            subject.definame = name
            self.subjects[name] = subject
        else:
            subject.definame = None
        self.aspects.append(subject)

    def error(self, msg, node=None, exception=ReportedError, **kwds):
        return self.pac.error(msg, node, exception, **kwds)

    def find_subject(self, name, node):
        return self.pac.find_subject(name, node, self)

    def get_arglist(self, node, min=0):
        arglist = node.get_arglist()
        for arg in node.get_arglist():
            if not arg:
                if node.arg.strip().startswith(',') or node.arg.strip().endswith(','):
                    m = 'Arg list to definition can not start or end with a comma.'
                else:
                    m = 'Missing argument to definition.'
                self.error(m, node, exception=None)
                arglist = [x for x in arglist if x]
                break
        if len(arglist) < min:
            self.error(
                'Not enough arguments, minimum %d expected to node %s' % (
                    min, node),
                node)
        return arglist

    def get_arglist_only(self, node, min=0):
        al = self.get_arglist(node, min)
        self.no_children(node)
        return al

    def get_line(self, index):
        try:
            with open(self.filename) as f:
                text = list(f.readlines())[index].rstrip()
        except Exception:
            text = None
        return text

    def _visit_aspect(self, node, mode):
        if self.aspect_mode is None:
            self.aspect_mode = mode
        else:
            if self.aspect_mode != mode:
                self.error('Inconsistent aspect mode: %r, was: %r' % (mode, self.aspect_mode),
                           node)
        self._visit_children(node)

    def _visit_children(self, node):
        for ch in node.children:
            try:
                if ch.tag not in self.description_class.d_sub:
                    self.error('Invalid  tag: %r  in: %r. Allowed = %s' % (
                        ch.tag, self.tag, self.description_class.d_sub), node)
                if self.mod.cover_check is not None:
                    self.mod.cover_check.setdefault(self.tag, {})[ch.tag] = 1
                ch.accept(self)
            except ReportedError:
                pass
            self.node_index += 1

    def make_child_name(self, child_lastname):
        return '%s.%s' % (self.fullname, child_lastname)

    def new_subject(self, node, name=None):
        is_def = self.mod.get_description_class(node.tag).d_is_def
        assert is_def == (name is not None)
        if name is None:
            name = '<%d>' % self.node_index
        tag = node.tag
        if tag == 'macro':
            return MacroSubject(self, node, name)
        elif tag == 'document':
            return DocumentSubject(self, node, name)
        else:
            return Subject(self, node, name)

    def new_tag_node(self, tag, node):
        return self.mod.SpecNodes.node_of_taci(tag, '', node.children, node.index)

    def no_children(self, node):
        if node.children:
            self.error('No children expected for node with tag %r' % node.tag,
                       node,
                       exception=None)

    def visit_and(self, node):
        for name in self.get_arglist(node, min=1):
            ofsubject = self.find_subject(name, node)
            ofsubject._visit_aspect(node, 'and')

    def visit_aspects_of(self, node):
        for name in self.get_arglist(node, min=1):
            ofsubject = self.find_subject(name, node)
            ofsubject._visit_aspect(node, 'aspect')

    def visit_arg(self, node, must_have_name=False):
        arg = node.arg.strip()
        arg_name = None
        kind = None
        if arg:
            if ':' in arg:
                nk = arg.split(':')
                if len(nk) > 2:
                    self.error('More than 1 colon in argument.', node)
                name, kind_name = [x.strip() for x in nk]
                if kind_name:
                    kind = self.find_subject(kind_name, node)
                if name:
                    arg_name = name
            else:
                # Is there an obvious default ?
                # For KeyArg, yes, the name is always.
                # let's say it's the name
                arg_name = arg

        subject = self.new_subject(node)
        if arg_name:
            subject.specified_name = arg_name
        self.add_subject(subject)

        if must_have_name and subject.specified_name is None:
            self.error('No argument name specified.', node)

        if kind is not None:
            subject.args = [kind]

    def visit_comment(self, node):
        pass

    def visit_condition(self, node):
        names = self.get_arglist(node, min=1)
        for name in names:
            self.add_new_subject(node, 'cond:%s' % name)

    def visit_default(self, node):
        description_class = self.mod.get_description_class(node.tag)
        arg = node.arg.strip()
        colon = arg.startswith(':')
        if (description_class.d_type == 'definition') != colon:
            if colon:
                msg = 'Tag %r is not a definition, should not have ::' % node.tag
            else:
                msg = 'Tag %r is a definition, requires ::' % node.tag
            self.error(msg, node, exception=None)

        getattr(self, '_visit_type_%s' % description_class.d_type)(node)

    def visit_description(self, node):
        self.def_new_subject(node)

    def visit_description_with_header(self, node):
        self.visit_description(node)

    def visit_example(self, node):
        subject = self.add_new_subject(node)
        partab = subject.description_class.partab
        ex = node.arg.strip()

        if '\n' in ex:
            if not (partab.get(ex[:1]) == ex[-1:] or
                    partab.get(ex[:3]) == ex[-3:]):
                self.error('Multi-line expression should be in parentheses (for clarity).', node,
                           exception=None, harmless=1)
            ex = '(%s)' % ex

        subject.ex_text = ex

    def visit_import(self, node):

        my_names = self.get_arglist(node, min=1)
        resolve_mode = None
        usings = None
        froms = []
        for ch in node.children:
            t = ch.tag
            if t == 'from':
                for name in self.get_arglist_only(ch):
                    froms.append((name, ch))
            elif t == 'resolve_by':
                if resolve_mode:
                    self.error("More than 1 'resolve' clause.",
                               ch.node, exception=None)
                else:
                    resolve_mode = ch.arg.strip()
                    if not resolve_mode in ('and', 'or'):
                        self.error("Resolve by: and / or expected.",
                                   ch,
                                   exception=None)
                        resolve_mode = 'and'
            elif t == 'using':
                if usings is None:
                    usings = []
                for name in self.get_arglist_only(ch):
                    usings.append((name, ch))
            else:
                self.error('Unexpected clause in import', ch, exception=None)

        using_map = {}
        if usings is not None:
            if len(usings) != len(my_names):
                if len(using_names) < len(my_names):
                    manyfew = 'few'
                else:
                    manyfew = 'many'
                self.error(
                    "Too %s 'using' names, should match number of names in .import" % manyfew,
                    using_node,
                    exception=None)
            for m, u in zip(my_names, usings):
                # zip stops at the shortest list, ok
                using_map[m] = u

        if len(froms) == 0:
            self.error("No 'from' clause", node)

        if len(froms) > 1:
            if not resolve_mode:
                self.error("Importing from multiple packages but no 'resolve by' clause",
                           node, exception=None)
                resolve_mode = 'and'

        for name in my_names:
            subject = self.def_new_subject(node, name)
            subject.imp_resolve_mode = resolve_mode
            subject.imp_using_map = using_map
            subject.imp_froms = froms

    def visit_key_arg(self, node):
        self.visit_arg(node, must_have_name=True)

    def visit_method(self, node):
        arg = node.arg.strip()
        if not arg.startswith(':'):
            self.error("Tag 'method' is a definition, requires ::", node)
        self.mod.node_of_taci('attribute', arg,
                              (self.mod.node_of_taci('mapping', '', node.children),)).accept(self)

    def visit_name(self, node):
        if self.specified_name is not None:
            self.error('Duplicate name specification.', node)
        name = node.arg.strip()
        if not name:
            self.error('No name specification.', node)
        self.specified_name = name

    def visit_or(self, node):
        for name in self.get_arglist(node, min=1):
            ofsubject = self.find_subject(name, node)
            ofsubject._visit_aspect(node, 'or')

    def visit_postcondition(self, node):
        arg = node.arg.strip()
        if not '(' in arg:
            self.error('No left parenthesis', node)
        lpar = arg.index('(')
        rpar = arg.find(')')
        if rpar < lpar:
            self.error('None or misplaced right parenthesis', node)

        n = arg[lpar+1:rpar].strip()
        if ',' in n:
            n = [x.strip() for x in n.split(',')]
        else:
            n = [n]
        arg_names = n

        cond_name = arg[:lpar].strip()
        if not cond_name:
            self.error('No condition name', node)
        is_not = 0
        if cond_name.startswith('not '):
            cond_name = cond_name[4:].strip()
            is_not = 1

        parts = cond_name.split('.')
        if not parts[-1].startswith('cond:'):
            parts[-1] = 'cond:'+parts[-1]
            cond_name = '.'.join(parts)

        cond_def = self.find_subject(cond_name, node)
        subject = self.add_new_subject(node)
        subject.cond_definition = cond_def
        subject.cond_name = cond_name
        subject.arg_names = arg_names
        subject.is_not = is_not

    def visit_precondition(self, node):
        self.visit_postcondition(node)


class ErrorSubject(Subject):
    pass


class PackageSubject(Subject):
    def __init__(self, mod, specenv, node, name, filename):
        self.mod = mod
        self.specenv = specenv
        self.pac = self
        self.filename = filename
        #name = 'package_%s'%(name,)
        name = '%s' % (name,)
        Subject.__init__(self, self, node, name)
        self.lastname = name.split('.')[-1]
        self.tag = 'package'
        self.description_class = Package

        self.documents = []
        for s in mod.predefined_subjects:
            s = s(self)
            self.subjects[s.fullname] = s

        self._visit_children(node)
        del self.specenv  # It was used only for error report

    def error(self, msg, node=None, exception=ReportedError, **kwds):
        return self.specenv.error(msg, node, exception, **kwds)

    def find_subject(self, name, node, context=None):
        if not name:
            self.error('Invalid subject name: %r' % name, node)

        parts = [x.strip() for x in name.split('.')]
        if not parts[0]:
            tag = parts[1]
            parts = parts[2:]
        else:
            tag = 'myfile'

        if tag == 'myfile':
            s = self
        elif tag == 'mykind':
            s = context
            if s is not None:
                kind_tags = ('kind', 'and', 'import')
                while s.parent != self and s.tag not in kind_tags:
                    s = s.parent
                if s.tag not in kind_tags:
                    s = None
            if s is None:
                self.error('mykind tag without such a context: %r' %
                           name, node)
        else:
            self.error('Invalid tag %r in %r' % (tag, name), node)

        sname = s.lastname
        for i, n in enumerate(parts):
            ns = s.subjects.get(n)
            if ns is None:
                if s.tag != 'import':
                    self.error('No such subject: %r  in %r.' %
                               (n, sname), node)
                return SubImportSubject(s, node, parts[i:])
            sname = sname + '.' + n
            s = ns
        return s


class SubImportSubject:
    def __init__(self, parent, node, rnparts):
        self.parent = parent
        self.node = node
        self.rnparts = rnparts
        self.fullname = '.'.join([parent.fullname]+rnparts)
        self.lastname = rnparts[-1]


class MacroSubject(Subject):
    def add_top_node(self):
        pass


class DocumentSubject(Subject):
    def add_top_node(self):
        self.parent.documents.append(self)


class GuppyWorld(Subject):
    def __init__(self, env):
        self.pac = env
        self.fullname = self.lastname = "Guppy_World"
        self.node = None
        self.tag = '<GuppyWorld>'
        self.aspects = []
        self.description_class = Description


class _GLUECLAMP_:
    _imports_ = (
        '_parent:Document',
        '_parent:FileIO',
        '_parent.FileIO:IO',
        '_parent:Filer',
        '_parent:Html',
        '_parent:Latex',
        '_parent:SpecNodes',
        '_parent.SpecNodes:node_of_taci',
        '_parent:Tester',
        '_root.hashlib:md5',
        '_root.guppy.etc:iterpermute',
        '_root.guppy.etc:RE',
    )

    _chgable_ = ('cover_check', 'io_dir', 'max_errors')

    description_classes = {
        'alt': Alt,
        'arg': Arg,
        'args': Args,
        'attribute': Attribute,
        'comment': Comment,
        'condition': Condition,
        'constructor': Constructor,
        'default': Default,
        'defines': Defines,
        'delitem': DelItem,
        'description': DescriptionDescription,
        'description_with_header': DescriptionWithHeader,
        'equation': Equation,
        'example': Example,
        'either': Either,
        'draw': Draw,
        'function_operator': FunctionOperator,
        'getitem': GetItem,
        'import': Import,
        'in_context': InContext,
        'inplace_operator': InplaceOperator,
        'key_arg': KeyArg,
        'kind': Kind,
        'kind_of': KindOf,
        'macro': Macro,
        'mapping': Mapping,
        'no_arg': NoArg,
        'operator': Operator,
        'postcondition': Postcondition,
        'precondition': Precondition,
        'python_code': PythonCode,
        'reverse_operator': ReverseOperator,
        'optionals': Optionals,
        'package': Package,
        'repeat': Repeat,
        'returns': Returns,
        'self': Self,
        'seq': Seq,
        'setitem': SetItem,
        'subkind_of': SubkindOf,
        'superkind': Superkind,
        'superkind_of': SuperkindOf,
    }

    tgt_prefix = '.tgt.'

    cover_check = None
    io_dir = None
    max_errors = 10

    def get_description_class(self, tag):
        return self.description_classes.get(tag, Description)

    def _get_predefined_subjects(self):
        return (GuppyWorld,)

    def _get_package_cache(self):
        return {}

    def main(self, filename, **kwds):
        se = SpecEnv(self)
        se.process_main(filename, **kwds)

    def _test_main_(self):
        pass

    def set_input_dir(self, dir):
        dir = self.IO.path.abspath(dir)
        self.input_dir = dir