From 5f46b51f12fa53ffaeddd81a8a948a6a7878a794 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 3 Aug 2025 15:59:38 -0500 Subject: [PATCH 001/342] + xo-alloc + xo-object + xo-alloc docs + GC utests --- CMakeLists.txt | 8 +- docs/CMakeLists.txt | 9 + docs/README | 41 ++ docs/_static/README | 1 + docs/_static/img/favicon.ico | Bin 0 -> 309936 bytes docs/conf.py | 39 ++ docs/implementation.rst | 202 +++++++ docs/index.rst | 14 + docs/install.rst | 120 +++++ docs/introduction.rst | 268 ++++++++++ include/xo/alloc/AllocPolicy.hpp | 58 +++ .../alloc/{LinearAlloc.hpp => ArenaAlloc.hpp} | 46 +- include/xo/alloc/Forwarding.hpp | 28 + include/xo/alloc/Forwarding1.hpp | 40 ++ include/xo/alloc/GC.hpp | 310 +++++++++++ include/xo/alloc/GCAlloc.hpp | 20 - include/xo/alloc/IAlloc.hpp | 42 +- include/xo/alloc/ListAlloc.hpp | 53 +- include/xo/alloc/Object.hpp | 232 +++++++++ include/xo/alloc/Stack.hpp | 49 ++ src/alloc/AllocPolicy.cpp | 13 + src/alloc/{LinearAlloc.cpp => ArenaAlloc.cpp} | 79 +-- src/alloc/CMakeLists.txt | 7 +- src/alloc/Forwarding1.cpp | 45 ++ src/alloc/GC.cpp | 492 ++++++++++++++++++ src/alloc/IAlloc.cpp | 54 ++ src/alloc/ListAlloc.cpp | 318 +++++++++++ src/alloc/Object.cpp | 196 +++++++ utest/ArenaAlloc.test.cpp | 87 ++++ utest/CMakeLists.txt | 3 +- utest/GC.test.cpp | 69 +++ utest/LinearAlloc.test.cpp | 42 +- 32 files changed, 2903 insertions(+), 82 deletions(-) create mode 100644 docs/CMakeLists.txt create mode 100644 docs/README create mode 100644 docs/_static/README create mode 100644 docs/_static/img/favicon.ico create mode 100644 docs/conf.py create mode 100644 docs/implementation.rst create mode 100644 docs/index.rst create mode 100644 docs/install.rst create mode 100644 docs/introduction.rst create mode 100644 include/xo/alloc/AllocPolicy.hpp rename include/xo/alloc/{LinearAlloc.hpp => ArenaAlloc.hpp} (61%) create mode 100644 include/xo/alloc/Forwarding.hpp create mode 100644 include/xo/alloc/Forwarding1.hpp create mode 100644 include/xo/alloc/GC.hpp delete mode 100644 include/xo/alloc/GCAlloc.hpp create mode 100644 include/xo/alloc/Object.hpp create mode 100644 include/xo/alloc/Stack.hpp create mode 100644 src/alloc/AllocPolicy.cpp rename src/alloc/{LinearAlloc.cpp => ArenaAlloc.cpp} (52%) create mode 100644 src/alloc/Forwarding1.cpp create mode 100644 src/alloc/GC.cpp create mode 100644 src/alloc/IAlloc.cpp create mode 100644 src/alloc/ListAlloc.cpp create mode 100644 src/alloc/Object.cpp create mode 100644 utest/ArenaAlloc.test.cpp create mode 100644 utest/GC.test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f93e8b0c..eebf3aff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,9 +20,13 @@ add_definitions(${PROJECT_CXX_FLAGS}) # must complete definition of expression lib before configuring examples add_subdirectory(src/alloc) - +add_subdirectory(utest) xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) # ---------------------------------------------------------------- +# docs targets depend on other library/utest/exec targets above, +# --> must come after them. +# +add_subdirectory(docs) -add_subdirectory(utest) +# end CmakeLists.txt diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt new file mode 100644 index 00000000..e13b26a0 --- /dev/null +++ b/docs/CMakeLists.txt @@ -0,0 +1,9 @@ +# xo-alloc/docs/CMakeLists.txt + +xo_doxygen_collect_deps() +xo_docdir_doxygen_config() +xo_docdir_sphinx_config( + index.rst install.rst introduction.rst implementation.rst) + +# see xo-reader/doc or xo-unit/doc for working examples +# example.rst install.rst implementation.rst diff --git a/docs/README b/docs/README new file mode 100644 index 00000000..6aff5d41 --- /dev/null +++ b/docs/README @@ -0,0 +1,41 @@ +standalone build + + +-----------------------------------------------+ + | cmake | + | CMakeLists.txt | + | $PREFIX/share/cmake/xo_macros/xo_cxx.cmake | + +-----------------------------------------------+ + | + | +----------------------+ + +------------------------------------------------->| .build/docs/Doxyfile | + | +----------------------+ + | ^ + | (cmake) | + | /------------/ + | | + | +---------------------------------------+ +-----------------+ + +---->| doxygen |--------->| .build/docs/dox | + | | $PREFIX/share/xo-macros/Doxyfile.in | (doxygen)| +- html/ | + | +---------------------------------------+ | +- xml/ | + | +-----------------+ + | | + | |(sphinx) + | | + | v + | +---------------------------------------+ +--------------------+ + \---->| sphinx |------->| .build/docs/sphinx | + | +- conf.py | | +- html/ | + | +- _static/ | +--------------------+ + | +- *.rst | + +---------------------------------------+ + +umbrella build relies on top-level cmake macros + +files + + README this file + CMakeLists.txt build entry point + conf.py sphinx config + _static static files for sphinx + + index.rst toplevel sphinx document; entry point diff --git a/docs/_static/README b/docs/_static/README new file mode 100644 index 00000000..7297d046 --- /dev/null +++ b/docs/_static/README @@ -0,0 +1 @@ +add any static {.html, .js, ..} files for sphinx to pickup here diff --git a/docs/_static/img/favicon.ico b/docs/_static/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4163dd69c734f8186cf1ce5e726213cebd231c31 GIT binary patch literal 309936 zcmZQzU}WH800Bk@1%|zv3=GQ{7#I#50EsIwXaq4aBx^A+G&Df@9E=RzHB1Z%2@w8@ zDGUsoTbLOf93XrRCkBRSNfrhJ0|#lWE5$ikqY0O79?U|^U$ zn}tC_0>bZ5U|_Ib!@?jS0O4n_Ffbh6%EHhY;OEXI1#%~^r-w@rND_oO*cccXVv1Iz zF)(Phc)B=-RNQ)dx4b6i>dX%x@9!*6Gnu4wa+A(!HtFQYZ7*je9SRb%TBzP4cZ$tP zVYbt&Pn&i>;q_KHJ!zBSLY3J9UJ4VK77ABwWnMNbtss9=YN_w;@ALjX?m2M7c-yHn zb2QI?|2$Jb#qjf;nbq?w|27CXaVWNsOmI2hTLyV&ero8F#WKIIuVn&NhzE8B9^U#LMNYX4rLd$CPc&nsSS&rGvkI^&_$nF1L# z_d{D)7<)DQJFe|mC~$Iu_x|S_4_;rx#UxfO_dfqc+Q(0(Ypg%a_slVu3-bv2A>zrf zXvLrJsUOz94$zigSokL68AJOnzTeh-m!~H22n0p%%r5;^zh#*{N5pIPJqsUpDm+*z z`nsb2nVibGJsf%U7rtG+rLLghAksRuzu}sNm*LiZ(rVxN`0MS2Ch9vir>{Bw79 zl(7G@ik0@~dUIuM7MR)^Z(o1LMF9jHA_`AEEcku(!@Zza+ojJ-Uex+`v~=dw@6th^ zKgP+jG@c{8zvI-Y3y=8?(UF<-aX6vKr6HmCfFzyMOK4XUi8l ziPZhL5^k@0v z8PmGW{&{5fPXF{H`!$Z~G4Fjg`)c62LfLJaZHM~V zmKMmg-&~wEBRcwQ^uxUoH!raF?@6%U@kgs|dwfX4xpc*ui?(f?C%=Plx~A)uGM}3j zcJf(sY1wz)C(IVYD+*;{?Pa%ZYo z_Pq#>_j+4pBkR_McI>J6<7V-M=|%O#;MJ>tOnrPI!Ft)kF7=A4TFNz{JBqxYF?Q^k zVZ%6W&7y;aKgzEsN(B_P$~$Osv|Ci)k?_l%#jOA5T$#&GRRslyCwKPRH%@b2uydmE zAw|1<>vgZB0!ELhsdKP?}rQHfY z{ytq8Zl7j7OD1mmTLzcP$e$c0G7VCpXD!#A*17%hNmr0Sk!9{Jm2VQU>{a{Tb`&`a zHJn&kn7rV3<+9y+%cmwxuJ4|bR8uPY{LkauJF089Ek4QX$)J>8_g|UgJR7SzV{q>A z$=NS6Pai)&vt-lxHOQL8WZpT^hY_1DTwl-0qB_{ov@f6{ks7h0WK z=oOf3J+G!nwk$6v;o6Oh+mt0OJsFhL)7~@4-*I<7@znTf)L;1pBE9R9^1hnEWTTEb z1T#;TZ8w^&wb^p%fzq4bf6aevSGoCZhTF0xGkc+*A@TgRwLaw{z1xyCS)Oiqypi27 zD*IOMaU-Eg3@&*t3X@XQM2q}eV~_dIb0|Kc`<6w)m%%WGYx8^;4vv+w*>@_MPCmW& z@4iR#d*gd$0?MI+H=}rFa$jNi>L6^O_cw#>7{lVmKnIaxe#@_>D^oT5Wpmi$G@^p9 z-aWqK*`j;5GhVAOc4+x5oX2s7VcBx|$%d`_1cPrV=PW!XQMBiJ!+~!{MY@7^EPgE! z`^r?#lVPfB;=ZlwOxBFMnX41H{#BeY|F>aQtJg%G=~L^QcPDVPuF(AI`&ET;ioJMn z>3!B8>Iw2b59RrHYHxVBL7KaLkB~lJ^Ynj@%0J|~8yQVvI5oNZ=d}C$7A!NmBj-%s zE?K1+U+VlZ|Hn*iDGn2b@Lvor6AKJ-ztuDKvGB1hn=t=;MDnfQb-(8486DmAD&wgN zgUK#?xBA%5{>7e58nvb~w*4tQaPfeT#K(QV?JjVaFuZQOdLSwx_Sb#uM!5y{f45sb zVOuSGRCL?@9;Q!!8ou5t6H!)CP*7N4qPc+8LdJsi2Txi?o<)sMV;oxzgAUU@=4nY> zwdNPtml)jtGyCNZX*c;7i^DfYeg3%XXVLX=+0yxfBb% zAHfn&)NXTKSYh!(^}y)^!3VTwHM=ZGxZFrRl$^Uq`QJq!_yHjIB*XS{#8KvaL`cgd=5yQXz<*WT0E|}5Tm2s4_gZ^{M_a&De1{@bh)5~Q62Vl_%2PFc zvZKC|==*1xYkxXfmb3h_(>5#l>{UMht%sYRki$m~W_HH=jCQ9Vq`lml$n_`pK=%wk zo9v+41*ZN%w_Rl$EGe13l@BF95X}9}Qo}9AqpFTzN!1YG`!wbx=M6llJ*8H)a z+4HtI!-seA3eyxeedhaP_M~Xm+lo()*^fT5ED!B}q`!)1o845YhS^V{vc<#ADqElFt+jO2Je3|`P`hd4^Uq#3M~zSV-DZ5+rovEN z#;~vb<=y+Y429nwxO>3&z-*DogYpHBwkKR&{NT5Z>AKG6s}IR!SudLtD3I~zpTz$B zI}>@A&&jl2a7W`~CXcFS&&+Mr`~`N=dVe;4xj(ldQ)!ReM6rL2=l5|jkz2bfPViR*O#hYg(`0SuQky!%+VZIT@mbch?o9MMaOkFj!VmukpEn%MRf%ep zZj4X7^+$E(f7chi8}pNGzqiF~lg)6RuC!M1W#RKlQ|H8sF3f*rxJ~(#>`KNb^O5S>#uF3_L1%@fIe3xe^C@9#3Gx!IyvHlMh-!8DL%29LK zwXovZuQ$wpJA+N!BJG6!f&W+U>ioS{+Vj;my?3>R{;E6T)lHLL^ht_%GW;|Y+`+cF zNI!b2ecMZ(JzNo))(>hT{~4I{G)*~v@9Wk-dNN7ww+(YIIy}7oV)nlkzxGw{<@Gnw%$L*4r$(;;uI#bN$^kh1TysuKYZ9ptphPVc7?Lg>dP@DIMX^Fo|=Pf$0TCdpGjj z?re?u`+@t*mm@!#+v<|IbC%$us|xzI^Y!76=Hn?-Eu@+$Udjb8W)b#$Gj5)>#n(1^MCn;pVbO7S-S3tFAXXZ_g9M_J@7u zd7F&GXRg#-coc1^G>O42&Hq9D$$gX7OaD;(VDE6KY{SvCpUwuE@e!YxCLiy8*z`&x zUGwM?r#n*`kA1d@^IP(x@;2K)v5a5KeVMi%Ppgk&j^T~*diLoPTiTZ8D%oX|7~1mH z&#=tT$^FOYBl=0qYtP&n`K#qx`||Fr6ux<})Z%!d#l_Maa;=k3ONY$<-}#e~yXyDO zt!tZqFOzq?oxi@d_c2F1=LHH&P4_w; z_~o!!<-(qMKA)1}=Ul%RcV-py^9P}Cjo)nGJFN2cY@5O1Q;|=F=PY_qxxeJpew7AA zDb|?wmyG9@2!B5NUwX-h=RUuKKU|t^VZ43$I;}G|p1DN{dCpp;WYQM1sIPgk>B@C+ zRfiR={xn?c%Zr-6Hu13If1jq-jIGZ*4l@MD?c9qg0 zb01!8eyK4jcG{`i8fW5qX1-(O5B@Ej`r`DAxW7K~HB3M1d;SFY1xlqQeoHx1qOYU; zyG9^z5#N!T4KwWu2JwgEa$we`jMH&V%|XQJ0cHMjp{E*?Pxxj`&9Ro zx5(w|lV8qz!MZQO+QG1>bjH0uIj#Ra+sfkRYv@}uzMuT_UWHi3HrWLdcC9nnX05&a zJ~pB6twL+*^rUN5DX#?n%zFFa$cI|K&3X305A)T3uQ3RWoYk;@@=v=;*_DdZmgE{n z7pDIT2tL3+Vd<4e!p9Ta8qN2HGdAT|Z zv8mnW3*fouIU~5txOT?+#Ahws8&@(L`X2V#+K_*f&yVL^$^-cny+5)CK5ku1{SFnb_yo3U$BAX)$;h#Ean zXIsy=S;yk?-V)^^ebKpd8~acEY23?@lWgq}Saj~-mfz-k=TBp}oXf6mCwOemqsh6o z|2?-ci>PKQ&7987KBHLCWuk@1=GO3KEFZGZbm=R$J&rQEAI`7feZ2dS#smG7e-oxn zs$HG0$oAObj9B69d(mqT$Q`bany9Uwe6H+ti0|$@Wd)0#T%A~(^3v$`!O&fXGq(Pj zX*Y*;#!&~So-5x^)b!i7m@u!gntkT=pUEeBbSGL@Grqq0$1a-rO_KEvud6=amhS6U zzFpmU=j1gWj)u>hNmnB2s*2Gp|O z93H(a|Ns6(qiq5^zgV6zdEoP#M%goxXjGxaRVY%@7%=UjT zQ{<{^`7Zy~ciE?NB**yrhLh*Z51sMM+$tJzQLUk5;rdrx8|OaXTl-q3_v~W2H;37O%S^=sJ7>HSZ&?1ojP-8Ol=UYTs~+Go z^Jfq?{JwcBOF+n_y~=%UZ)+^BH&@q2$T@h;R({<6`Ge`2YX$dAMu8 ze4!%!Wo-eGK@L2N80QEc$d+ni68+OJ&zQk)=W)QbJNDJIkV`W`ua^^Cp) zrxqBt?iW@2`C;{eFL%VZJV^Io=@j{Muvt>7SZ0HOr5R&I`&r=wT3SyxNcO&5^gS`3 zf1X}KY5j)IgoW(wHhfvlZ_T}@%+5Mf@EMdd6&Ca>%@CYX-dL%@>(2HeZlmbG-bn|# z82qk2IB{XY2}RaBPS2(`rr+XPrLZ<`?!GGC;~6^w5AvkG?%M8j(1rE?;)iSa55C+c zJ3&KSDq`Bh=Uqj1PBsr7o0LZ|cz1uDZSU;6;HApRDgj(*t3 zj|TVWG3soJUC};~Wg7d3NcqVpS|k=KH(JbAZ?F$Mvbm`J`SN8KR1%yR`fuxpl{yEt{dD*t<{Jcj*CaT25YhC@9!!KXApUZ9S*1yZTg3M(jPCipm zc))wcYU(G03-7)^Ji@RmNBn`z6(*s=9SV1+D;_E6Wf$96$rRDFwC}*49;PpC3r!EP zJg{D6)92FX@?iF^Ahn#1noi4^-{-D)Hd%BP>(tLI9~1(XFH}4^^OVkB-O5uoX^i3u zpP7$*Sjx0n^v1GP8q--e*k5>SsLJwOE4b{`$(1K2CMNx`F;Z{fSSA)wVCl=im==B4 z%Hm|BY;H_|on~>;g_oz!WQZiKusM_S!?#tVokhU7f8&9ZPrqH=Kk>0?j=q8ek8^{j z+Uz2Yc9sBUmqhynb7}El4z6X1->SruEFMYLJxln-$fcLAps+xEM*gio?u>!b;=u}i zO^ZcbmWU~|DNcQu&gDJ3>4^@bOQYq5H3|QX*8O8%keDyOZSqA1L!P*4^P?@*bkY?R z6b_j7&*WNmW5)!h*$)n^dphrhOI*q-3oV_w7bjj8zq-L%v|!&nqpMpjU#gyS>bY{D z=RnhGPo^6hpXTPow5V=2ZBb?HP&^fO^?NSMHB8#H{%yyc(r#nZPh z^xT%M$YQX(*{U+vbK{b>ZaV$cAmPk4*N90MW|o%=D$SNM;+H*cpw1#1b8ef` zwF}G7^evydNPXRlvdiN7M-;A1+Nq#$p?9hN`8lc#sYW-XK>oh8@NKVQ2|HKDX4zg1 z!O|2zhS-!iwK?UMo(!G}OrE^*4nN;APxDlHaCl|xm$1{591JUxPwWZVC+z*#)AA*= zgv6izgR?{YT7UFT6ZyBx>(w_A<*QE5ST;<1bGqfTR{GoqI{`y>nJIq*t8SIt+Ouk6 z?V+O+denCM?cZiiw4b{|=W*jQ9{c>GJj_uOU)wPVJ^R?vCY~D`vM-}z@#Tm2 z;&e|l9G#GQ+cC>hZ26SuHR_l27D$;feBQED)bHnlgZ>9}g>AyNgq`wXpXhBpq4Lq) z_J~=`43!=Xj}7NGa>+5g)1SU+(ZiQ`P+k8YC!c|JM1G$-zd zX@T(5eHCG!KW=+?nYrRt*~5Fc7Bhdj?$GXFy}|9Ef`UTof5pz4paW-9{1~R+;#;TC z>9w2msyDYYuf1BJXL-lXH>BmVp>VC)-sN%%pPwl_)&I-qVmfDe;>NR0@-vQW z@!r29`|Yq#;58G`5a6`wlHTuy=h z+p>5%SLU+lnlHW{J7eb3#RmCt&Leah3P^R^DXwLju#f2<}R4d=J+Y}e*gX_ zzwaIT_wQ=<|6j|Q{|cN;PG0#$zP9A5n*Lv_0*ht&2X;;JWN=*|wL@Yuht%djz3hJk zgOC2cP<9}x`2Nph?N?f+?~qPn_hIh)#{4}Z!F=f)w}AOt{4Zxc4O=Sg?3BG%WRE)Y z{_pdaJjgcq%Y1WBlcz|3aHRV( z@wMIiK5?+TRaA0+^KRF~V$-e1877Z#A zgy5s+Yag-)Xvt(|-LjPF?NgljMs4B?m)8tF@fWW~++isRp2X0WZn;c2ohfbga-Z66 z(*uqN{AOI9bnPbJu1hgRoyR`^TD8~ZkIt19@lIC_y)3tSt+c6mFCEqVc*m9N{%Mz% z9G+qI)n(S~=K@@$iUWVm38> z{Kxv;4AV{GCmB5%l*QTnj+}WrZ(r+v?}Ro`>R5lwgu82z@QOPzMV)F-oRntXxLxXG z&z!!0Pwid)nQqy86*(q_v)4V>|EnPM`|JAIZvVC@EBH1{ZK|^NkTCQsS z_nW`-3w;*<5lzhx5gK#{4=kKf`AFOF`61TkO2&zIf5u1p<{ox& zTmH!1`H5RWnZ~+9{}mLLhH%WOHF?P9t~&32_Ihn0Zm~bhr$(qSJ_+O5{OfgT0^3b@ z1qFpWU*7j0RB1UX5_rB~rRCEp*ClS-^zOU&Bi(f3>?uWR;+Z%9&$xCf(Ch8WQjJUU zudDLb@74PrSNnBV({V*m=qP+QS>|Bh^fGxSZ%FFT+ffPiKD`Hymx!I3@K8Xu@<(aK z%6YL1eyJ6ti&Z~tZ{%}&nlZ<6VZf5rYMWC2+5P?#u;1ptI%}`9ki)+cX8)vL?8_3{ zc#QAP;*w~eX>K4MEF96dMpI%+e#|bm^RMNlUl{&x=8|XlIpfx3`pv-17UsgAc~V3pv#NoMFkppUCw^XVZ7y9W$Jj`i_24+>-c6>C zLbZB%Q7iw~HNJ08>Msr9U2(H+)#HzC$7-#c)@esxj+=3P8cTr0-2=e~YR-J@oP6@% zJ$Hk%ZI2DLPu?<+?U}@3R`j!cy0HJ&2RnG%9ezlyopUQl=a0dLXAZsLU8_2xe!Td0 zx$eP!lmE|ID|0;=T7?4A7lt>xUVnEeH`iMJ zuc~*q_e!xkgItGRC(ZI@;wJmVEOg(??>s--#`yo-J^Qz*G#u(?{?8zHOypVSjB^Ka zvKsChvQK%_G}Cj3*yjI^uD|{*wO2g$FhkZZc;$(uUMu&=6h(V@HMVKF?@Sgwct5E| zb6>(i{?Gq*O=5U+li`o7apMZH8}oGEo5l1-Hk2@J$p4l8+Ti!HkSVs`c8a&}D?GLG zuY!Vt#qFt|w*NmiC1}AFmy!=<3!L(0ZQMT|vY&VAb@sHHXF7#)Y0{rQH(WN@+O(FJ zxsR!j>7RIozz?|%%A!Sajd6UQ>-p?gSbAlr`|T9@*T3F>wbqo+sp0F_c3V$>^7rc! zwg4HnWo-BRBh@doLhyNm|7QX|YZIP-`Mf3gSh0eFg4G_DMDx(aoiPf2o;^SL zTZ0yu>K@oUYnLjw*q{G<_RYJ((B*AjV4ik);%5WjmbId3tvBo6$(+e^;ZHJCzS;f8 zxli>pze&{cvZFGOf|iBMy>{{Ov$Nc*z4dCW_peX+9duO8G$Bo4UiZ!D1daBITaw#k zE@kz9R%D-FpKfjqS zv)%6J{{6ShpZL#cyu#oW+z@F{B3xi?z;2xUf#b}Yg9pX>q|R)4eDlC`L*KsshSnLq z{`dX&Tivd`{J%A)5D zuN#;Re)Gt5-0V--;JlYhqW7ip4dEZ@XVx4xJy1O(Zz z%Z8q+2UJ?a&g8kBZs0fA+H!S<<|$c+^+k7{Jud3iYn(JNi5NZ-bf7^JMW0&7MjMXAEC!o?%hrzkFFV;hi_@j)fDX%ck(D20Nyl znK5@(zxBI~v$L|*-(>yv)n!?`m32R~*f$ankzW@vT0~UwFPhSB=nQ1~We#Bgh$;#HeV>aS}4tl7I)TX%11>r%tRjfvNblRZ5dl)jrRWB&N|%VR&E z+4a_E9xaMB>`YX97F{diYEY;nr{CpV`Z;gGA^D7^nzBj{CIM!XWwmw_1l}Fg@t5oN zP%ifGkiPk|85O8rOuak<9YW? z`4`C&ES+(zN5|)wO2^5U_4#ba7)ocns%w!^>$ta%@9A$(r-fZRN+&PaZFiUF)Y`5J zaaTW8L)%}{2E|Nl7Bk+S&o)8%KaI$RbRp3$*BVY2|UIkKLV%iFE*=c`LX1|?wq*b z4~+L2^_xEZ+A{rC`F;7=)l;fxzU|g!>AmlGVWZvr;~rj20|3{Q)kOP5u}KUrCj+XO`Sx}zMx%22=Z{qc7@ejKvP z+xz&;p8c~_7y^rwt`@J9t?hfi>z{Ab>(r;494B0p^7#Ah+3e$cCcoIZUtztbf`Wp> zlsWPLf-c_tDQ5rQ^=)O{c+n;JZb3y z`{U=j-Ll2DY}0#m&bnNyf@czg%T0^-d%~FP?*+u({o#Ck?Ou+quYVkT1z6T+zm0uj z@lc%c+1bsL*DnDz&rTi7uQTr3^~*Ch(Y$Quq1{p0ceAaR`DU)Y7-j$X_s8OGH3 z_jujzZyTg0e%Eu3agA*G_HfD%)twiQSIA#?pCD|3AAPwRi#l)4T6~ zcg|;-tG-8U)n0`e-(Lsk>^GI4%%X7W-p=Ri7A@cIn`>Qn>dO-GUtK{HgQpg$KU=J~ zz;uC0#;=3*ZtN$evlhqp|Gd>3`+u|8?fj!@DvTXnh370+cc|~WyX+#baes6k9TNt9Nlv5_116U8cE%<>R*f#CoH149ENXsxFLNQ!~Mfr)`3 zg#m&gBBSJJ2#kinXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2By2#kin zXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQMeD zjE2By2#kinXb6mkz-S1JhQMeDjE2C73;{+41}1(6A#QmFE*5qM4rb;N849DG9^N7F zKRcV@za0a^^NcL6Pg&V&U$e5ker09l{LRYh_>-M8{aaSn+#lIFv;Jjg_x;JrD*Kj| z75X(h$M8i?zTowua>lDg6~jA#MtwIdL*Qdd3d7ypLbi{YSw_FJva0@OXYc--o&Drr zcJ`0|+1dYb;eXlLfBt1>zx|t?efn2+&ZKYIIi6p#vIPJC|IctFICxlw)u^Y2PY8U> z&SiL+SIF@xGt=W&cJ_+D+1amgrFCM&|7B-?`@Fgc#;&*n=?EeJX_PEkCIpY7avycDE%(VR9(ZO&pHg-sc->9R9 zZU{U}Ok{YMk;(8TEnWV1cJ`+K+1dZdNyn7v`InV-`&VYB`~UiShL5SKLpLx-T|T5j zz*t0t;cI3V!{@9l>EBsdTPaDyl?p@NTj2o=t!TyXommUSq$H^vfTbMYuaEHLh zyaI*~c?BY%IoN?tqh9mz6cc6~CZb*bcn}r1fs7>)RJ16{K zcJ@zv>2EN|{m#yweXppT=~I5ukO<#VM-J`~c#)dMa4#u^E(2)3Vlap8sM`j22wabfV)$QJ$nY~WvjLX2h64RJJNxj< ztZbeaSvi9{fJa?NuMl8jU|?WpU|`^5U|*VU|`T?U|=v|U|_IhU|_Ie zU|_I?VoL@FMq@?>HeCUB1qHRI2?-m9Lc)i+@o#qagAZBR3Li!%gz1&Q27^7U3=9lH z3=9ma(8L_hz`y_+1?gd6U|7Pyz_6Wxf#Em<1H%;t28MeK3=Gd07#Q9#FfhDlU|{&f zz`*dCfq~%*lm_wNGcqu}W?*1^T4`+j4VJcs0{t&L`~9!%Y?I&FqZ46+Az{+M4II!y z98_R~W_x-W7#KD%Ffg2BU|@I(O~Zc}7#KjK;1uIZQ`3L{b8@IQSxbjJ^!;CUwhL(B zmIh%zY9xI_fDzho(P3a0l5K0|SFGw9USS zfq~%>0|Ub^TxBvI@xRb^{Bs5dhAWJW%m>+6*;g?#F--y8ch11T0Gb(!XJB9mVqjqK zU|?WyU|?XdVqjn}XJBA3Wnf@11M!)eSwP|*^1QqW_v7O354HBs->fX>(ezJ;R7;r^ zT+lRE&A`C0pMinlEdv7ssB9*-&HkN%f#C_XU%MEZzGD~|80;7r7}P<7Jxq+uT&iMH z;1kwnmXwg>+PlfA4EIw~x&CBj4a!BIxcU+Qva{cP%gi+TIeJ(MN%2i5#h|nZ8hiu| zPJr6+pfpcRdIy#3?-&>u&N47CfYN#~0|SFAbi4;Nun8LEq^cJ#M@BNN@$g{!ote1= zS6Um4;{UR=QRTZ!(Ijk22h*Go`HcujDdlHF6kXxuzg7&;gj81573 z%Yy2HV+;%oRSXOaMhpxL3ePS-@uKm5(kzWF&bOYU3d z=s}^>NdZKe0&3@g%KLU`+a6aN2UONShPLNHeE|WYOdnuHf3mX~erM-^7J+^r?0MjK zcJ`FSumr}7siSRwIwc!W`ySL*zk{c|2aV&OXJBBcWME*>U|?VXjRDcgd6Zl8F(ZTF zLq>++-|Xx|gE{?!4p0A)lWX&5blivXNGEIpXgmkh!2+dgTw^()`PG9A3=AN3;)IPH zoGLC=)HD3gNN4z&l@&LbHv;_2&R*~@JBJO_XCIs)IV@ZSD!W1BGFurK7(nS8TU!St zzMFx80kj5lNVIVX#mu{`9ER7K+5CU9v$qV!IskOR#@DPYQ&3xNZC*Jc?~KZm7Xq>j z3=CZi3=E(#N^I#K)Xo8w_Yu%FYvkE72z9yay~F@oPw*o<+xA~}_VYoO2mXA|%Bp1W zPi8!yKHBf4LGoc^U|;~|#EbAf?@0W?PinxCS969(SMS6Mj>GqTGV ze`ea*5B*JFapcw`J}|6F8XV2A|GSt%$C%4sX8H)uv3Y3gP8osq%tH78f% zZ&ns)c^uu(gZ`JDeep+5uJ!+%Y=&34pqX=;d3U543>uUj?->~kKQl4}e`ja+{L9Y%Li6Guv<)*S=kK4atX}2931}{85u!G zSV#`HFdRVt2tv1&f5Xz=dBMQIP{6>z0NS27fKD75R^QIZW;m6c&iWxM+wxa-&h&rT z*$@6_Xa6O;PRPl5+iz=om5GrNv|Sli9{pfsVDK9nAwn%zg1yej!0?}$f#E+Z1H*q7 z28RDkh!Z}@wg)t9xeUh=WzcaVpeHL1_}sbNTyrA{SyLuPR?x97;6wl_qZk<&`iF10 zf=*<5#>l|%ho6Drzaay||0o8A|Md(E|7SBW{9nz$@P9J{!~cy84F8ugF#Maq!1%L} zf$^s&1H&&R28KUu3=FVhoL~rnw#e=Rg(n&Yl{M?3XQUA{WK;p}5cpqO%J3mQgW*YD zA?wTBe5r3)*;c=^vZB6c=M?|V&Tjsno!#{>JG<>mW@hD&%&g=u>FKVY)6!IL$Hj34 z7+W&%vU4!7FtczlFff9ao50gQ0|UcJ1_lODy^Y)QAteLy8ff*vUoHlQzt#*4f7=-t z{vT&x`2U81;r|~7hX4Nw;2#VO{~s_g{NKR9@IRe_;fE3f!*6K)fHfdMOYTpgrF)Pg zKwHZDphu};)i^3RARz!+(*ueh7zP!R76alEs#*&3&VMcjhW~yH4F5MVF#P{OAgvS1 z3x63H{@rC@_}k6E@JE}0;TI$1BoVm7LFZk9hVbE*L-PS>dwC%P0|V%IHMrtY#-IoR z(D|gGv1jBs%N-OhBij*RuYlV0X3%!cR|?ZTwtVq`f$?`01Jfrl2BtKSOF>72T!W@} zumhm%rwj~?p!svqv@b~AC>~rP06Mo9w8RQI&Op=eLo~j?-r#0n_@B?f@c#)7(mirs z0JWd?Ffb%$FfcG+N&8H985kJ6m>5ArprD;xgDc`kT>}mQ&=|x5XjuhLJPZsBpm`e5 z@c>{2LxTW09n{4BA{K;$d~c1m z3>UN%D`n_7AC&a|Npugd&?5#$VM_)^&?&P+Cj>{hOF?tK z*U{QQpyPpuK(K(a>K`5khJSPETjpcSSC9WQFkF7i!1yl!Jbxwz+QB;nf^gJ{pmkRp z(b7NYs4&nms)ILln4d8)@T_HIVE9+U!0`Xqz^8v$p7?v6f$@hf10$$EGI)b;)MY3k z(1w=&L1P!7ZK)`V1`p>y0|O&yUhB6F1H->(gD367^1%O93=H3S7#KiH+y+mmjk*M9 z2!M{a25mP5HKsurG$#N$z8$BAft3KYd;ao5*DDNAn;)LmvDyEFf#F9yxE%!E)jqJH zHEKJ-5CDz$fUfBPrF{?vB`{E)AgGc43P884ft>g!oPpv0_d!_pL-WJmlMKvn#Tl4D zw+YcdltyhNDFi^baxW;) z(k*~SEh0SxK7OeD!~f5NJN<+6z#ayMAH0wgt!Nr3 zqlQx!0-$sbTCWZ(`$075>YPC~1_W{zDE3Z!IMKgN77n9*3hAkRJl*>mWc^{ejLb zAm2o)>-@{W!1xnXo_-oS>Hq&$28KWEkXuHn9w4IzQZEDo(az=o4P1cMMo`ZNicJDl zO@A_mP}&EL1>I&~{4K)(-fBv50E`+yyAS}Sbx@iIB{C2Ot!oURopq#|3~~|}_YJA^ z&-nKP1M3HK1{ToCZlwBoR6QL-0CeaH`Z*oRbhMvGF#Ov;^wR(Tw9)iW$FxG8RghDM_drX2ST0z|z`!s_wy%OZ z{#prwD%&KOX>AkRdq>H?>Kkn>uGSo#N@wxvIs{;8T6Xki#=70_}} z0z<-}6XHNS#Asn38D@g>0H`hTcL?QyOAHME#YWRV8PQE&EueNjXw@e;kwNpo&cStZ z8Q5u{vh>vuO8?6l82&OdFo0I>(KkXzZ6hfJhCuoU_knpC82%j`Lg_yfQuc!m8Y3w_ zMitXH1VHT{(CKgBLKa&7Z)ad&03BgQUzgyt4Rmlm$a(*2hDiE<%E0hn8wRghAs$gQ)!v3Mf!J;t%Kq^A|%P4=jb=EC6!&C?4D)z{0@502=QB zrF$3#-Pi`o7lX*jyeTf2!KxLM!&gX$>5p) zf;qXAfq@Zp0?Ieg=_juTaUNL5zyLmh9p>;+dQgV|BQFC3<59Hs&x}FoWCeu>3=F*I znHd=WP8g&a;57roKYPfa&uHO4C=(Hiqd;RnjKT~IjObT544x%$DDDNNDNsY`k0JxZ zzjK2u5By_b_}#+5aD|D1;SGwbM>&H!1h6fE23-*|I33M$A6i%a_JLk$1Y2@E(DZf& zhX0^#%7Zi9MqPy~1hg3#7+ygW6{vs(;X$+o2Ai`%M+|-jUCC9z!0`XuAgBi}GBEtp z9c}kui>pB|2D-B03sU+Aow4aV=v~bK%BKH8TVom-82*EIv4=5N1 zf5?rx5G4e{85kIlj{yZ8iD-_ZV$gCxdEk!%1H*sNaU)*_pdJ7%^06H)_XlkPA;w{) zNM%1LK|Nw%U{EGT#;#;8`hqO(V%t{=*svT3=IF*GBDh0WMGJCWnkdi#=yYvj)8&k zDFXwGJ_ExLtRAt1(5MhY0s~_30+e7t=e2^4gd1i-1M=E`&?aIY28REt3=IDq85sUY zF);kkVqo}R#K7?$V!0;b*jh!h2!#_y|hX0_2;cg5J4Cv)UJ0l}#&EPN#qLJwx z(3Owi!~tys-DF^3kRF*qfz{Wd3=9k>pVVq}3=E@n0G%R$ zM%E;uwf(;_Ffh2&$gZJoEa*s7(85zt*$=}lL)}v&*!`f*U7$nWU~vheLF1sKZGY^E z0<=cE|ZM~`qZFfgDW91JQ~mN76e@X*m6qgD|P0Z& zz`Jf}y8twH25S3*(mo7>))jgTZEp=5*MsU}&>RgcZa_4s><=0?J{(w&fYytn@1p>P zF=$i1=D<2_)OH32hByWWh97ACG*Es3<%`h(qD}~a_EDpcD}(aD76t|eaq3txY6=-4 zAkV!@$6xgG%$4H%Ap4P-d|D~I9quX=`a|2i1X|LL3sewHcB56d0^Tu28POMj0}g~i!mJk8o+S+*EEK6f6p+S`}c<7+`r!p=l}o5 ziqHM~#c=NLYlgFbPBWbPIhEn~SAT~6uSFORzF}ZE11iGtMh56Ymjd+h9%e?C2h2?D zCd`bWX)wI{M#&HhW)P@81}vpVmSV_fZ^QV z8w}_F|06ryBj*7y``=%NGk>lyocxi=aQHnx!=?WW4Cg^rD%_(cSkCeUDF9t&rvO(q z%Aj`$fcDiL#8MA{*3N;>S{?dr(gSZ87@FoYFdX}0&T!_>4!rFfa9YOE_90I07sHu9 zn;4FNHDvhzpMil5T!etu;~vKn#-Ori^h^hOr+7^JK=HE|OZZ--pyI?+N6Qvw!a}ocs~QC?>1Oz{rGthB>I*2c7Q#suM6{V^m}yLI5-- z2bvEC&542H2N{Fv2h)LY6h(G|+B`G&vN0V0R>W}r-v_#-eONtl;r}bfl-e^4Oe~=D z8<4`2@dX0|gYW1$-4w+xEi{A9kN~a21zl8t6kp(eG3Z>;Xa)ub(0U?T*iBtCw>@BB zSbBzq;na^uzxpx+nA3)_8=v-o#K{-#*xr%|| z>VF1?<6mtU&i#8lplKhJ{y`X&2M)Y`%@C4N%Fe*R%Ekzq2B2BojT%gy5CGjT;K{(i zfPS_vC=Y<}YX$~}Rt5$J(ArY!*hmdi_Pt_Y*!e`1;qt6pe zFr4~X!EpZH-$9lBL3!Z(zuycef8>D2MSIub@yMvuAPWJ|`Eex-3=Ge)jFE!!18Dsm zXs@>IfUey=@{xgI{~Jw)vw!XmzO)Y=FFo_;D#N~43JeE9M>`C%SRQo_z7PPlhin)a z7|fd339zE?23{LjF! z`x(CQ9+exMAt1!SzyP|F9CQykdisa)LF3z?d3{T|?JGF`71ZaIV>tKk`ruCg|Nk?b z`+JVz$S3j9e!$>N;6%6zG=O2iz`y{yqXBd$AuQda)1XQobf%LZP46sEse_F9ocmGXSVI6bP6|4+Z#VjyUbKD!=7Y;h;5N|z{|u*oP6wYsvlO%qX0S%@sJn;^0ni$`7zPFg(7XWX zylM1$0LBLuc%Zh?MrJ0KOlD?g(D_7^uYCl~cb)kyH6+?Tu=IcS?>UBp?}Ql+z9TY- zN0kkM5CHWJK<5qZ!!dsh%Lo4%85luhr=am9&>jTPo=j)xTmtF)4nTe1Q$K7N&j0^B zWXgZgKAV%@4H-^>ii;r-v!hNVB?Lg@rJy!HsO=A$CxfSZw004)IA{zNbXFZ`V7!ij zfguojf0-Dxy#(rWV0Xg>(3tbnFZZzoWa1r0J=y?1$y0Q$GqAZvAIq@B>}jGxQ^S)CV|2091B^?y3jv{{!v42c6B1e&!jz zynrqTTAvEi4?5TJ3o`@5ImWeD*D`?D7|^`j#=b8YmZnLePyK9Vc>JG%!7UtTz>P`_ zyAS})qk+~8fyRwM`^!M%LZEUU)E_`k=S1)%V zKR|;gzZn^rUNFwue{9I5|I@!(8SejQVCV!56O4rD9rYubApkm)3v?DfsNDowj|$q0 z3A!%@v_9LHnSsHLantRIL$3XQ;(HOp-Tw>>p`b23nISW(Z8QX~{AXY|`8|1vjsN^% zIQuu00W@|y8iS*Nk`Ork3$*slf#KZ0FGD5|ocsHp;mAi*hGU>1EJ{2-s&~YP0B8-t zfw!^@XaC+FGU@;9pNkCpUyCw;_N$Hf2pkOnib7z=69$HL*I5|O{9ZL=(*K#?a~Y~; zFfoA6-lfR%qnby22;{aiFx>plz;NPQ>fqe>h&Cq&I$!t1x5&};&m%tNQZE2Nd&&=g zRAK;~yEfqST4?DV-92aiTxQt&LW*G@Xxfi@K`?642o8b8Cm9$d6&V@M{O%p}ZJ;y1 z8^L?vmw}c&N^*VJ!0JIO_)DQhZbM6m%xewx>`*(-o_*XTC6QHGl)b;+TX(K!Y zc0Xre2+w6?IQe6+t_A(eaO!6nxa{9Gy7zsAr&ii{A9M!F!MD;3Xa5`@bnT$CfA%pP zd?(6q6trcUHr^jKb%cjN+cL;GC?|ioF`WDNYS83?vwt5m9RF$yz89l)(Fl*EQSZ|< z1hzk7V3@KEbjMLH!?}Oo20Ra(`}c|A*q3CmpGU|0!ND*}&^QD@^QznKvooCi+sJVK zKl%52f%>eJ;B$Y!F&zI|!La8!%jkJOG>-F8<55H4_!kC-!ygnB6ciZF{AnDZs^Bxj ziEkAQt1hxLY`Tr=yiwk02+$)0wm)QG*mRqn;p7icbLb`AnnP#*K4UofBZcAkSJu(t zPI^T2s2w;%0MsQ|f1Qcp_*YkkGrvJYL$o{|8gv!pL58EB?HFoiF)}PahtpZ35~CqN zw-9Jv$iVRSKLf+wmr@KTe>5?i`}c(Eb-~#`4;W7UtYH9Ms|`BZq+>bVyfb|0Jq&06+@bK;&_4|4{@r9a^|PH}|7$IV>AM*jR)KB}A<8wQ zibg|VU_xNwF$RW-o0%96y;o#7{VSQ_%O0c-)Dw1e{M3I`Mr$c z^sjh^V_)PM_P=HvJ<9nXE^aaiQ&wjdWN%q zCNmuWI+x+Zw>b>w{!L;y^|OxQ+_to%QQ_yb66V~96EQVlr1kj;S@^B*jZ6pw!xAc+8+ z9+1R8K#chh7KbPSC!z;XH-p0zNxT877c7pHVIZ#j{~sKvh;;i0?AibS|D&bz9}Hky z{{IJsDvbUA|Njqgub}3m15j)Kg8~Sy=Kuc&xDyVb59(WpgP`X8 zVBr4)^)1Lz4UACE0|v$)P$eMo|Nk2yR09J;0o*wtA&5B0CkjX*_5XhZND|_6xHCaQ z5OHuwp%g_2K$0K_Ga!Y?|Ns9X;-DCUx(uuiCJu^eG;y%0;1mN@385Y!#KA0x=>Pu^ zac~O8C60*E|4{WH??RF?%$WZVK&l|(DEjuM_o>WLQz2QxJB zL#+J|HisJGAYWoL2cI~^zo_m9sV7eyq!a3^|NlRLcv!-p2yswMpqc|I=}^VNJj`?g z4o^_VM5|gM;-K`2nw}BjsOc6W4oc@J*$xt4;Cz9S?V#eI2tWx=s5mG-5y79@TC z2YC$a5x4{-{ewJ!lKi3h0#r0&6~|~vK+X9Nvj}Fv0ho4(2Vug{d<`n~P~8d1@Bjb* z|AFc+NV$PW{10mQK*}XhS%)eP5A}bj;fzZhp$e`74Kf3SkvJca0}e_22Xa7wizSf8|Ns9Wy!ikB0fZy|A$u6f(f^P= zjOT$A%`jc0~|u& zG6co^KVWBIivI_-zOj^P{~H*fjR&wsuv@^y0|t9Ym5UM%poR%MR`Guf4E3PkWI$8@ zzkz`ft2j7pKn?|m2-r?A0SM^}73^6EfnOXYejysb?!+aIl71lSG1Cu39GngzOcWBAI4I7*2@*v$Bt((3 z7fc!ym&n-*CJssvn8E)aOPvDM(STMZLWTc7K<~RiB|zl{l!;1xM&*w31}FqH7#JA9 zsgjX_fssK0oS;E0h7<+{FoueZQllX-8UmwWGz3ONU^E0qLtr!nMnhmU1V%$(Gz3ON zU^E0qLtr!nMnhmU1V%$(Gz3ONU^E1%7Xr6pViXvzwGS0|FW~c{?E?-_dh%PKNSD_m!19nUv~DBzuDP4e`jYG{LIW!evqEQ z_$D)JK-@lRDfuDrKRcV@XLb(5m+V}g-`Uwof3vgC{L9Y%4UKD9oa3WG>EZ65?ChE^ znOPG5^Ya)UCnl2bpi!N43xNxTWeoqbvlxD4=cxV7&R+RHJNqXI@s6G*{{GF*KKeU5 z+wMVlD8sk(bh`Ot)FRSD;B86@!~en}hVPkK=6|!Z&r%TYDCyu|cJ|{xSy^E(l9Cv| zXJnA>uu&Z}4}l%ktqlLOG8uklWgGp?&b~~oxQChZFFX6?uk4)Q|0%Hyud}jg?w?T$ zNDF~)+1U(Vva+TBW@jIS#Tm8ff7#jheq?8x{m;#1m>fOY9w04-Xs7yhdIrP2)HLQl zS=qhRj&pSL{$yuw`;wg_@GU!sb{-lvnWPZ-o1Me(D?8ivUv~Bz^!TCy|M#z~tn~i{ z1q=`3;z)AmsAB4e!28@hhNpRjEPt}I=hGmrQQCnp^Z#aNpZJuOCGsh2bZmh7F-n?= zzp}C!er9E9{magN3X2~)&_90X_Cm3{#X|8sH}erIK;p^fKZ z&9~G{7k{#|r~Yq`Ww@U)+83Z&gpz2`tE?=B%%E_FKUrCGs2R7!nDs9^`}pUqY`)K< zeL)gq4X<(*1_lN`1_lNh1_lOQ1_lOO1_lOS1_p*`1_p*S1_p+F1_lPu#7r3j14A(b z17i+98%O%3h=|Mob8={&=aJI|XiVsPR<`nw(fG$3p*SQN85kJ285kIp85kIx85kHc z85kJ)7#JAVGcYimWME*p%fP_!nt_4g3j+hgF9rq%(5^Djra27E$jJDAzO&1}|GBwz zjsO4I+3){mXB+>^9xeZI#4)-sF9QRE9s>gdsM9osfq~&50|Ucj1_p+23=9ky@k*>1 z8xzz2Ej~W~=^g+7va>(`%+0g(iz^TrStyH$~ul*H`9atFFX7B z&#WvBQ2!IdVIxm~63 z<$qQdL)9Em5YW%D$wXGi?c&i+A7gZAHEA(iu>c)!NL zz);G-zyOj5jpqzl7<|pnX84?y&GR=qdp)h=AGEgUTUM6R2pIQcXJB9mgSOd0c^z&dmIOI4J0Up@G4FLou-{qFh{(GCZK{L8;3IrGC&n`(C7Y2c-c}S^%{H z2Bm|Eb<~TDEQW{anQY&(bL{?R=ga{0+yCL&5A-iP`_KRE?58i2lGZEo3EW|T%u9Y_ zWMFU`&<+lUhe2nKeq&}}_$SH0@ZXk!;eR{>!~aqShX1t;4FAg*82%y|Tr#@%rFuc#rXa16vE%zfQ$LCLWcIBV! zY*2bw@h>}jVHhJQ^@SO4GK!OFu z*$fQ-uQM?G|H8lkx-tQD;4B>fV_^9Im4V^^O$LVl3m6#w`Z6&5=7TJy;DALas67W- zX8|@8y5<5jrVDBV!qf~)dUs$L!wSzphM$?4Og}O*nC7^6FuqAnLiei=0|Nu-&|gsa zfDREJzzP851W-Qy@4&$De-kv$|AVfCAQFFLVEDg-f$@(!1LI@Rd|My`1H%)f^nDI8 zzBjl^IrIpjGaodr1*-!C;P~QDt!@%(W4UzGUD{Z`GV3@QFy6y&? zs2CU+4>2$>>VQ1P$cT5k9i(I=VNgB+txW)h6R5%sr@!YxR{s}aVE8wef#Lse3gaG{ zCXW4QV9)>?%)r2~n}LBz1>`R#Mo|zoicv$L2C0k$tzklyr6~`Tbr14H<82F5TG28ML-QROuC%Fs0&)CK_chd}uSH0KE#6Q{jz7{4+wFueh_ z+v^z^KsQv78_&4({rk_r@aqo)dl48Ljbr=e+sIs*g4GiVublYxOjiuT?B zB{k6W+CNtYhW~G=Q|9AJ2me1ZF#PcccXQc5%dTnfyCG(S00RR9XdDa_DWLfe(3&+G zdjXUefAKOf{NGOFxQEsme-AJ)eG+0|0xi9zvDb#4@u0EK70~<-s*poz>jhX<^AD6K zL47u89O2Br)R6zh!1yPMff1C%LBl_^_2CdS9W?d>3LFpytv{!s7eH40V`gCZzlc70 zAD*t(F);jQV_*O!aTGEt>dn zs2VEBz`y{S9|OhzOXxax>idNm)b|2e@xN(6;-B$fA2|NmZd2cHL)%2qyzfzH`44Ib z7}3r<;P}rSkoaf#R|$@Pc0byAZ)lnf+Viv@8vmfe(Sml~0LQ;K1H=EHbWQ_*7#RMC zf#aWco*SwrgBHx}hQ>c=ucI~XJOb+f|5s*U`2Ud3@&AH>;lK81{9}z-tpRR2di;Xg>;!WFdqJ%98)Y85sU=rcpB3!@%%Q1~T&pvI}DCD2WjQ<_ruBAE8wM zs3`y%6~a(NeF0FMfSQE=K&|sFR9*=RihDIkvk$bi=MkWR@K$b~@B4iDHPdWiv z30j%)M}mRj?{o%+|CFu_`oX~PZ$1OVUs*`L2c@rJ6jQYE3h2a1P(*+*=rl^&*n-zo zP(1zRU|{$k$-wacG#NVrelaloJI}!QJAr}m3l{@ul`&rXMkSF#0CXA#DDFXc0Jnkv zWnf_a!oa}zTbzOMZwdp$zwHbR|6bx*B@XJ^zh+=~cani&+7<=|-DwOA%z}_Zwvl`{ z%ET7}pcCw1GXS8|ia{q<<5N!uIZ!eLl?OjSgHw#Zbr=}_M?m-gPGMm9KZk+gKWIJ| zw0|Iqf#I431A`!F-xp~7@;d_qWANyv50WAYbWS;_;|B_M(D_HS?*NkIJfakX&hY@b zAB49+&tE4>cV1_n^t1;sz892lMGB|Zk*pgliO*n!x@ z>l{2PK_gjRNd5pFTuQ^WjDyGH6uJZyMu(u`2I?k*_5@OBKD*(U(|rP zWawB7TJP}=8fG`3chd|V*JHZ05$YFES$2Yffk6UO$*2fY2-G2k*IWh$hM|5w3g}#? zOHe<7x)9Y!ejR0^h5+cidf5I?Q2P&bJ`Spip~(a7X#)8NR0e>~fuX~`)*%^Cp!f#W z`JiwD-CY5?&t^z^1kKT)JJvQq%K(tyK>M2Lc4j-8TLvo^wC)RZ{}3pAK)7MBI+RRz zfzES>ooxVGcm_Jl8`MW2)3{-$%>`-34^&2i&Pg0jo&?1;Xg@P(Y6+CSL1$bIf|1QZ z5yX%M5e%!5ib&9PRztn%hb?SDM_j;;xdJ5vP;*BKo5B$$209`SG)x8x6HqZp<28Q+ z8oHos89`lJkY7P~B?AKkXwBPzI%)td2W{~L9eEB43lIiP_zuUsj~v9o3=9mgVGhtf z^j-!A22c|SS7-~L;%Y$?-IEv?7+`51 zRR4h%z6{QDK^GonVEFT&f#JX#ZibUTj2KS;PGUIoyNluM--Qh4|F2>=`*$hBnLm>l zPXEehIQheo;mAi(hE@=*U;l5f7ln*Z&zAm_Y46(C|N2#lut(RPQeV zZ9svxeL?$OKv(V#o~u7*AAqcdJ@H+F;qY7Fr54Mmf`&We+=jU|Hq2Y{rk#r z_V0OyGryY|j(yf<*nF3XVK?ZeVR$Tp;&}no&;J=27;mvKvFfpaj>P2xjh4XGjRXd0 zmpUDj8|9vGn-a&DXz<(Le{oT#5=LM)=m&d@s06PB=7Z_TWN+fzt`a{=MnLXy&gc8zwrM* z!-2Pt84PVfd-_0e|Br!z5j4dIsta(rW~7OO#)m-tU(j*^P#A&mRR#tI(9{Th`UaPXNSfeey5>N9seV_;Zyk(uGl?>2_>|Nl}w{z2uz#sB{qHs8L^m{6w6kk>(dKMW5O zLE{6UtDRx{U_ogB)HVQJ6$rW-f%(sy`78V!5_TKWuXG{f3UpmYFYgZc}0RJ|hd$VUc-L+^PQ&i>g-)3^u4 zKL~^R1xG*YGMoUd@uxw^4Id*x^#N$tbPP07Qev3_xW>7ZW41Gb1A-XzYNvv~cjltwI%o_Lw1f_{kusKnfx&=*fkB9YfdTtC%h^Am_%~-b z|NjGB;~!K8ocUeEaOFP(L-S(tLSkg=0+k1#^Kq&e7#Kiz%77YEpt1lNgT|9UWd$fb zfW{a>bqHuvEohTHsO@0P$iSe*xc){8!-fC9=^p=Q|4aq90cPwO*)d7E??L$+bcJ+3 z^ax$h@rlUk0G$mgbU}Ry&{)iKrlQ{64423l-v{MkO7PjgD;c)jWn$P1ng*sk5JpX4 z0M+@RrSzcdhD#V27*;VbFkEI}U;v$Y42pB~bO7T2X3TE6G$8SR{{MQ0v%gsw&Vrma z8hca=0Y*?V0GkG?^FjAb8bZgBiy0UgCNeNEfYzPuWME(b9k6qRF~4gU!^MHf|9_S; zOx?l6uxa!tY;bJRj{uD^g05KPW@2DaP*7mp{Vasx{QqC{Zvp)6Wq9%*)B~lT-$!ji z4FT}1&v!kBbN^n`J^oMqOk=qCpMl{Ts3Jmj)+mooApjbIIsAd2;q2dIbd7(|Ov8!q zW(=Sa2s(Ln)EX=yu=+9s!{`4D3}=3~&^7+g{yD&K;4Lr1LC|0}7I%#b(Jur*qi`pG zm@u6C_mWO&;4j1JUpWkS|1&U*_WtP?&$w&?t@=6io`vD;ANtG!ocni<;p7i#hEt%$ z@3XyG93OO%W(2L14B1xJ_^a&QRd(Z z0nnnbJe>G+} z`=^=V+}~r+;bQbDgFg)C{(WRP`}YdN*}t;m@-+;zvU_h||w3k>ONj*9r zw4an8NuCfNw7d`DV327HNFF!u*=d|-fx|NjAT#t#Vp0rLm2asU58_zesPpz-|h0n`~FLqHhB|HA-L2IK!= zKt%h8|NsAgKnk@F_5c4rK$geCKY(N&NIf$DM?KhA3?REe7=v$*CO-)HDDJlh#{x9i z|NsACj~X7>_{iZ0lK;WL0Ew>u5dD7`K#2zw8vp-;!s8!26+rm^8z89xqyiM4{~w_7 z!L9(w{{Ih_N9Kcte?XGM|Ns9%@%{h*A2j|yxO*V-|G=per1c<(`2QcB4@rLi|Nn1> z$TvbLOg>cM0hm10pa;-m17^_&X!`sEbqFN={*#9}6q3FlFv2|Y2W(CQLjhFZKaf5D z7#I|w=Kcpo5GcFC_zj@21|16vbqFX!d_YR459Cqf@dG=U4>AU<;}0Why#HgU2jxb% z{Qm}iP;P~%>;DHBQTZPjysJw!?7i>ENa&ZbOJdpXIY>8SN zqnQ66H6MYj1Qm!N8itY6HAoDdkDSjz@*j}$J(LfQ1`r#Bk<&GZkDRVSeB^Wu;{R_z z1Q(e902GU0)=(le7#J857#J8p!OO@1y;61p0|Nu-ymAl*#p@^@4S~@R7!85Z5Eu=C z(GVC7fzc2c4S~@R7!85Z5MX$nmCbM=C5_>GRu<3CtZc2nSy}GCva&;eXJ-ff$;z_( zk)0#|E+?1me|`bOudM9R5TjBEyvxjDxRQ~>@I5PA@ppE1>A&pk1OKwKU;NL`{_#IM z`|tnk>_7jrv%mby&c6RQJA3t?tnBdbS=s#mGcy^krjDfhw5Sx|NXGok$z}MKldGWc zCp$a!Uv~D5|Jm99{%2?ZCxCzc&CcHOD=XXPYeoj+&rHx^i%6!9GKmU-@0nQ)pEEKA z|7K@Th9-7G;f^l<^lw&H?3eU(reC9RKvbB+6#dN3VfdDv!~Hiqdm6NmK@VGE`EUPZ z=S2Najc53n1G>}#X2U3rD+FGpXEOZnX=V76on7!hJNp-bvW8$h{L9XM@H0ExIMEb)KY*_Wsh?#O2R&CZ_q zKP#T$MOF^Ts!@z31VHKYcUG4DzwGQU$YDnf_P^}x6W_A3`M-_4?iuL3e9)Q5>I@7F zpmUK!7#J8p&2rGW>Fo>*44{cX(0z-O85kJ4iVO_a{mRTFrln7?_C=1jf7#hjerIQ^ z{LUWM-DA+f!~6^k4EhWV44`{!IvE%kHZd?TfbOPv!N9-(I-?#mO%6Kl6D#&nRQ&%d zGn1sSMGj{??00{1at#0G47>6NbPoXNK4s9o@}N7VPe9N6Mh<7teUhMi zF;F}4S9T8H-|Xz3|Jm8!hzM&)9OdNv|DTidA2jm(Cp$a*O_v}I4=K{6GK@J36 zLIq0mw-^{0qCxvk=n>BN?D(9O&G0EJoBelocHCdcm>g)z7ZT1m`e@gpqW-s8Sp1LI z)T{%U{W3QfM9~3*f(}${{9|EY_|L<@@SmT7;V%~h%Nr&JhK~#kNuaJKhBJ`wya)AB zw=gg;=whfEK!HaYSq%UGA7=QHl`ZopJ0}}7y9??|{m;(+3Z0?(`7b;B82t z>>SX^v_G;oY`<9*|1#vbbsEG#h=Y0kS2GBLy5Mip5py2-x zO75-<4F5MVF#P`r+U|h^|6^eI|B`{>-#iA!{{{>U>@o}t4C|mt1#|~4=xQ!dQABlD z4uFBm3=9mQyWK%eH$U3g589pcmydzre-i`4|Mxh;{6BW_ANLs;Y)(PL{xt&wVn7@mD)VEh`xzyR863vw#e zTsasF0(Bxmp1RJ!z#u^#2Z6>IK}P=bB)!xDg*jGylY!y41_J}AM5B%?2Zoz0!C?d!bjv9y&E_>J*82)djLHPe?VEo$#4uAf= zlsk3sn9v6ef6&Anh0SYF+3=4a+OY+tSt{dyix^m*GBPlL`oe=J04a0{XpsvjQ*WiX z4a)S3fr06lFayKCi!@394F6X#F#cjsKMAkbk0R|1I{$yuh__u<};SZWPfI5`|=M6rspoPAm^naLv zfq|QH=iPvY(O)YDhX2o~69@m!Ffja;h0McH?!rN40<8VHjpFtv%wvq-85mgZFfuUw z%VS{p|DD1(c)`H%A2gQ7z`*bZX2WozL6dr*^uL(8W9%R!|FbhN{I6$V`2Us6IC#mx z@IQuu;RoX|P5Yq5kgK2t252EXmD3fdF8&Lu3(^=EKqo$e+mOVxOaC%3{5!|M02;&o zJ6yva6xN{j{&8sdgX#g07?m+-Oz0P=EYf3O_&1e-;r~NCb22{}7(P8@VA#8cf$_8o z1H)tn24>K_3zeNTc#H$h0zYP8VEDejVEVz#!0=aP`~b{PTP|zegKV!fCkt=gFF^gF>!Dj z0$Kq9YIA}TW7i;ZB4{Hbs4oI?*Fvhbi3gDfp-$0;ZWIBP{XS5!!9qncFff2NQG8-x zU>Iy}qgEJ!Hiv-H*cAo_2GBe(walf4IiN-S8=z$)Xkou7H4Gg@W`NqA`=I^<^}hy@ z)8I}4ZG?s`c&?>x-w)DIPDP`$ev z>aUFq;N^YL^R@@255yQ47(nywprR7AZ+bAhmDm6TRcW80d+q&+)ii+WKwUA=Vqs7m zfQG3+#peJzha#&%%{y3nT0e-I{e(P~1l{um>KcH~!~pHVBcx|A%9la+GrR`f+cFp( zh{H{weIhLkkTsy7^(W;FG~YXd#U=aSFfi;ALQ70PTGQjjMt-GJ%du zqu#P@d>%jYk%8gBTV{sSzl<5q{^?{m_wO{rxqq)2&j0_xaQ^=?B6wHhdnGWfZ|}|t%HmOJ)(@Ype^I%J8KZ?1hpYRU1Lz+ z3{)q8*1v$xt^!SMkk>}t^^}3(`hNz7)4x-pbt@u0!@`tQ`ojMo3}=4FG2Hmiz_9u5 zAPh!|odnvf3M!9aXV8Gk+GPw3436Y<@z4BbU^x9tgyGyj@{1m9QFQL_VTR*h1sP6& zTF?}Gc`zCPnlW=?U|;}klLvVcR4jp_0(8V4Xr-kz3llpN!6NwFKL&;~zrDfDN^Ids zw%EU~45xm&GMojq90p_XQO!-D5p2*Nb5KzPYNmqX0aP^IU}Rtfbs<1I4?#zFV6ONE zHG4qC&$)kX6c_#2;_2+4dT_I9;W4Utb`To`>au}GdqG_W&`JZ)atu&hfD+(S1_lOD zvuP^ysH^}61_o=;(Ugor;+hO6e{7;j_@Dc`oMHV9CLCSlK^&A6ISo`UfzmtZ=si$Z z2vi4xX8u5N0mGoU0p*qVj0y@oHyAhHy~A*kh`tuKM2=7F+`nB6C%&;WoB$oyMUkh5 zs%B8fA9Nn52Ll5GXdDT2#s_Ho31}-Q=Es<-u?kRM}9)rNh$@P!H+EH&O6F zGd%35P#K^5cZ}iK7a@jYpz-tJ8FW+u$GW4PNxqoLV$^&Qro?B>(30=0ucqd|rY=l&ffD-O>6J;-qKyB@gBv+}}74^h(n56%aF zL6eYj3}^mKW;p-vEm84s?%x}RvwtQqocJcgaN$402pe%AJ)8;YIQgA{;n){ehSR^S z8P5Kl%y91CC5H3=K0qf4{(|Xq|K2m4`*)Gy+~0`|r+!*8?0?P5a0IlBn2_P4@ovk#!Knc?CM z42)RW3`pXjy;%@N;Ik(nOwiIg&>=1$9;90ZV*UT$zyMl^3TFRf;0Mp-gE&7JKxd6W z?0UcsQU+lkut%^#UOK=4cH2J?33c-ikT0Nq`5^!Q|NjpRAd>w-{r~^}|A74agW&+k zj{l7O|NlRLIh_Chf2d*q|MP<^0U7iE|NnN7L!f~KX2Zq*F+eN_slmnm16OnS{~vfD z;bnuo^8f$;!~YRxVz8lZI1F+dG8^j7!yxxV+3g^IfdT;Hmj?`>V1TfHAhG{*Kodnf zD3qXVkP&~NdO_@e$ZU|n|Njsnh#QdE5N*xiaQ*`}?jV@`1I&H^W`6)X1r#rT7$NKr z_MqrW0L%W6N5sw_q}Tz)bptHq8IeMuq5eMuEZIJgM}*!7W(4~WgB?6ZK#2_&`~N|^ zgds`n|9{ZVZ5aE113cFLBgF`AHo^`6k=*tlDMtPy#mIkU^E0qLtr!n25Sg>$;@K-kdevs zD=S;;9xH1{t%JNaiu2FvfkeSsxWVGK&||8ufIm#g~z%g%m@&+kZbAOB`&C;ZRJVEB*) zx~GvSs|KYa(50Hcv$JLYWoMs5@*my{9YN~;WoO_0ot3Q(x*T{=dW;B1y~)gC_@A8( zx?DORcye4pRRwJNx9X z>}-KSdWkb=V=Cz24p5f`wD25s-X`e&GtkB5pdA6A9ZOqe80PVay!@$4*x}*m*g7T7qff00(Ea=_=(19SJ`!_aA zaB&^D5gq-FO#i?7lbxgWcVOEDpm+w|vI+7t=ztT@B6H9w1Q!_?7#1)vFn~79x-u{@ zXfiP|i!(7Xfp$uPHfn;>KlA>;K(W7BStONxur%^7JNw@6>})wu89D&*5AwGvv?~re z1RS*M4s_r`4FdxM=l~ng!3Cgvj?-yh)6*GVrKB=}E{TQti4^)@cJ{XKS=k&v=-(Cs zZTQf$p>erDd`#1eM)Cv$MJWWoIu#@*BZ$_?Ml%^H)~3 z@GttsJ?J8MP}vPy$h`x4m=4+gh6UFBxHyJ?+2Hn{^1tlt19-y#bdh*&F6bih^MA9m z4M1`KB0U3U6fJ4c*?6F`9JKMjh=Bn-22M5mK$m)h>aaiA*@}O&v*-QK&i;fg9G)g5 z{9o?o_F{KHfMv6p8N=t?d@|htO1hu{e$ZLr|5X?m{yQ)*{C8tu_-o3*@K=O^0d#&f zXdgHDz@7*O1_sd1Ns#|R2l{}@Ju>aZukBk_HpADfY>q$K*^Zz~=0R!ve|Glqf7#i4 z{^#aSNY~Ms%*4nDay$iR_<=@||Fc5R_+P`o@c%Ib!~bs#44_fu{~s6_{$F5V_}|FD z@I;A$fgu%|&q2GXL45okppxwKoIHj{Ir)s=v$EO$WM%Vy$;beeJ0R0Fq3sFK9SR^m zi5TSff4mF~|62*)Onvzd1A_!;bN@mH21e0Aavd*d&m8EiT+lg!piPY=_#d?Y=Qk+c z+Zh=C{{~HM;m5!KGcX+f$iT4Km4N|vWIqYk(N5_U=pCM*%i4*w1>|>d-1`uScPw`W z{M*dH_>-4`5p?bkk=D^x8K}SqrAq_itpSyF|3G(BfX;r$;z!WL4^I4zf#IJo3?_i@VPXNDAxXTgG*YR@z`y{Ce^5Fg z(h5-8|L;Qn-7x>QGBEyP8zgxE)D8okYyfJ1li>e<-V6-?e~}sgdl?x2a14@r7(oZD zf%?%T+}{e0e@hDPC|=3H_=}l=5p=2t5tIi0b&%ozCkzb#bs_#I-bNa#1f_q_!405$bV;xV zlm`BS+WMDB2m{c)Ky?fZKSB4|kYE>0m6B2Zflf1r9gg(hm4V^^eIml(4+F#h`3wyI z1qM;vg8~-R?g7<*X&?@17?cM+UG%U5B+0c`2B)`;ScB@F9Arq2c(ZQ zn`o#SbeJ`${R0|PCc~Pa3=E8*_V8bj-vSvJ{)6sl+R4BGT2b_W6$8W8RSXQ)Cm0w6 zH5nL4XkwG$5;C=b4sZdDDTBt<$ut6{4OAw8?&1O8+s4Jf@E_E-H-}z)2Re%$rf{&( zpz)@43=9mQaaPbtPqc6ss9y;h&jgKaQX!0~>O|0jFOa)PX#0?5zZnAq18A&k@*umD z33PWVDDQ&~dnC(aL}~)%1JI%8pm_{WBK6Q(8R+D=?FLtPC>XVQ0_^-{*`Bj7u3AnYadMEEY7kHywH@L@NUW z19|l?=t2R|Fw>bo77XY9?PNIr|0njd4gS4lxbVM+!94;r5dli~p!>=}^Q{bO0s~ep zgTerG=q>2fLeOEip!+PbMln`F(76Dh!{yKXc4RpB?+$iOP0B%SSY?$3XQt@jo&wk>00 zSPn`8n8pr(2&h~H%?W}|69uIO(A{OAaar8q06JR;bQtuxzx4#;9sT^R3;*6QocV1z z2+uGBjm3cKW6;1js9grCqmmgJ89{f8g4V(yq6T!r^O@hm4CnuyA=&?+@Bo#GH~%v* zfXWYqse^?DS`Pu5j0N>eK;ZzIF9o&LKz*n%=z0)MhK>~;4Cnt7ca{st&&U{5FC72M z&Hy?mY_Rwm(;c983aGpW)eoQ@I-mpcL2Wh=e#2<%eS_ib-|u9_|M`C>zzqaYI>NMf zFp7ZNGz{Q9I-sHgG>x9Y7?IP$aPIGCvV!2;zXJ>>e{eB?j-?rl9wy`_(9u$-f5{P5 z^&uyH82jAc*$f>k7>DdJFQ8*=4!mJzIQMS>8S(#<;q0F<@ZB^!K(jxD0(%h3&pXV( zaPBYYcriPM^WeLTh(G4@+`runr+*1DfSM44&}&3H33SXR=%}Kzf6ItI>h#>dy9{T3 zTQPu+NZki&brEgb;8X}Y;_u9F4hC=-5J(5-{+(wy^Vva|h;=QF=54MnhmU1O{CQkaP$E=%5CW2GCg^ zAR2bK0gQeCJ%KK}ox{{hna|4;o7(D5Jt|I|Z{Jwc{HCs=^^=rrh* z3xqzH{y$Lj{(-&lr~W_q+=f5({||tUwD?i~AAID+59sk2F#5xP@X;dwKSGY*`2X<# z|NqVZ{~vt(|NsAk|Nk>MgHD5hy8S~v_^6WqKjfiyvP0VhT1ZZ#ubW{Wg z54sdP>Y&jOpezLb7Z)>3h)ZYKoSMzBE-jZ~Ve-(}Dh}ET^dmcm8MMXyUv_rIzwGR} z|FW}Z{mstK`R+L{qKKv_Pu}E*(txW zvRMCQWzonL+1bCbZM}hteg2!Boe0{l{xy5>q$$w$slVCT zmjAP}UqjuAbNkr8?Ck4*va=Ni!M1VG)=1D40chrzfr0HuMrJ!9*F)w1{sV3Pr*8~^ zTnbuv=*Gan02=6@$iTp`f`Nenw22pV<=?IiUS3a#-NgGZJG=dVb{50kLePcc8Ja$DrhceADE-8N zHV-13Lj^V{MS~X4Er%}D=w@JGFd=5K05k_%{LjvQ1$84nKV1Eroh=XAFh~VA!;An; zTZEKnJYoz49(JG=5^q-r7;Xi1>Z7Ku9|6B%!e|`)M|6z-GKnpuS8!JJJ`6*s)`aLU~;d53t zs0E?_H#@uJUv~D)f7#hnzoe(%E0iKhk=3SF#xI|K{=Q}vjOb>AmX;^g4UA# zU%|leml=`^@P`bAvY?_9RJ)hqHwT=9Wf>U$UnL?AKwFU$=#v8&LE#T-{ehNr;`Ra~ zXebX92me61;5z|7Y+_*eCrF2|2e}uN{y|4iB!M{iG06SkZ4DI+4FBI^@dKz9+swcK zKK=ky)8RLcIF6&D1H(UC28REW85sT_WMKGzoPpu(4hDwWV+;(j zx(p1#^m02W1VAk

USYs{rwd#Qzx>7=JS|F#HE?G2vlgZ~&FWpmK~rJ|fb1;*~`) zFfbfsU|;|(<0M`ec9ozD-9hUSLA4@w71R|4l|6GA7#OIv^#gR2!deCf26}Dr03C}3 zN;^(e3>H%c1_n@%1r!%lG#0B-prw4985kIFFY&~xji4ZC8~bGj1_n^?mY`xX6@ZQ? z0@>kBrha_dKqDhv(5)i+_!MHufz~v9_z${jP>SK)-*|>||0Xh=`!}26+}|38vwy4@ zeu9o^VE~nxn;94wr!g=vg0^O17()dC(AJJg3=9mQo)~dQ%YfE$t-Z>~aQ3ekbUE`M zv^8Dt7*7A5$RMQvItC7O+#6^+4HcY<(+E(02Av8HT8ax=o{f8XKIob>(Di_4|2Q+8 z|MwKl-H0_==l=a?=vniGK~>j`!InUy8K<*Ik^qfZg)lHMoQ969f$B-j{03SAdgeDj z!?}NZaJn6~X7J+wZwwdz2ZOJ`1uefP$vI>z25pxDErA6c69#IpfZ_v`H$cl{nHWy} z1g(R!XE^_#xOJfC{w-xV{E?Z?*T{nE8_-N4sI3U{1L!!vBMb}-D;XFVCNfk^UBz(m zKj;cXM0$aRIVOFI0Tf@Lcq2PVDbfhqz5_Zs3Dj5uwK=*NN+)b!xbXiU!Sn<6%fEqk zKdR?J>j2OGabP(A{|iy>Klg7r!;w$)PCuw_M&^Oi!RcQD4CnssBf|aP8P5I<17Bx4 zSk^usdd~oM&)L6j4Cntp$Loi4|K>5A`pL}zTIYrw1_R9ox#!qtQ2pfxzP|K4Mqd8N zaPHp}hSR^qz*i`5dpOW8#GcYtSg787>q#>+Pax?_!0w61jKqDm}7ApM{Jl6UD{{ef5c!NBI zW`NQBVEzZt!I+a2;r67KH!*0gQ&I z`w!Lk{{u6~od5s-utVto_D~vBY=J@*>w!T1dQk=j23-aQ2GA^M zC<6mSjJup%-k0=rLRWr#`V3|b)p_Z)Q?pt%IlOeSdiGU#{@&~*f$V`UdJFff3Q zmg}>Xl3M&eHT4_5@cW;g{rg{bb|5G%P{&!|v1w5FEQPLW0L`-dGcYiKjy~XHW@2IC z;t^o@os|W;Hbd%vcJ_4w?tA|?JKKy3;RhOf1C7Uk#*9I8U_lHF44~CGSiSu_JBQ(2 zb`Ime?Cc(V?)#UWy$Q7Hg2MDC!N9-(I+g(xhk*<7jpZ`E_7%9 z%g+A)H!JJPzwB%iQ1s$IWgawj`Uf<{A;`e+Uy*^~ALz7276t~;s5b-X#8S`+0ia=0 zkW-PJfR_y_olbtR7FFU*CUv~ES|Jm7(|L5dfUhLv}!%tDEQk9E~;dwRa(gAEn zfv3ShQ$%764F9Vc82+DTVEF%tf#LrR28RE$85qi97#J8pQ!${Eu0c_Z%@BfOplaer zb`In3>};XG+1ZN!8ybWa6ckukKzrXo%ee3?$pN|WAINo}vw8o4nvtmZv|4bB zi$R2-OGs1zTIK}uJ&vU}pb0pT`~HLM2RGeN-3DpCF);k!!@%$lbeE4v72UnyAHqRz#p93vKY5 z2?`pJQ^DC8bVO+q1H;=$1_s0R3=C}c3=E*@9sDMcDXYl9zyKQGmnBm_X#NsZ#Dm&X zWEz228)(cPRK$>5If2?Jpdu7h72&mr3`tPC7Bs(yBYO~SB4|}PXpRt69TBaG2!)_) zh(Jg3P&)SrnhOHWn}F61;ixLHxCXq({Sza@nco5oXa6cPocSZkaPkK$gQhV^F)srH z1E?KIt-E_bEASw#Kv2sWzmMmGPNMh+nt2vsIQOrD;rzc-4CntpVmSZ*Cd2uE3mFc+ zvt(dktYu(eSj5P{#LEc22L2{|D_nBm;Nl?><6W~nax z|Icvv!y5+AC{T(~WMBf-!PpETTMRU#585yYT2Bp{Q3kDW0j(T^7zmoZy!@Ym;oLva z2^P3#(9Zrj#&GesFvDd~$p+C%WfGKIK&}2g3=9mQ*?UmSAJpC!U}#w+#&GW6F}yP~ z=l_3aIQQ2Re5wYO9fo8aDBM790?hz}N-~ z23pkuo}vA#4=GQO4)g=hCWHAu8P5GJW!U+caX@CMPX1tExb~lc;p|@<2FNTd=+qHV zS_G|PxzBL!Z!yEEpP&*IG*1W#clwi{`QA(5^+AFR=l(h~oco)^aPDsi!`VN|49C7O z(Rn=t{rx{`Bf$^=&!K>ZH$V(j`Uhyc9%zF;XweN4eE`%@{r~?1_zc(o{~I9mKL!V| z_z!-F{D=AnAbmd+|9=3P^MU#Q4-o$W|NsA>?NJZdA@l(x8niV6#7CxK>OVmB{g8*~ z``?eCLFWHI{{KIiKK#E4bjRBNhyNMC^oKgoloZ4NA94`-4+Dh$52GJI`QWK52GHDF zJtQ1JQ&OOrvPMv^0u(&hXwZBUXr>9Y4GDfe0BChCXub)A3C6&v0&+tDG^hv~_xzQW z%?cVc`r8?t@%&iP85ZCl_}0rsBWs?AiabvmZkD51$3i0sYC!W&;g8 z5@QxQYCvZH$<7x1mz}*Cec<(fcJ`Nl+1c@+U7bIuw@VP@Oi(`t)Vc)?tMNUKPl*1X zo&6Jw{h+y#qkpoq`9bjm(ntXYb=*PgZxb097@DCiRnYvxl!>;sNAc{qef%#wTZw{k zd(c2L$WD-5prflnx!IP1fl--(ff3Zo<9n8vnD;+B8?-kcuY=4uL4H{BL(MNy-T6qcT z6MzmY2aRmtR1Vs+3fhDHFFV`oe|Gkj|Jm7pLGJjJn)>%fbo93Wxp`v$azM>?bR)p! zDCjad4+e(+Jq!&0r!X-5k7Z!+uz+6r3|fs&)M&-`>}-ZR8Q{xL<^N@8NB+;vO`l|E zm(9z{3aVtVbnHNVsefz?4F8)L82*1j8gTo?z_8&V1A}b{1H(3S2b0PNT`n+-fq?;( zf)IMyKwIa)e)nQv`2QKnZsY;oTF5RkkUE4`5?P==6DY-^4tj%k*MZFa-;2X;kUI`D zP-iC_sP7Lt{2$?Tg#FX-*ngUV;U7O0c0++y-GXM=5cWgrb5Px$$iVO)bU6{ozvy@t z1H*qNDhy_V><5j!A=wXNg43Tc1H=CfSi%6b+sy!CHz=M!>dD5Sz38A(F*E}}_Jhm@ z?Vkqcfny8||Iaco96Zawu+^D?0Tg5)c{FXLaY1F(LkSxptQgUp6&x(rpm{_ zzz!2Q-)tO8=y41`)k5*{{It`hyBR=(n25m;(7*!> zA7nW5n}-3kM4U{E(X@doQP2QfGy?+zXfU&nVfyY93>U$JFfcoj=}Qb}{|eJ=&jfUr11+tliiK!~ z9RJ1uHvimT9fouNRzTC?D~9v`jxwD48_aOx8)SP7nl`F(k9`3Re1Qi4K}Qg)Fr59X z#c<}20K@XL3=AMSs#-RD3mjD0!01VszfBvBU|M3s?|BwH(|9}3!{Qv&{{15p5w;z!IfAE0){|5~6 z|H0=zI>>_-8vp}>Ym+1c!$a`G6y=Hybv^`H*h-|TFzf7#g?|Fg3}tD3g|%g&Dbn@xF#9@1sX1|7AO zgVu2db=X0jX@(y}9gTzHRZ#5&+E5Ov9YV#qxZVujrU=M*7U4jO6 z{$*!pAuUz~b*w=PL8Cx&Ki~^$LCsXqeT)C)7#RNBF);jBV_=X5jm3eExdH9A#M*>` zcAFLcWoM`T&(7ZdF*S8>x3%@WZd+UK&3+&+f}8?xCWk;*dVOPH`2U!JVd`cE24PbM z2K<@j8|Xm1>}-brd3o$zR#u?q9O#@fQ04;}4(ft{Flb5rb<}Ra-**fQ|E$UA{(zd! zpbe79=7W~%e?>JPRDFVvW`U|BngVsnkv8^%!(Ic+x+G9If$qsB+F+LZW!p^H-(A_v7eW2zwx*R$m)Jg*#(g4c8 z=yD9;R?+ESObloLC@@_7&&;3>stXuEQ`N-Y1q*H(gI4^4A`H}DfLH>$oC(x4KKmDR zJ4rXg`TzSFF8-g#klzVf*#Qn5uuh0-!Xzlmfbtlq(W}P5z{tX|^fc(+3m%5^|JJ}8 z-k?VC?q@Fc13+%Wya!*KrpS~T;o zFr53VLh&p;EQZhh1zkVZ$8i4tL5B1H7BigtYtC@}Kj>OA3@4E#0P47alIWS=pr*;` zUo7C=lc#@?Wf&!z{{R2a@c(~1!~g%x5PX1<;XeZ-!#{Rrh6DD@35@GyqK$fl32-a}1PL zKP^I-RJKO4ic6QUh?Cj8g+1c!%%94Olpn?XRwS`uBc$odm&b|q4 z6@XeaL7*BNhXEk3f(Euhw~~Suo_KUxSrz@w%K8q~532PmA^JfjHMquMWncgwX#pD8 z0aev5&<$QJ{|gF0tt#RF+1YFVXJ>zVpPG92OM1G=w+v9j1*}((f#Lsh28KTy85pXn z7#J8pi*n#j`<)GLm4VC<`k#|y>7$^K%*@Cr%EJmOu$$`d1Kx^_La^RxpFAKxD zf4U4;{~IzWX@UlxJs254X#=7JjRY0%pe-37Hwu8NPlogV5*W_^f5CA6|9ghHhn6r% z$_p{*g60FzbRxK*X(-UNP!NNFa4^H(7boCjA{YK&X1MfUgvcVBnSqOkkKyF^exzb^ zHN)Az3JT!6mJk+VXKlR?TFC{%q73K%U x_zy+~h69ca42=&N7?^)TaQjaNhW3vP43C=`7(OsFF#G_W uml diagrams + ] + +# note: breathe requires doxygen xml output -> must have GENERATE_XML = YES in Doxyfile.in +# match project name in Doxyfile.in +breathe_default_project = "xodoxxml" + +templates_path = ['_templates'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +pygments_style = 'sphinx' + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +#html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' +html_static_path = ['_static'] +html_favicon = '_static/img/favicon.ico' diff --git a/docs/implementation.rst b/docs/implementation.rst new file mode 100644 index 00000000..e325f88c --- /dev/null +++ b/docs/implementation.rst @@ -0,0 +1,202 @@ +.. _implementation: + +.. toctree:: + :maxdepth: 2 + +Library +======= + +Library dependency tower for *xo-alloc*: + +.. ditaa:: + + +------------------------------------------+ + | xo_alloc | + +------------------------------------------+ + | xo_indentlog | + +------------------------------------------+ + +Install instructions :doc:`here` + +Components +========== + +Abstraction tower for *xo-alloc* components: + +.. ditaa:: + :--scale: 0.85 + + +----------------+-------------+ + | IAlloc | Object | + +----------------+-------------+ + + +-------------+ +-------------+ + | GC | | Forwarding1 | + +-------------+ +-------------+ + | ListAlloc | + +-------------+ + | ArenaAlloc | + +-------------+ + +* *IAlloc* + Allocator interface. + +* *Object* + Root Object Interface for types participating in garbage collection + +* *GC* + Incremental compacting garbage collector. + +* *ListAlloc* + Auto-expanding allocator. Contains a collection of ArenaAllocs + +* *ArenaAlloc* + Arena allocator (a.k.a bump allocator). + +* *Object* + Interface for types that participate in garbage collection + +* *Forwarding1* + Forwarding pointer. Supports the Object interface; + used internally by GC during evacuation. + +Key Points +---------- + +* Allocators can be reset, but do not support freeing of individual allocs. +* GC works with types that implement auxiliary GC-support methods. + Such types must inherit Object. +* A region may uses multiple arenas, but because of allocation activity + since the last GC. If necessary, GC will allocate a new to-space with a + single arena that's large enough to accomodate all objects that might survive + from a from-space that has acquired multiple arenas. + Intent is to scale up to find application's working set size, then stabilize + +Components +========== + +Allocators +---------- + +Inheritance +^^^^^^^^^^^ + +.. uml:: + :caption: allocators + :scale: 99% + :align: center + + class IAlloc { + + alloc() + + alloc_gc_copy() + + checkpoint() + + clear() + } + + class ArenaAlloc { + + free_ptr() + - lo_ : byte* + - checkpoint_ : byte* + - limit_ : byte* + } + + IAlloc <|-- ArenaAlloc + + class ListAlloc { + + expand() + + free_ptr() + - start_z_ + - hd_ + - full_l_ + } + + IAlloc <|-- ListAlloc + + class GC { + + add_gc_root() + + request_gc() + + gc_statistics() + - gc_root_v_[] : Object** + - nursery_[2] : ListAlloc* + - tenured_[2] : ListAlloc* + } + + IAlloc <|-- GC + + +Composition +^^^^^^^^^^^ + +.. uml:: + :caption: allocator composition + :scale: 99% + :align: center + + object gc<> + gc : nursery[from] = n0 + gc : nursery[to] = n1 + gc : tenured[from] = t0 + gc : tenured[to] = t1 + + object n0<> + + object n1<> + + object t0<> + + object t1<> + + gc o-- n0 + gc o-- n1 + gc o-- t0 + gc o-- t1 + + +Each ListAlloc composes like this: + +.. uml:: + :caption: ListAlloc composition + :scale: 99% + :align: center + + object x<> + x : hd_ = a0 + x : full_l = {a1, a2} + + object a0<> + a0 : lo_ = 0 + a0 : free_ = 12345 + a0 : hi_ = 1000000 + + object a1<> + + object a2<> + + x o-- a0 + x o-- a1 + x o-- a2 + +Here *a1* and *a2* are full, while *a0* can still allocate memory. + +Objects + +.. uml:: + :caption: objects + :scale: 99% + :align: center + + class Object { + + _is_forwarded() + + _offset_destination() + + _forward_to() + + _destination() + + _shallow_size() + + _shallow_copy() + + _forward_children() + } + + class Forwarding1 { + - dest_ : Object* + } + + Object <|-- Forwarding1 diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..198cf01c --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,14 @@ +# xo-alloc documentation master file + +xo-alloc documentation +====================== + +xo-alloc provides arena allocators and a generation garbage collector + +.. toctree:: + :maxdepth: 2 + :caption: xo-alloc contents + + install + introduction + implementation diff --git a/docs/install.rst b/docs/install.rst new file mode 100644 index 00000000..ab356be5 --- /dev/null +++ b/docs/install.rst @@ -0,0 +1,120 @@ +.. _install: + +.. toctree:: + :maxdepth: 2 + +Source +====== + +Source code lives on github `here`_ + +.. _here: https://github.com/rconybea/xo-alloc + +To clone from git: + +.. code-block:: bash + + git clone https://github.com/rconybea/xo-alloc + +Tested with gcc 13.3 + +Install +======= + +One-step Install +---------------- + +Install along with the reset of *XO* from `xo-umbrella2 source`_ + +.. _xo-umbrella2 source: https://github.com/rconybea/xo-umbrella2 + +Minimal Install +--------------- + +To build+install just required dependencies: +``xo-alloc`` uses several supporting libraries from the *XO* project: + +- `xo-indentlog source`_ (structured logging) +- `xo-cmake source`_ (shared cmake macros) + +.. _xo-indentlog source: https://github.com/rconybea/indentlog +.. _xo-cmake source: https://github.com/rconybea/xo-cmake + +Building from source +-------------------- + +Install scripts for XO libraries depend on helper scripts installed from `xo-cmake`. + +Preamble: + +.. code-block:: bash + + mkdir -p ~/proj/xo + cd ~/proj/xo + + git clone https://github.com/rconybea/xo-cmake + + PREFIX=/usr/local # ..or desired installation prefix + + # want PREFIX/bin in PATH to use xo-cmake helpers + PATH=$PREFIX/bin:$PATH + +Install `xo-cmake`: + +.. code-block:: bash + + cmake -B xo-cmake/.build -S xo-cmake + cmake --install xo-cmake/.build + +Install remaining dependencie(s) in topological order: + +.. code-block:: bash + + xo-build --clone --configure --build --install xo-indentlog + xo-build --clone --configure --build --install xo-alloc + +Directories under ``PREFIX`` will then contain: + +.. code-block:: + + PREFIX + +- bin + | +- xo-build + | +- xo-cmake-config + | \- xo-cmake-lcov-harness + +- include + | \- xo + | +- alloc/ + | \- indentlog/ + +- lib + | +- cmake + | | +- xo_alloc/ + | | \- indentlog/ + | +- lib*.so + +- share + +- cmake + | \- xo_macros + | +- code-coverage.cmake + | +- xo-project-macros.cmake + | \- xo_cxx.cmake + +- etc + | \- xo + | \- subsystem-list + \- xo-macros + +- Doxyfile.in + +- gen-ccov.in + \- xo-bootstrap-macros.cmake + +CMake Support +------------- + +To use built-in cmake support, when using ``xo-alloc`` from another project: + +Make sure ``PREFIX/lib/cmake`` is searched by cmake (for example include it in ``CMAKE_PREFIX_PATH``) + +Add to your ``CMakeLists.txt``: + +.. code-block:: cmake + + FindPackage(xo_alloc CONFIG REQUIRED) + target_link_libraries(mytarget INTERFACE xo_alloc) diff --git a/docs/introduction.rst b/docs/introduction.rst new file mode 100644 index 00000000..7b5333cf --- /dev/null +++ b/docs/introduction.rst @@ -0,0 +1,268 @@ +.. _introduction: + +.. toctree + :maxdepth: 2 + +Introduction +============ + +The ``xo-alloc`` library provides a in incremental, generational collector for c++ code. + +Features: + +* *incremental* - can reasonably expect short pause times. +* *generational* - focuses effort on collecting young objects, + on the basis that they're more likely to be garbage. +* *compacting* - each garbage collection cycle evacuates survivors to contiguous memory, + so effect is to defragment. +* *collects cycles* - collection algorithm naturally collects cyclic references + +Tradeoffs: + +* Application is responsible for spilling register values and protecting hardware stack, + since garbage collector cannot indepndently distinguish collectable object pointers from + non-pointer values. + +* GC will not spontaneously run without permission. Instead will set a pending bit, with GC + occurring only when application releases it (e.g. when stack+registers are known to be empty of values + subject to GC). + +* GC implementation is single-threaded. It cannot run in parallel with the mutator (i.e. application code) + In return this allows GC to be only lightly coupled with application. + +* GC divides each generation into separate from- and to- spaces. A collection cycle copies surviving + objects out of from-space. Once complete, the entire from-space is treated as empty, and available to + become to-space on a future cycle. This means that at any time only half of allocated memory is available + to the application; the rest is waiting to receive survivors from the next GC cycle. + +Design +------ + +Garbage Collector +^^^^^^^^^^^^^^^^^ + +The garbage collector supports two generations, labelled *nursery* and *tenured*. +Nursery objects that survive two collection cycles are promoted to tenured space. +Nursery and tenured objects are kept in separate memory areas, instead of being interspersed. + +Collection cycles come in two flavors: + +1. *incremental* collections - these collect only the nursery space. + +2. *full* collections - these collect both nursery and tenured spaces. + Full collection may incur noticeable GC pauses. + +Application Interaction +^^^^^^^^^^^^^^^^^^^^^^^ + +Application code that interacts with GC has several responsibilities. + +1. application must explicitly invoke GC, when convenient. Since in general any GC-eligible object + may get moved by the collector: once a collection cycle completes, + it's up to the application to re-load pointers from memory addresses + (GC roots) that have been shared with the collector. + +2. application must identify a set of GC roots. GC preserves everything reachable from any GC root + +3. The collector needs to know how to traverse GC-managed objects. + We teach it this by requiring that such objects inherit the ``xo::Object`` interface, + and implement auxiliary function detailed below. + +4. GC also needs to know when a mutation alters a pointer from one GC-managed object to another. + In particular, GC needs to track pointers from tenured space into nursery space, + and update them when an incremental collection moves nursery objects. + We do this by requiring application code use a GC-provided assignment primitive + on GC-eligible pointers. + + +Example GC Use +-------------- + +.. code-block:: cpp + :linenos: + + #include "xo/object/List.hpp" // polymorphic List with GC support + #include "xo/object/String.hpp" // string type with GC support + #include "xo/alloc/GC.hpp" + + int main() { + using xo::gc::Config; + using xo::obj::String; + using xo::obj::List; + using xo::gp; + + Config config = { .initial_nursery_z_ = 50*1000, + .initial_tenured_z_ = 10*1000*1000, + .debug_flag_ = false }; + + up gc = GC::make(config); + + Object::mm = gc; // use GC for allocation of Object (+ derived classes) + + gc->disable_gc(); // gc forbidden + + // tiny example data structure + gp s1 = String::copy("hello"); + gp s2 = String::copy(", "); + gp s3 = String::copy("world!"); + gp list = List::cons(s1, List::cons(s2, List::cons(s3, List::nil))); + + // tell GC what to preserve + gc->add_gc_root(reinterpret_cast(list.ptr_address()); + + gc->enable_gc(); // triggers immediate gc + + // s1, s2, s3 invalid. + // list at new address + + std::cout << "list.size=" << list->size << std::endl; + } + +GC-Eligible Types +----------------- + +Or, how to inherit ``xo::Object`` and provide GC support + +A type Foo that inherits ``xo::Object`` needs to provide overrides for Object methods ``_shallow_size()``, +``_shallow_copy()`` and ``_forward_children()``: + +Typical Pattern +^^^^^^^^^^^^^^^ + +GC support methods look something like this: + +* class definition + +.. code-block:: cpp + :linenos: + + #include "xo/alloc/Object.hpp" + + namespace xo { + class Foo : public xo::Object { + public: + ... + virtual std::size_t _shallow_size() const override; + virtual Object * _shallow_copy() const override; + virtual std::size_t _forward_children() override; + }; + } + +* use overloaded ``operator new`` + +A GC-eligible class will allocate instances using the ``MMPtr`` overload. +This allocates memory in GC-owned space + +.. code-block::cpp + :linenos: + + gp Foo::make(...) { + ... + return new MMPtr(mm) Foo(...); + } + +* ``_shallow_size()`` returns the amount of memory used by the subject: + +.. code-block:: cpp + :linenos: + + std::size_t Foo::_shallow_size() const { return sizeof(Foo); } + +* ``_shallow_copy()`` is invoked during GC to create a copy of the subject + + It should use the ``xo::Cpof`` argument to ``operator new``. + +.. code-block:: cpp + :linenos: + + Object * + Foo::_shallow_copy() const; + +* ``_forward_children()`` is invoked during GC to vist child ``xo::Object`` pointers + to make sure they survive + +.. code-block:: cpp + :linenos: + + std::size_t + Foo::_forward_children(); + +Atomic Types Without Object Pointers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Plain-old-data classes without embedded pointers + +.. code-block:: cpp + :linenos: + + Object * + Foo::_shallow_copy() const { + return new (Cpof(this)) Foo(*this); + } + +.. code-block:: cpp + :linenos: + + std::size_t + Foo::_forward_children() { return Foo::_shallow_size(); } + +For example see ``xo::obj::String`` in ``xo-object`` + +Non-GC Objects +^^^^^^^^^^^^^^ + +A class *Foo* that inherits ``xo::Object`` can opt-out of garbage collection by +omitting the ``MMptr(mm)`` overload. + +In that case `Foo::_shallow_size()`, `Foo::_shallow_copy()` and `Foo::_forward_children()` +will not be called: + +.. code-block:: cpp + :linenos: + + std::size_t Foo::_shallow_size() const { return sizeof(Foo); } + Object * Foo::_shallow_copy() const { assert(false); return nullptr; } + std::size_t Foo::_forward_children() { assert(false); return 0; } + +For example see ``xo::obj::Boolean`` in ``xo-object`` + +Structs Containing Object Pointers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A class with object pointers needs to tell GC how to traverse them + +.. code-block:: cpp + :linenos: + + #include "xo/alloc/Object.hpp" + + namespace xo { + class Foo : public xo::Object { + public: + ... + virtual std::size_t _shallow_size() const override; + virtual Object * _shallow_copy() const override; + virtual std::size_t _forward_children() override; + + private: + gp bar_; + gp quux_; + }; + } + +* ``_forward_children()`` is invoked during GC to fixup child pointers + that refer to forwarding objects: + +.. code-block:: cpp + :linenos: + + std::size_t + Foo::_forward_children() + { + Object::_forward_inplace(bar_); + Object::_forward_inplace(quux_); + + return Foo::_shallow_size(); + } + +For example see ``xo::obj::List`` in ``xo-object`` diff --git a/include/xo/alloc/AllocPolicy.hpp b/include/xo/alloc/AllocPolicy.hpp new file mode 100644 index 00000000..53f758ee --- /dev/null +++ b/include/xo/alloc/AllocPolicy.hpp @@ -0,0 +1,58 @@ +/* AllocPolicy.hpp + * + * author: Roland Conybeare, Jul 2025 + */ + +#include + +namespace xo { + /** Tag class, drives overload of operator new. + * See also: xoglobal, xocopy + **/ + struct xolib { + xolib() = default; + }; + + /** @brief opt-in allocator for XO libraries. + * + * By default delegates to vanilla operator new/delete, + * but can set alloc/free functions at runtime to + * adopt a different implementation. + * + * Intending this to op-in to garbage-collector? + * Not sure if we actually need this + * + * Use: + * struct Foo { .. }; + * auto p = new (xo) Foo(..); + **/ + class XoAllocPolicy { + public: + using AllocFn = void* (*)(std::size_t); + using FreeFn = void (*)(void *); + + public: + XoAllocPolicy() = default; + + static void * global_alloc(std::size_t z) { return ::operator new(z); } + static void global_free(void * x) { ::operator delete(x); } + + void * alloc(std::size_t z) { return (*alloc_)(z); } + void free(void * x) { (*free_)(x); } + + private: + AllocFn alloc_ = global_alloc; + FreeFn free_ = global_free; + }; + + /** singleton xolib instance **/ + static XoAllocPolicy xo; +} + +inline void * operator new(std::size_t z, xo::xolib) { + return xo::xo.alloc(z); +} + +void operator delete(void * ptr) noexcept; + +/* end AllocPolicy.hpp */ diff --git a/include/xo/alloc/LinearAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp similarity index 61% rename from include/xo/alloc/LinearAlloc.hpp rename to include/xo/alloc/ArenaAlloc.hpp index e1390dfc..e2e74e8f 100644 --- a/include/xo/alloc/LinearAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -1,4 +1,4 @@ -/* file LinearAlloc.hpp +/* file ArenaAlloc.hpp * * author: Roland Conybeare, Jul 2025 */ @@ -9,7 +9,7 @@ namespace xo { namespace gc { - /** @class LinearAlloc + /** @class ArenaAlloc * @brief Bump allocator with fixed capacity * * @text @@ -33,34 +33,39 @@ namespace xo { * * TODO: rename to ArenaAlloc **/ - class LinearAlloc : public IAlloc { + class ArenaAlloc : public IAlloc { public: - ~LinearAlloc(); + ~ArenaAlloc(); /** create allocator with capacity @p z, * with reserved capacity @p redline_z. **/ - static up make(std::size_t redline_z, std::size_t z); + static up make(const std::string & name, + std::size_t redline_z, + std::size_t z, + bool debug_flag); - std::uint8_t * free_ptr() const { return free_ptr_; } - void set_free_ptr(std::uint8_t * x); + const std::string & name() const { return name_; } + std::byte * free_ptr() const { return free_ptr_; } + void set_free_ptr(std::byte * x); // inherited from IAlloc... virtual std::size_t size() const override; virtual std::size_t available() const override; virtual std::size_t allocated() const override; - virtual bool is_before_checkpoint(const std::uint8_t * x) const override; + virtual bool contains(const void * x) const override; + virtual bool is_before_checkpoint(const void * x) const override; virtual std::size_t before_checkpoint() const override; virtual std::size_t after_checkpoint() const override; virtual void clear() override; virtual void checkpoint() override; - virtual std::uint8_t * alloc(std::size_t z) override; - + virtual std::byte * alloc(std::size_t z) override; + virtual void release_redline_memory() override; private: - LinearAlloc(std::size_t rz, std::size_t z); + ArenaAlloc(const std::string & name, std::size_t rz, std::size_t z, bool debug_flag); private: /** @@ -68,23 +73,30 @@ namespace xo { * - @ref free_ always a multiple of word size (assumed to be sizeof(void*)) **/ + /** optional instance name, for diagnostics **/ + std::string name_; + /** allocator owns memory in range [@ref lo_, @ref hi_) **/ - std::uint8_t * lo_ = nullptr; + std::byte * lo_ = nullptr; /** checkpoint (for GC support); divides objects into * older (addresses below checkpoint) * and younger (addresses above checkpoint) **/ - std::uint8_t * checkpoint_; + std::byte * checkpoint_; /** free pointer. memory in range [@ref free_, @ref limit_) available **/ - std::uint8_t * free_ptr_ = nullptr; + std::byte * free_ptr_ = nullptr; /** soft limit: end of released memory **/ - std::uint8_t * limit_ = nullptr; + std::byte * limit_ = nullptr; + /** amount of last-resort memory to reserve **/ + std::size_t redline_z_ = 0; /** hard limit: end of allocated memory **/ - std::uint8_t * hi_ = nullptr; + std::byte * hi_ = nullptr; + /** true to enable detailed debug logging **/ + bool debug_flag_ = false; }; } /*namespace gc*/ } /*namespace xo*/ -/* end LinearAlloc.hpp */ +/* end ArenaAlloc.hpp */ diff --git a/include/xo/alloc/Forwarding.hpp b/include/xo/alloc/Forwarding.hpp new file mode 100644 index 00000000..47a555da --- /dev/null +++ b/include/xo/alloc/Forwarding.hpp @@ -0,0 +1,28 @@ +/* Forwarding.hpp + * + * author: Roland Conybeare, Jul 2025 + */ + +#pragma once + +#include "Object.hpp" + +namespace xo { + namespace gc { + class Forwarding : public Object { + public: + Forwarding() = default; + + // inherited from Object.. +#ifdef NOT_USING + virtual bool _is_forwarded() const override final { return true; } +#endif + virtual Object * _destination() override final { return destination_.ptr(); } + + private: + gp destination_; + }; + } /*namespace gc*/ +} /*namespace xo*/ + +/* end Forwarding.hpp */ diff --git a/include/xo/alloc/Forwarding1.hpp b/include/xo/alloc/Forwarding1.hpp new file mode 100644 index 00000000..62536651 --- /dev/null +++ b/include/xo/alloc/Forwarding1.hpp @@ -0,0 +1,40 @@ +/* file Forwarding1.hpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "Object.hpp" + +namespace xo { + namespace obj { + class Forwarding1 : public Object { + public: + explicit Forwarding1(gp dest); + + // inherited from Object.. + virtual bool _is_forwarded() const override { return true; } + virtual Object * _offset_destination(Object * src) const; + virtual std::size_t _shallow_size() const override; + virtual Object * _shallow_copy() const override; + virtual std::size_t _forward_children() override; + + private: + /** the object that used to be located at this address (i.e. @c this) + * has been moved to @ref destination_ , + * with original location overwritten by a forwarding pointer + * + * Require: + * - can only use Forwarding with types that have a single vtable. + * To forward a multiply-inheriting class with two vtables, use Forwarding2. + * - if you try to use Forwarding for an object with multiple vtables, + * one of the vtable pointers will be replaced by @ref destination_. + * UB revealed when GC traverses a pointer that relies on the 2nd + * vtable to index virtual methods. + **/ + gp dest_; + }; + + } /*namespace obj*/ +} /*namespace xo*/ + +/* end Forwarding1.hpp */ diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp new file mode 100644 index 00000000..f42864b7 --- /dev/null +++ b/include/xo/alloc/GC.hpp @@ -0,0 +1,310 @@ +/* GC.hpp + * + * author: Roland Conybeare, jul 2025 + */ + +#pragma once + +#include "ListAlloc.hpp" +#include "xo/indentlog/print/array.hpp" +#include +#include + +namespace xo { + /** types that can participate in GC inherit from this base class. See Object.hpp in this directory **/ + class Object; + + namespace gc { + enum class generation { + nursery, + tenured, + N + }; + + constexpr std::size_t gen2int(generation x) { return static_cast(x); } + + enum class role { + /** nursery: generation for new objects **/ + from_space, + /** tenured: generation for objects that have survived two collections **/ + to_space, + N, + }; + + constexpr std::size_t role2int(role x) { return static_cast(x); } + + /** @class Config + * @brief garbage collector configuration + **/ + struct Config { + /** initial size in bytes for youngest (Nursery) generation. + * GC allocates two nursery spaces of this size. + * Will allocate more space as needed + **/ + std::size_t initial_nursery_z_ = 0; + /** initial size in bytes for oldest (Tenured) generation. + * GC allocates two tenured spaces of this size + * Will allocate more space as needed + **/ + std::size_t initial_tenured_z_ = 0; + /** true to permit incremental garbage collection **/ + bool allow_incremental_gc_ = true; + /** true to enable debug logging **/ + bool debug_flag_ = false; + }; + + /** @class ObjectStatistics + * @brief placeholder for type-driven allocation statistics + * + * Passed to @ref Object::deep_move for example + **/ + class ObjectStatistics { + }; + + /** @class PerGenerationStatistics + * @brief garbage collection statistics for particular GC generation + **/ + class PerGenerationStatistics { + public: + /** update statistics after a GC cycle + * @param alloc_z. new allocations (since preceding GC) + * @param before_z. generation size (bytes allocated) before collection + * @param after_z. generation size after collection + * @param promote_z. bytes promoted to next generation + **/ + void include_gc(std::size_t alloc_z, std::size_t before_z, std::size_t after_z, + std::size_t promote_z); + /** update with current state (use at end of gc cycle) **/ + void update_snapshot(std::size_t after_z); + + /** @param os. write stats on this output stream **/ + void display(std::ostream & os) const; + + /** number of bytes currently in use **/ + std::size_t used_z_ = 0; + + /** number of collection cycles completed **/ + std::size_t n_gc_ = 0; + /** sum of new alloc bytes, sampled at start of each collection cycle **/ + std::size_t new_alloc_z_ = 0; + /** sum of allocated bytes sampled at beginning of each collection cycle **/ + std::size_t scanned_z_ = 0; + /** sum of bytes remaining after collection cycle **/ + std::size_t survive_z_ = 0; + /** sum of bytes promoted to next generation **/ + std::size_t promote_z_ = 0; + }; + + inline std::ostream & operator<< (std::ostream & os, const PerGenerationStatistics & x) { + x.display(os); + return os; + } + + /** @class GcStatistics + * @brief garbage collection statistics + **/ + class GcStatistics { + public: + /** update statistics after a GC cycle + * @param upto. nursery -> incremental collection; tenured -> full collection + * @param alloc_z. new allocations (since preceding GC) + * @param before_z. generation size (bytes allocated) before collection + * @param after_z. generation size after collection + * @param promote_z. bytes promoted to next generation + **/ + void include_gc(generation upto, std::size_t alloc_z, + std::size_t before_z, std::size_t after_z, std::size_t promote_z); + /** update snapshot for current state. + * Use with tenured stats after incremental gc + **/ + void update_snapshot(generation upto, std::size_t after_z); + + /** @param os. write stats on this output stream **/ + void display(std::ostream & os) const; + + /** statistics gathered across {incr, full} GCs respectively **/ + std::array(generation::N)> gen_v_; + /** total bytes allocated since inception **/ + std::size_t total_allocated_ = 0; + /** snapshot of total bytes promoted asof beginning of last gc cycle **/ + std::size_t total_promoted_sab_ = 0; + /** total bytes promoted from nursery->tenured since inception **/ + std::size_t total_promoted_ = 0; + + /** per-type statistics (placeholder) **/ + ObjectStatistics per_type_stats_; + }; + + inline std::ostream & operator<< (std::ostream & os, const GcStatistics & x) { + x.display(os); + return os; + } + + /** @class GCRunstate + * @brief encapsulate state needed while GC is running + * + * state pertaining to a single GC invocation. + * We stash an instance of this in @ref GC as context, + * so that per-Object-derived-type auxiliary functions can be slightly streamlined + **/ + class GCRunstate { + public: + GCRunstate() = default; + explicit GCRunstate(bool in_progress, bool full_move) + : in_progress_{in_progress}, full_move_{full_move} {} + + bool in_progress() const { return in_progress_; } + bool full_move() const { return full_move_; } + + private: + /** true when GC begins; remains true until GC cycle complete **/ + bool in_progress_ = false; + /** true for full GC; false for incremental GC **/ + bool full_move_ = false; + }; + + /** @class GC + * @brief generational garbage collector + * + * Works with objects of type @ref xo::Object + **/ + class GC : public IAlloc { + public: + /** create new GC instance with configuration @p config **/ + explicit GC(const Config & config); + + /** create GC allocator. + * + * Initial memory consumption: + * approximately 2x @ref Config::nursery_size_ + 2x @ref Config::tenured_size_ + **/ + static up make(const Config & config); + + const GCRunstate & runstate() const { return runstate_; } + const GcStatistics & gc_statistics() const { return gc_statistics_; } + + /** true iff GC permitted in current state **/ + bool is_gc_enabled() const { return gc_enabled_ == 0; } + /** @return generation to which object at @p x belongs **/ + generation generation_of(const void * x) const; + /** @return generation that contains @p x, given it's in from-space **/ + generation fromspace_generation_of(const void * x) const; + /** true iff from-space contains @p x **/ + bool fromspace_contains(const void * x) const; + /** true during (and only during) a GC cycle **/ + bool gc_in_progress() const { return runstate_.in_progress(); } + /** return free pointer for generation @p gen, i.e. nursery or tenured space **/ + std::byte * free_ptr(generation gen); + + /** add gc root at address @p addr . Gc will keep alive anything reachable + * from @c *addr + **/ + void add_gc_root(Object ** addr); + /** request garbage collection. **/ + void request_gc(generation g); + /** disable garbage collection until matching call to @ref enable_gc. + * + * GC is disabled when number of calls to @ref disable_gc exceeds number of + * calls to @ref enable_gc. + **/ + void disable_gc(); + /** enable garbage collection + * + * GC is enabled when number of calls to @ref enable_gc is at least as large + * as number of calls to @ref disable_gc. + **/ + void enable_gc(); + + // inherited from IAlloc.. + + /** capacity in bytes (counting both free+allocated) for object storage. + * only counts one of {to-space, from-space}, + * since one role is always held empty between collections. + **/ + virtual std::size_t size() const override; + + virtual std::size_t allocated() const override; + virtual std::size_t available() const override; + /** only tests to-space **/ + virtual bool contains(const void * x) const override; + virtual bool is_before_checkpoint(const void * x) const override; + virtual std::size_t before_checkpoint() const override; + virtual std::size_t after_checkpoint() const override; + + virtual void clear() override; + virtual void checkpoint() override; + + virtual std::byte * alloc(std::size_t z) override; + virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) override; + + virtual void release_redline_memory() override; + + private: + /** begin GC now **/ + void execute_gc(generation g); + /** cleanup phase. aux function for @ref execute_gc **/ + void cleanup_phase(generation g); + /** swap roles of From/To spaces for nursery generation **/ + void swap_nursery(); + /** swap roles of From/To spaces for tenured generation **/ + void swap_tenured(); + /** swap roles of FromSpace/ToSpace **/ + void swap_spaces(generation g); + /** copy object **/ + void copy_object(Object ** addr, generation upto, ObjectStatistics * object_stats); + /** copy everything reachable from global gc roots **/ + void copy_globals(generation g); + + private: + /** garbage collector configuration **/ + Config config_; + + /** contains allocated objects, along with unreachable garbage to be collected. + * roles reverse after each incremental, or full, collection. + **/ + std::array, static_cast(role::N)> nursery_; + /** empty space, destination for objects that survive collection. + * roles reverse after each full collection. + **/ + std::array, static_cast(role::N)> tenured_; + + /** current state of GC activity. + * @text + * in_progress full_move descr + * ----------------------------------------- + * false * gc not running + * true false incremental gc + * true true full gc + * ----------------------------------------- + * @endtext + **/ + GCRunstate runstate_; + + /** root object handles: targets of handles in this vector are always preserved by GC. + * Application can introduce new root object pointers at any time provided GC not running, + * but cannot withdraw them. + **/ + std::vector gc_root_v_; + + /** allocation/collection counters **/ + GcStatistics gc_statistics_; + + /** trigger full GC whenever this much data arrives in tenured generation **/ + std::size_t full_gc_threshold_ = 0; + /** trigger incr GC whenever this much data arrives in nuresery generation **/ + std::size_t incr_gc_threshold_ = 0; + + /** true when GC requested, + * remains true until GC.. completes? begins? + **/ + bool incr_gc_pending_ = false; + bool full_gc_pending_ = false; + + /** enabled when 0. disabled when <0 **/ + int gc_enabled_ = 0; + }; + } /*namespace gc*/ + +} /*namespace xo*/ + +/* end GC.hpp */ diff --git a/include/xo/alloc/GCAlloc.hpp b/include/xo/alloc/GCAlloc.hpp deleted file mode 100644 index e0c6ab7a..00000000 --- a/include/xo/alloc/GCAlloc.hpp +++ /dev/null @@ -1,20 +0,0 @@ -/* file GCAlloc.hpp - * - * author: Roland Conybeare, Jul 2025 - */ - -#pragma once - -namespace xo { - namespace gc { - class GC : public IAlloc { - enum class Space { A, B, N_Space }; - enum class Gen { Nursery, Tenured }; - - }; - - } /*namespace mem */ -} /*namespace xo*/ - - -/* end GCAlloc.hpp */ diff --git a/include/xo/alloc/IAlloc.hpp b/include/xo/alloc/IAlloc.hpp index 848f182c..2f759c53 100644 --- a/include/xo/alloc/IAlloc.hpp +++ b/include/xo/alloc/IAlloc.hpp @@ -20,6 +20,13 @@ namespace xo { public: virtual ~IAlloc() {} + /** compute padding to add to an allocation of size z to bring it up to + * a multiple of word size (8 bytes on x86_64) + **/ + static std::uint32_t alloc_padding(std::size_t z); + /** z + alloc_padding(z) **/ + static std::size_t with_padding(std::size_t z); + /** allocator size in bytes (up to soft limit). * Includes unallocated mmeory **/ @@ -30,10 +37,12 @@ namespace xo { virtual std::size_t available() const = 0; /** number of bytes allocated from this allocator **/ virtual std::size_t allocated() const = 0; + /** true iff pointer x comes from this allocator **/ + virtual bool contains(const void * x) const = 0; /** true iff object at address @p x was allocated by this allocator, * and before checkpoint **/ - virtual bool is_before_checkpoint(const std::uint8_t * x) const = 0; + virtual bool is_before_checkpoint(const void * x) const = 0; /** number of bytes allocated before @ref checkpoint **/ virtual std::size_t before_checkpoint() const = 0; /** number of bytes allocated since @ref checkpoint **/ @@ -48,10 +57,39 @@ namespace xo { **/ virtual void checkpoint() = 0; /** allocate @p z bytes of memory. returns pointer to first address **/ - virtual std::uint8_t * alloc(std::size_t z) = 0; + virtual std::byte * alloc(std::size_t z) = 0; + /** allocate @p z bytes for copy of object at @p src. + * Only used in @ref GC. Default implementation asserts and returns nullptr + **/ + virtual std::byte * alloc_gc_copy(std::size_t z, const void * src); + /** release last-resort reserved memory **/ + virtual void release_redline_memory() = 0; }; } /*namespace gc*/ + + class MMPtr { + public: + explicit MMPtr(gc::IAlloc * mm) : mm_{mm} {} + + gc::IAlloc * mm_ = nullptr; + }; } /*namespace xo*/ +inline void * operator new (std::size_t z, const xo::MMPtr & mmp) { + return mmp.mm_->alloc(z); +} + +//inline void operator delete (void * p, const MMPtr & mmp) { +// mmp.mm_->free(reinterpret_cast(p)); +//} + +inline void * operator new[] (std::size_t z, const xo::MMPtr & mmp) { + return mmp.mm_->alloc(z); +} + +//inline void operator delete[] (void * p, const MMPtr & mmp) { +// mmp.mm_->free(reinterpret_cast(p)); +//} + /* end IAlloc.hpp */ diff --git a/include/xo/alloc/ListAlloc.hpp b/include/xo/alloc/ListAlloc.hpp index 780d2bd2..8d27e6b4 100644 --- a/include/xo/alloc/ListAlloc.hpp +++ b/include/xo/alloc/ListAlloc.hpp @@ -6,13 +6,17 @@ #pragma once #include "IAlloc.hpp" +#include #include #include namespace xo { namespace gc { + class ArenaAlloc; + /** GC-compatible allocator using a linked list of buckets. * + * - all allocs done from first allocator in list * GC Support: * - reserved memory, released after call to @ref release_redline_memory. * @@ -21,27 +25,60 @@ namespace xo { **/ class ListAlloc : public IAlloc { public: - ListAlloc(LinearAlloc* hd, - std::size_t cz, std::size_t nz; std::size_tz, - LinearAlloc* marked, bool use_redline, - bool redlined_flag, OnEmptyFn on_overflow); + ListAlloc(std::unique_ptr hd, + ArenaAlloc * marked, + std::size_t cz, std::size_t nz, std::size_t tz, + bool use_redline, + bool debug_flag); ~ListAlloc(); - static up make(std::size_t cz, std::size_t nz, - OnEmptyFn on_overflow); + static up make(const std::string & name, std::size_t cz, std::size_t nz, bool debug_flag); + + /** reset to have at least @p z bytes of storage **/ + bool reset(std::size_t z); + + /** expand bucket list to accomodate a requrest of size @p z **/ + bool expand(std::size_t z); + + /** current free pointer **/ + std::byte * free_ptr() const; + + // inherited from IAlloc.. + + virtual std::size_t size() const override; + virtual std::size_t available() const override; + virtual std::size_t allocated() const override; + virtual bool contains(const void * x) const override; + virtual bool is_before_checkpoint(const void * x) const override; + virtual std::size_t before_checkpoint() const override; + virtual std::size_t after_checkpoint() const override; + + virtual void clear() override; + virtual void checkpoint() override; + virtual std::byte * alloc(std::size_t z) override; + virtual void release_redline_memory() override; private: + /** **/ std::size_t start_z_ = 0; - LinearAlloc* hd_ = nullptr; + /** all new allocs from this list **/ + std::unique_ptr hd_; + /** allocator that was in @ref hd_ when @ref checkpoint last called **/ + ArenaAlloc * marked_ = nullptr; + /** overflow allocs (expect list to be short); + * from trying to converge on app working set size + **/ + std::list> full_l_; std::size_t current_z_ = 0;; std::size_t next_z_ = 0;; std::size_t total_z_ = 0; bool use_redline_ = false; bool redlined_flag_ = false; + /** true to enable debug logging **/ + bool debug_flag_ = false; }; } /*namespace gc*/ } /*namespace xo*/ - /* end ListAlloc.hpp */ diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp new file mode 100644 index 00000000..f66e8e9a --- /dev/null +++ b/include/xo/alloc/Object.hpp @@ -0,0 +1,232 @@ +/* Object.hpp + * + * author: Roland Conybeare, Jul 2025 + */ + +#pragma once + +#include "IAlloc.hpp" +#include +#include + +namespace xo { + namespace gc { + class GC; + class ObjectStatistics; + }; + + class Object; + + template + class gc_ptr; + + template + using gp = gc_ptr; + + /** wrapper for a pointer to garbage-collector-eligible T. + * Application code will usually use the alias template gp + **/ + template + class gc_ptr { + public: + using element_type = T; + + public: + gc_ptr() = default; + gc_ptr(T * p) : ptr_{p} {} + gc_ptr(const gc_ptr & x) : ptr_{x.ptr_} {} + + /** create from gc_ptr to some related type @tparam S **/ + template + gc_ptr(const gc_ptr & x) : ptr_{x.ptr()} {} + + static bool is_eq(gc_ptr x1, gc_ptr x2) { + std::uintptr_t u1 = reinterpret_cast(x1.ptr()); + std::uintptr_t u2 = reinterpret_cast(x2.ptr()); + + // multiple inheritance shenanigans. + // (allow interface pointers separated by one pointer) + + if (u1 >= u2) + return (u1 <= u2 + sizeof(std::uintptr_t)); + else + return (u2 <= u1 + sizeof(std::uintptr_t)); + } + + T * ptr() const { return ptr_; } + T ** ptr_address() { return &ptr_; } + + bool is_null() const { return ptr_ == nullptr; } + void make_null() { ptr_ = nullptr; } + + void assign_ptr(T * x) { ptr_ = x; } + + gc_ptr & operator=(const gc_ptr & x) { ptr_ = x.ptr(); return *this; } + T * operator->() const { return ptr_; } + + private: + T * ptr_ = nullptr; + }; + + /** Root class for all xo GC-collectable objects. + * + * Design note: + * + * relying on inheritance means we insist that GC traits + * for a type appear directly in that type's vtable, and at specific locations. + * This implies one level of indirection when GC traverses an instance. + * + * Would be feasible to relax the must-inherit-from-Object constraint, + * but cost would be an extra layer of indirection + **/ + class Object { + public: + virtual ~Object() = default; + + /** memory allocator for objects. Likely this will be a GC instance, + * but simple arena also supported. + **/ + static gc::IAlloc * mm; + + /** use from GC aux functions **/ + static gc::GC * _gc() { return reinterpret_cast(mm); } + + /** during GC + * 1. copy destination object @p *addr to (new) to-space. + * 2. overwrite existing object @p *addr with a forwarding pointer to + * copy made in step 1. + * 3. return the location of the copy make in step 1. + * + * @p src. source object to be forwarded + * @p gc. garbage collector + */ + static Object * _forward(Object * src, gc::GC * gc); + + template + static void _forward_inplace(T ** src_addr) { + Object * fwd = _forward(*src_addr, _gc()); + + *src_addr = reinterpret_cast(fwd); + } + + template + static void _forward_inplace(gp & src) { + _forward_inplace(src.ptr_address()); + } + + /** primary workhorse for garbage collection. + * + * we assign each object one of three colors: black|gray|white. + * + * color | location | children | action | + * ------+------------+------------+-------------------------+ + * black | from-space | any | move to to-space | + * gray | to-space | any | move remaining children | + * white | to-space | white/gray | done | + * + * initially all reachable objects are black. + * GC is complete when all reachable objects are white. + * GC needs a variable amount of temporary storage to keep track of all gray objects + **/ + static Object * _deep_move(Object * src, gc::GC * gc, gc::ObjectStatistics * stats); + + /** copy @p src to to-space, and replace original with forwarding pointer to new location. + * return the new location + **/ + static Object * _shallow_move(Object * src, gc::GC * gc); + + // GC support + + /** true iff this object represents a forwarding pointer. + * Forwarding pointers are exclusively created by the garbage collector; + * forwarding pointers (and only forwarding pointers) return true here. + **/ + virtual bool _is_forwarded() const { return false; } + + /** offset for uncommon situation where pointer address is offset from object + * base address + **/ + virtual Object * _offset_destination(Object * src) const { return src; }; + + /** replace this object with a forwarding pointer referring to @p dest. + **/ + virtual void _forward_to(Object * dest); + + /** if this object represents a forwarding pointer, return its new location. + * forwarding pointers belong to the garbage collector implementation. + * (if you have to ask -- no, your class is not a forwarding pointer) + * all other objects return nullptr here. + **/ + virtual Object * _destination() { return nullptr; } + + /** return amount of storage (including padding) consumed by this object, + * excluding immediate Object-pointer children + **/ + virtual std::size_t _shallow_size() const = 0; + + // TODO: _shallow_move() also overwrite *this with gc-only forwarding object point to C + + /** if subject is allocated by GC: + * - create copy C in to-space + * - destination C will be nursery|tenured depending on location of this. + * else + * - return this to disengage from GC + * + * Require: @ref mm is an instance of @ref gc::GC + **/ + virtual Object * _shallow_copy() const = 0; + + /** update child pointers that refer to forwarding pointers, + * replacing them with the correct destination. + * See @ref Object::deep_move + * + * this gray object, located in to-space. + * fwd1 forwarding objects. + * Located in from-space. Invalid at end of GC cycle. + * p1,p2 source pointers. + * D1,D2 already-forwarded objects. located in to-space. + * + * before: + * this fwd1 + * +----+ +-+ + * | p1 ----->|x|-------> D1 + * | | +-+ + * | | + * | p2 ----------------> D2 + * +----+ + * + * after: + * this + * +----+ + * | p1 ----------------> D1 + * | | + * | | + * | p2 ----------------> D2 + * +----+ + * + * this is now white + * + * @return shallow size of *this. Must exactly match the amount of memory in to-space + * allocated by @ref _shallow_move + * + **/ + virtual std::size_t _forward_children() = 0; + }; + + /** @class Cpof + * @brief argument to operator new used for garbage collector evacuation phase + * + * Tag overloaded operator new to activate allocation policy based on location + * in memory of source object. + **/ + class Cpof { + public: + explicit Cpof(const Object * src) : src_{src} {} + + const void * src_ = nullptr; + }; +} /*namespace xo*/ + +void * operator new (std::size_t z, const xo::Cpof & copy); + +/* end Object.hpp */ diff --git a/include/xo/alloc/Stack.hpp b/include/xo/alloc/Stack.hpp new file mode 100644 index 00000000..b894d853 --- /dev/null +++ b/include/xo/alloc/Stack.hpp @@ -0,0 +1,49 @@ +/* Stack.hpp + * + * author: Roland Conybeare, jul 2025 + */ + +#pragma once + +#include + +namespace xo { + namespace gc { + /** Simple stack implementation + **/ + template + class Stack { + public: + explicit Stack(std::size_t capacity) { + this->contents_.reserve(capacity); + } + + bool is_empty() const { return contents_.empty(); } + std::size_t available() const { return contents_.capacity() - contents_.size(); } + void drop() { contents_.resize(contents_.size() - 1); } + void push(const T & x) { contents_.push_back(x); } + T pop() { + T retval = contents_[contents_.size() - 1]; + this->drop(); + return retval; + } + const T & top() const { + return this->lookup(0); + } + const T & lookup(std::size_t i) const { + return contents_.at(contents_.size() - 1 - i); + } + void clear() { contents_.clear(); } + void reset_to(std::size_t z) { contents_.resize(z); } + + std::size_t n_elements() const { return contents_.size(); } + std::size_t capacity() const { return contents_.capacity(); } + + private: + std::vector contents_; + }; + + } /*namespace gc*/ +} /*namespace xo*/ + +/* end Stack.hpp */ diff --git a/src/alloc/AllocPolicy.cpp b/src/alloc/AllocPolicy.cpp new file mode 100644 index 00000000..b1dc162f --- /dev/null +++ b/src/alloc/AllocPolicy.cpp @@ -0,0 +1,13 @@ +/* AllocPolicy.cpp + * + * author: Roland Conybeare, Jul 2025 + */ + +#include "AllocPolicy.hpp" + +/* note: inline/.hpp definition not allowed for operator delete */ +void operator delete(void * ptr) noexcept { + xo::xo.free(ptr); +} + +/* end AllocPolicy.cpp */ diff --git a/src/alloc/LinearAlloc.cpp b/src/alloc/ArenaAlloc.cpp similarity index 52% rename from src/alloc/LinearAlloc.cpp rename to src/alloc/ArenaAlloc.cpp index 3ae57e70..227e2d63 100644 --- a/src/alloc/LinearAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -1,29 +1,33 @@ -/* file LinearAlloc.cpp +/* file ArenaAlloc.cpp * * author: Roland Conybeare */ -#include "LinearAlloc.hpp" +#include "ArenaAlloc.hpp" +#include "xo/indentlog/scope.hpp" #include "xo/indentlog/print/tag.hpp" #include namespace xo { namespace gc { - LinearAlloc::LinearAlloc(std::size_t rz, std::size_t z) + ArenaAlloc::ArenaAlloc(const std::string & name, std::size_t rz, std::size_t z, bool debug_flag) { - this->lo_ = (new std::uint8_t [rz + z]); + this->name_ = name; + this->lo_ = (new std::byte [rz + z]); this->checkpoint_ = lo_; this->free_ptr_ = lo_; this->limit_ = lo_ + z; + this->redline_z_ = rz; this->hi_ = limit_ + rz; + this->debug_flag_ = debug_flag; if (!lo_) { - throw std::runtime_error(tostr("LinearAlloc: allocation failed", + throw std::runtime_error(tostr("ArenaAlloc: allocation failed", xtag("size", rz + z))); } } - LinearAlloc::~LinearAlloc() + ArenaAlloc::~ArenaAlloc() { delete [] this->lo_; @@ -33,17 +37,19 @@ namespace xo { this->checkpoint_ = nullptr; this->free_ptr_ = nullptr; this->limit_ = nullptr; + this->redline_z_ = 0; this->hi_ = nullptr; + this->debug_flag_ = false; } - up - LinearAlloc::make(std::size_t rz, std::size_t z) + up + ArenaAlloc::make(const std::string & name, std::size_t rz, std::size_t z, bool debug_flag) { - return up(new LinearAlloc(rz, z)); + return up(new ArenaAlloc(name, rz, z, debug_flag)); } void - LinearAlloc::set_free_ptr(std::uint8_t * x) + ArenaAlloc::set_free_ptr(std::byte * x) { assert(lo_ <= x); assert(x < limit_); @@ -57,70 +63,79 @@ namespace xo { } std::size_t - LinearAlloc::size() const { + ArenaAlloc::size() const { return limit_ - lo_; } std::size_t - LinearAlloc::available() const { + ArenaAlloc::available() const { return limit_ - free_ptr_; } std::size_t - LinearAlloc::allocated() const { + ArenaAlloc::allocated() const { return free_ptr_ - lo_; } bool - LinearAlloc::is_before_checkpoint(const std::uint8_t * x) const { + ArenaAlloc::contains(const void * x) const { + return (lo_ <= x) && (x < hi_); + } + + bool + ArenaAlloc::is_before_checkpoint(const void * x) const { return (lo_ <= x) && (x < checkpoint_); } std::size_t - LinearAlloc::before_checkpoint() const + ArenaAlloc::before_checkpoint() const { return checkpoint_ - lo_; } std::size_t - LinearAlloc::after_checkpoint() const + ArenaAlloc::after_checkpoint() const { return free_ptr_ - checkpoint_; } void - LinearAlloc::clear() + ArenaAlloc::clear() { this->checkpoint_ = lo_; this->free_ptr_ = lo_; - this->limit_ = lo_; + this->limit_ = hi_ - redline_z_; } void - LinearAlloc::checkpoint() + ArenaAlloc::checkpoint() { this->checkpoint_ = this->free_ptr_; } - std::uint8_t * - LinearAlloc::alloc(std::size_t z) + std::byte * + ArenaAlloc::alloc(std::size_t z0) { + scope log(XO_DEBUG(debug_flag_)); + /* word size for alignment */ - constexpr uint32_t c_bpw = sizeof(void*); + constexpr uint32_t c_bpw = sizeof(std::uintptr_t); std::uintptr_t free_u64 = reinterpret_cast(free_ptr_); assert(free_u64 % c_bpw == 0ul); - /* round up to multiple of c_bpw */ - std::uint32_t dz = (c_bpw - (z % c_bpw)); - z += dz; + std::uint32_t dz = alloc_padding(z0); - assert(z % c_bpw == 0ul); + std::size_t z1 = z0 + dz; - std::uint8_t * retval = this->free_ptr_; + assert(z1 % c_bpw == 0ul); - this->free_ptr_ += z; + std::byte * retval = this->free_ptr_; + + this->free_ptr_ += z1; + + log && log(xtag("self", name_), xtag("z0", z0), xtag("+pad", dz), xtag("z1", z1)); if (free_ptr_ > limit_) { return nullptr; @@ -128,8 +143,14 @@ namespace xo { return retval; } + + void + ArenaAlloc::release_redline_memory() { + this->limit_ = this->hi_; + } + } /*namespace gc*/ } /*namespace xo*/ -/* end LinearAlloc.cpp */ +/* end ArenaAlloc.cpp */ diff --git a/src/alloc/CMakeLists.txt b/src/alloc/CMakeLists.txt index cc5768d8..bc0f919f 100644 --- a/src/alloc/CMakeLists.txt +++ b/src/alloc/CMakeLists.txt @@ -2,7 +2,12 @@ set(SELF_LIB xo_alloc) set(SELF_SRCS - LinearAlloc.cpp + IAlloc.cpp + ArenaAlloc.cpp + ListAlloc.cpp + GC.cpp + Object.cpp + Forwarding1.cpp ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) diff --git a/src/alloc/Forwarding1.cpp b/src/alloc/Forwarding1.cpp new file mode 100644 index 00000000..825115a2 --- /dev/null +++ b/src/alloc/Forwarding1.cpp @@ -0,0 +1,45 @@ +/* file Forwarding1.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "Forwarding1.hpp" +#include +#include + +namespace xo { + namespace obj { + Forwarding1::Forwarding1(gp dest) + : dest_{dest} + {} + + Object * + Forwarding1::_offset_destination(Object * src) const + { + intptr_t offset = src - static_cast(this); + + return dest_.ptr() + offset; + } + + std::size_t + Forwarding1::_shallow_size() const { + assert(false); + return 0; + } + + Object * + Forwarding1::_shallow_copy() const { + assert(false); + return nullptr; + } + + std::size_t + Forwarding1::_forward_children() { + assert(false); + return 0; + } + + } /*namespace obj*/ +} /*namespace xo*/ + +/* end Forwarding1.cpp */ diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp new file mode 100644 index 00000000..ec4aa647 --- /dev/null +++ b/src/alloc/GC.cpp @@ -0,0 +1,492 @@ +/* GC.cpp + * + * author: Roland Conybeare, Jul 2025 + */ + +#include "GC.hpp" +#include "Object.hpp" +#include "xo/indentlog/scope.hpp" +#include +#include + +namespace xo { + namespace gc { + void + PerGenerationStatistics::include_gc(std::size_t alloc_z, + std::size_t before_z, + std::size_t after_z, + std::size_t promote_z) + { + this->update_snapshot(after_z); + + new_alloc_z_ += alloc_z; + scanned_z_ += before_z; + survive_z_ += after_z; + promote_z_ += promote_z; + } + + void + PerGenerationStatistics::update_snapshot(std::size_t after_z) + { + used_z_ = after_z; + } + + void + PerGenerationStatistics::display(std::ostream & os) const + { + os << ""; + } + + void + GcStatistics::include_gc(generation upto, + std::size_t alloc_z, + std::size_t before_z, + std::size_t after_z, + std::size_t promote_z) + { + gen_v_[static_cast(upto)].include_gc(alloc_z, before_z, after_z, promote_z); + } + + void + GcStatistics::update_snapshot(generation upto, + std::size_t after_z) + { + gen_v_[static_cast(upto)].update_snapshot(after_z); + } + + void + GcStatistics::display(std::ostream & os) const + { + os << ""; + } + + GC::GC(const Config & config) + : config_{config} + { + enum { NurseryFrom, NurseryTo, TenuredFrom, TenuredTo }; + + std::size_t nursery_size = config.initial_nursery_z_; + std::size_t tenured_size = config.initial_tenured_z_; + + nursery_[role2int(role::from_space)] + = ListAlloc::make("NA", nursery_size, 2 * nursery_size, config.debug_flag_); + nursery_[role2int(role::to_space) ] + = ListAlloc::make("NB", nursery_size, 2 * nursery_size, config.debug_flag_); + + tenured_[role2int(role::from_space)] + = ListAlloc::make("TA", tenured_size, 2 * tenured_size, config.debug_flag_); + tenured_[role2int(role::to_space) ] + = ListAlloc::make("TB", tenured_size, 2 * tenured_size, config.debug_flag_); + + this->checkpoint(); + } + + up + GC::make(const Config & config) + { + GC * gc = new GC(config); + + return up{gc}; + } + + std::size_t + GC::size() const + { + return nursery_[role2int(role::to_space)]->size() + tenured_[role2int(role::to_space)]->size(); + } + + std::size_t + GC::allocated() const + { + return (nursery_[role2int(role::to_space)]->allocated() + + tenured_[role2int(role::to_space)]->allocated()); + } + + std::size_t + GC::available() const + { + return nursery_[role2int(role::to_space)]->available(); + } + + bool + GC::fromspace_contains(const void * x) const + { + return (nursery_[role2int(role::from_space)]->contains(x) + || tenured_[role2int(role::from_space)]->contains(x)); + } + + bool + GC::contains(const void * x) const + { + return (nursery_[role2int(role::to_space)]->contains(x) + || tenured_[role2int(role::to_space)]->contains(x)); + } + + bool + GC::is_before_checkpoint(const void * x) const + { + return nursery_[role2int(role::to_space)]->is_before_checkpoint(x); + } + + std::size_t + GC::before_checkpoint() const + { + return nursery_[role2int(role::to_space)]->before_checkpoint(); + } + + std::size_t + GC::after_checkpoint() const + { + return nursery_[role2int(role::to_space)]->after_checkpoint(); + } + + generation + GC::fromspace_generation_of(const void * x) const + { + if (tenured_[role2int(role::from_space)]->contains(x)) + return generation::tenured; + + return generation::nursery; + } + + generation + GC::generation_of(const void * x) const + { + if (tenured_[role2int(role::to_space)]->contains(x)) + return generation::tenured; + + return generation::nursery; + } + + std::byte * + GC::free_ptr(generation gen) + { + switch(gen) { + case generation::nursery: + return nursery_[role2int(role::to_space)]->free_ptr(); + case generation::tenured: + return tenured_[role2int(role::to_space)]->free_ptr(); + case generation::N: + assert(false); + } + + return nullptr; + } + + void + GC::clear() + { + nursery_[role2int(role::from_space)]->clear(); + nursery_[role2int(role::to_space) ]->clear(); + + tenured_[role2int(role::from_space)]->clear(); + tenured_[role2int(role::to_space) ]->clear(); + } + + void + GC::add_gc_root(Object ** addr) + { + gc_root_v_.push_back(addr); + } + + void + GC::checkpoint() + { + nursery_[role2int(role::to_space) ]->checkpoint(); + } + + std::byte * + GC::alloc(std::size_t z) + { + std::byte * x = nursery_[role2int(role::to_space)]->alloc(z); + + if (!x) { + this->request_gc(generation::nursery); + + if (incr_gc_pending_ || full_gc_pending_) + nursery_[role2int(role::to_space)]->release_redline_memory(); + + /* try (just once) more, maybe request fits in redline space */ + x = nursery_[role2int(role::to_space)]->alloc(z); + + assert(x); + } + + return x; + } + + std::byte * + GC::alloc_gc_copy(std::size_t z, const void * src) + { + scope log(XO_DEBUG(config_.debug_flag_), xtag("z", z), xtag("+pad", IAlloc::alloc_padding(z))); + + generation g = this->fromspace_generation_of(src); + + std::byte * retval = nullptr; + + if (g == generation::tenured) + { + log && log("tenured"); + + retval = tenured_[role2int(role::to_space)]->alloc(z); + } else if (nursery_[role2int(role::from_space)]->is_before_checkpoint(src)) + { + log && log("promote"); + + /* nursery object has survived 2nd collection cycle + * -> promote into tenured generation + */ + retval = tenured_[role2int(role::to_space)]->alloc(z); + + this->gc_statistics_.total_promoted_ += IAlloc::with_padding(z); + } else { + log && log("nursery"); + + retval = nursery_[role2int(role::to_space)]->alloc(z); + + if (!retval) { + /* nursery space exhausted */ + + this->request_gc(generation::nursery); + + nursery_[role2int(role::to_space)]->release_redline_memory(); + + retval = nursery_[role2int(role::to_space)]->alloc(z); + } + } + + assert(retval); + + return retval; + } + + void + GC::release_redline_memory() + { + // not supported feature for GC + } + + void + GC::swap_nursery() + { + up tmp = std::move(nursery_[role2int(role::to_space)]); + nursery_[role2int(role::to_space)] = std::move(nursery_[role2int(role::from_space)]); + nursery_[role2int(role::from_space)] = std::move(tmp); + } + + void + GC::swap_tenured() + { + up tmp = std::move(tenured_[role2int(role::to_space)]); + tenured_[role2int(role::to_space)] = std::move(tenured_[role2int(role::from_space)]); + tenured_[role2int(role::from_space)] = std::move(tmp); + } + + void + GC::swap_spaces(generation target) + { + // will be copying into storage currently labelled FromSpace + + /* gc will copy some to-be-determined amount in [0..promote_z] + from nursery->tenured generation. + */ + std::size_t promote_z = nursery_[role2int(role::to_space)]->before_checkpoint(); + if (target == generation::tenured) { + /* gc on tenured generation may need this much space */ + std::size_t tenured_z = (tenured_[role2int(role::to_space)]->allocated() + + promote_z + + full_gc_threshold_); + + tenured_[role2int(role::from_space)]->reset(tenured_z); + + this->swap_tenured(); + } else { + if (tenured_[role2int(role::to_space)]->available() < promote_z) { + tenured_[role2int(role::to_space)]->expand(promote_z); + } + } + + nursery_[role2int(role::from_space)]->reset(nursery_[role2int(role::to_space)]->allocated() + - promote_z + + incr_gc_threshold_); + this->swap_nursery(); + } /*swap_spaces*/ + + void + GC::copy_object(Object ** pp_object, generation upto, ObjectStatistics * object_stats) + { + void * object_address = *pp_object; + + if (nursery_[role2int(role::to_space)]->contains(object_address) + || ((upto == generation::tenured) + && tenured_[role2int(role::to_space)]->contains(object_address))) + { + /* global is already in to-space */ + ; + } else if((upto == generation::nursery) && tenured_[role2int(role::to_space)]->contains(object_address)) + { + /* skip tenured objects when incremental collection */ + ; + } else { + *pp_object = Object::_deep_move(*pp_object, this, object_stats); + } + } + + void + GC::copy_globals(generation upto) + { + for (Object ** pp_root : gc_root_v_) { + this->copy_object(pp_root, upto, &gc_statistics_.per_type_stats_); + } + } + + void + GC::cleanup_phase(generation upto) + { + scope log(XO_DEBUG(config_.debug_flag_)); + + std::size_t N_allocated = nursery_[role2int(role::from_space)]->after_checkpoint(); + std::size_t T_allocated = tenured_[role2int(role::from_space)]->after_checkpoint(); + + std::size_t N_before_gc = nursery_[role2int(role::from_space)]->allocated(); + std::size_t T_before_gc = tenured_[role2int(role::from_space)]->allocated(); + + std::size_t N_after_gc = nursery_[role2int(role::to_space)]->allocated(); + std::size_t T_after_gc = tenured_[role2int(role::to_space)]->allocated(); + //std::byte * N_free_ptr = nursery_[role2int(role::to_space)]->free_ptr(); + + std::size_t promote_z = gc_statistics_.total_promoted_ - gc_statistics_.total_promoted_sab_; + + this->nursery_[role2int(role::from_space)]->reset(0); + this->tenured_[role2int(role::from_space)]->reset(0); + + /* objects currenty in to-space nursery have survived one collection */ + this->nursery_[role2int(role::to_space)]->checkpoint(); + + // nursery_[role2int(role::to_space)]->set_redline(nursery_[role2int(role::to_space)]->allocated() + incr_gc_threshold_) + + if (upto == generation::tenured) + this->tenured_[role2int(role::to_space)]->checkpoint(); + + if (log) { + log(xtag("N_allocated", N_allocated)); + log(xtag("N_before_gc", N_before_gc)); + log(xtag("N_after_gc", N_after_gc)); + log(xtag("T_allocated", T_allocated)); + log(xtag("T_before_gc", T_before_gc)); + log(xtag("T_after_gc", T_after_gc)); + } + + this->incr_gc_pending_ = false; + this->gc_statistics_.include_gc(generation::nursery, N_allocated, N_before_gc, N_after_gc, promote_z); + + if (upto == generation::tenured) { + this->full_gc_pending_ = false; + this->gc_statistics_.include_gc(generation::tenured, T_allocated, T_before_gc, T_after_gc, 0); + } else { + // still want to update tenured stats for current alloc size + this->gc_statistics_.update_snapshot(generation::tenured, T_after_gc); + } + } + + void + GC::execute_gc(generation target) + { + scope log(XO_DEBUG(config_.debug_flag_)); + + bool full_move = (target == generation::tenured); + + // TODO: RAII version in case of exceptions + this->runstate_ = GCRunstate(true /*in_progress*/, full_move); + + log && log("step 0: snapshot alloc stats"); + + /* new allocation since last GC */ + std::size_t new_alloc = this->after_checkpoint(); + + ++(gc_statistics_.gen_v_[static_cast(target)].n_gc_); + gc_statistics_.total_allocated_ += new_alloc; + gc_statistics_.total_promoted_sab_ = gc_statistics_.total_promoted_; + + log && log(xtag("new_alloc", new_alloc)); + + log && log("step 1: swap to/from roles"); + + this->swap_spaces(target); + + log && log("step 2a: copy globals"); + + this->copy_globals(target); + + log && log("step 2b: TODO: copy pinned"); + + log && log("step 3: TODO: forward mutation log"); + + log && log("step 4: TODO: notify destructor log"); + + log && log("step 5: TODO: keep reachable weak pointers"); + + log && log("step 6: cleanup"); + + this->cleanup_phase(target); + + this->runstate_ = GCRunstate(); + + log && log("statistics:"); + log && log(gc_statistics_); + } + + void + GC::request_gc(generation target) + { + if (!runstate_.in_progress() && (gc_enabled_ == 0)) { + if (!config_.allow_incremental_gc_) + target = generation::tenured; + + if ((target == generation::nursery) + && (tenured_[role2int(role::to_space)]->after_checkpoint() > full_gc_threshold_)) + { + /** full collection when >= @ref full_gc_threshold_ bytes added to tenured + * generation, since last full collection + **/ + target = generation::tenured; + } + + this->execute_gc(target); + } else { + this->incr_gc_pending_ = true; + if (target == generation::tenured) + this->full_gc_pending_ = true; + } + } + + void + GC::disable_gc() { + --gc_enabled_; + } + + void + GC::enable_gc() { + ++gc_enabled_; + + if (gc_enabled_ == 0) { + /* unblock gc */ + if (incr_gc_pending_) + this->request_gc(full_gc_pending_ ? generation::tenured : generation::nursery); + } + } + } /*namespace gc*/ +} /*namespace xo*/ + +/* end GC.cpp */ diff --git a/src/alloc/IAlloc.cpp b/src/alloc/IAlloc.cpp new file mode 100644 index 00000000..4fbdd556 --- /dev/null +++ b/src/alloc/IAlloc.cpp @@ -0,0 +1,54 @@ +/* @file IAlloc.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "IAlloc.hpp" +#include +#include + +namespace xo { + namespace gc { + + std::uint32_t + IAlloc::alloc_padding(std::size_t z) + { + /* word size for alignment */ + constexpr uint32_t c_bpw = sizeof(std::uintptr_t); + + /* round up to multiple of c_bpw, but map 0 -> 0 + * (table assuming c_bpw==8) + * + * z%c_bpw dz + * ------------ + * 0 0 + * 1 7 + * 2 6 + * .. .. + * 7 1 + */ + std::uint32_t dz = (c_bpw - (z % c_bpw)) % c_bpw; + z += dz; + + assert(z % c_bpw == 0ul); + + return dz; + } + + std::size_t + IAlloc::with_padding(std::size_t z) + { + return z + alloc_padding(z); + } + + std::byte * + IAlloc::alloc_gc_copy(std::size_t /*z*/, const void * /*src*/) + { + assert(false); + return nullptr; + } + + } /*namespace gc*/ +} /*namespace xo*/ + +/* end IAlloc.cpp */ diff --git a/src/alloc/ListAlloc.cpp b/src/alloc/ListAlloc.cpp new file mode 100644 index 00000000..76da8b19 --- /dev/null +++ b/src/alloc/ListAlloc.cpp @@ -0,0 +1,318 @@ +/* file ListAlloc.cpp + * + * author: Roland Conybeare, Jul 2025 + */ + +#include "ListAlloc.hpp" +#include "ArenaAlloc.hpp" +#include +#include + +namespace xo { + namespace gc { + ListAlloc::ListAlloc(std::unique_ptr hd, + ArenaAlloc * marked, + std::size_t cz, std::size_t nz, std::size_t tz, + bool use_redline, + bool debug_flag) + : start_z_{cz}, + hd_{std::move(hd)}, + marked_{marked}, + full_l_{}, + current_z_{cz}, + next_z_{nz}, + total_z_{tz}, + use_redline_{use_redline}, + debug_flag_{debug_flag} + {} + + ListAlloc::~ListAlloc() + { + this->clear(); + } + + up + ListAlloc::make(const std::string & name, std::size_t cz, std::size_t nz, bool debug_flag) + { + std::unique_ptr hd{ArenaAlloc::make(name, 0, cz, debug_flag)}; + + if (!hd) + return nullptr; + + ArenaAlloc * marked = nullptr; + + up retval{new ListAlloc(std::move(hd), + marked, + cz, nz, cz, + false /*!use_redline*/, + debug_flag)}; + + return retval; + } + + std::size_t + ListAlloc::size() const { + return total_z_; + } + + std::byte * + ListAlloc::free_ptr() const { + return hd_->free_ptr(); + } + + std::size_t + ListAlloc::available() const { + if (hd_) { + /* can only allocate from @ref hd_, + * so even if there were available space in @ref full_l_, + * it's not accessible to ListAlloc. + */ + + return hd_->available(); + } + + return 0; + } + + std::size_t + ListAlloc::allocated() const { + std::size_t total = 0; + + if (hd_) + total += hd_->allocated(); + + for (const auto & alloc : full_l_) + total += alloc->allocated(); + + return total; + } + + bool + ListAlloc::contains(const void * x) const { + if (hd_ && hd_->contains(x)) + return true; + + for (const auto & alloc : full_l_) { + if (alloc->contains(x)) + return true; + } + + return false; + } + + bool + ListAlloc::is_before_checkpoint(const void * x) const { + if (!marked_) + return false; + + if ((marked_ == hd_.get()) && hd_->contains(x)) + return hd_->is_before_checkpoint(x); + + /* + * 1. allocs in full_l_ appear in youngest-to-oldest order + * 2. allocators that appear before marked_ in full_l_ count as 'after checkpoint' + * 3. allocators that appear after marked_ in full_l_ count as 'before checkpoint' + */ + + bool younger_than_marked = true; + + for (const auto & alloc : full_l_) { + if (younger_than_marked) { + if (alloc.get() == marked_) { + /* nothing else to test on this iteration, + * already checked .marked_ specifically + */ + younger_than_marked = false; + } else { + /* after checkpoint */ + if (alloc->contains(x)) + return false; + } + } else { + if (alloc->contains(x)) + return true; + } + } + + return false; + } + + std::size_t + ListAlloc::before_checkpoint() const + { + if (marked_) { + if (full_l_.empty()) { + assert(marked_ == hd_.get()); + + return marked_->before_checkpoint(); + } + } else { + /* count everything allocated */ + return this->allocated(); + } + + std::size_t z = 0; + + /* control here: .marked & .full_l non-empty. */ + if (hd_.get() == marked_) { + z += hd_->before_checkpoint(); + + /* anything in .full_l older than marked .hd */ + for (const auto & alloc : full_l_) { + z += alloc->allocated(); + } + + return z; + } else { + /* messiest case: .marked is true, + * and not the youngest arena + */ + bool younger_than_marked = true; + + for (const auto & alloc : full_l_) { + if (younger_than_marked) { + if (alloc.get() == marked_) { + younger_than_marked = false; + z += marked_->before_checkpoint(); + } else { + ; + } + } else { + z += alloc->allocated(); + } + } + } + + return z; + } + + std::size_t + ListAlloc::after_checkpoint() const + { + if (!marked_) + return 0; + + if (full_l_.empty()) { + assert(marked_ == hd_.get()); + + return marked_->after_checkpoint(); + } + + bool younger_than_marked = true; + + std::size_t z = 0; + + for (const auto & alloc : full_l_) { + if (younger_than_marked) { + if (alloc.get() == marked_) { + younger_than_marked = false; + z += marked_->after_checkpoint(); + break; + } else { + z += alloc->allocated(); + } + } + } + + return z; + } + + void + ListAlloc::clear() { + // general hygiene + start_z_ = 0; + hd_.reset(); + marked_ = nullptr; + full_l_.clear(); + current_z_ = 0; + next_z_ = 0; + total_z_ = 0; + use_redline_ = false; + } + + bool + ListAlloc::reset(std::size_t z) + { + // warning: hd_->size() does not include redline memory + hd_->release_redline_memory(); + + bool recycle_head_bucket = hd_ && (z <= hd_->size()); + + this->full_l_.clear(); + this->marked_ = nullptr; + this->redlined_flag_ = false; + + if (recycle_head_bucket) { + this->hd_->clear(); + this->total_z_ = hd_->size(); + + return true; + } else { + this->hd_.reset(nullptr); + this->total_z_ = 0; + + return this->expand(z); + } + } + + bool + ListAlloc::expand(std::size_t z) + { + std::size_t cz = current_z_; + std::size_t nz = next_z_; + std::size_t tz; + + do { + tz = cz + nz; + cz = nz; + nz = tz; + } while (cz < z); + + std::string name = hd_->name() + "+exp"; + + std::unique_ptr new_alloc = ArenaAlloc::make(name, 0, cz, debug_flag_); + + if (!new_alloc) + return false; + + this->current_z_ = cz; + this->next_z_ = nz; + this->total_z_ += cz; + + this->hd_ = std::move(new_alloc); + + return true; + } + + void + ListAlloc::checkpoint() { + hd_->checkpoint(); + + this->marked_ = hd_.get(); + } + + std::byte * + ListAlloc::alloc(std::size_t z) { + std::byte * retval = hd_->alloc(z); + + if (retval) + return retval; + + if (this->expand(z)) + return hd_->alloc(z); + + return nullptr; + } + + void + ListAlloc::release_redline_memory() + { + if (use_redline_) + redlined_flag_ = true; + + this->hd_->release_redline_memory(); + } + } /*namespace gc*/ +} /*namespace xo*/ + +/* end ListAlloc.cpp */ diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp new file mode 100644 index 00000000..7aa1a8d0 --- /dev/null +++ b/src/alloc/Object.cpp @@ -0,0 +1,196 @@ +/* Object.cpp + * + * author: Roalnd Conybeare, Jul 2025 + */ + +#include "Object.hpp" +#include "GC.hpp" +#include "Forwarding1.hpp" + +using xo::obj::Forwarding1; + +void * +operator new (std::size_t z, const xo::Cpof & cpof) +{ + using xo::gc::GC; + + GC * gc = reinterpret_cast(xo::Object::mm); + + return gc->alloc_gc_copy(z, cpof.src_); +} + +namespace xo { + gc::IAlloc * + Object::mm = nullptr; + + Object * + Object::_forward(Object * src, gc::GC * gc) + { + if (!src) + return src; + + if (src->_is_forwarded()) + return src->_offset_destination(src); + + bool full_move = gc->runstate().full_move(); + + if (!full_move && (gc->generation_of(src) == gc::generation::tenured)) { + /* don't move tenured objects during incremental collection */ + return src; + } + + Object::_shallow_move(src, gc); + + /* *src is now a forwarding pointer to copy in to-space */ + + return src->_offset_destination(src); + } + + Object * + Object::_deep_move(Object * from_src, gc::GC * gc, gc::ObjectStatistics * /*stats*/) + { + using gc::generation; + + if (!from_src) + return nullptr; + + Object * retval = from_src->_destination(); + + if (retval) + return retval; + + bool full_move = gc->runstate().full_move(); + + if (!full_move && gc->generation_of(from_src) == generation::tenured) { + /** incremental collection does not move already-tenured objects **/ + return from_src; + } + + /** + * To-space: + * + * to_lo = start of to-space + * w,W = white objects. An object x is white if x + all immediate children of x are in to-space + * (also implies this GC cycle put it there) + * g,G = grey objects. An object x is gray if it's in to-space, + * but possibly has >0 black children + * _ = free to-space memory + * N = nursery space + * T = tenured space + * + * wwwwwwwwwwwwwwwwwwwggggggggggggggggggggg_________________... + * ^ ^ ^ + * to_lo grey_lo(N) free_ptr(N) + * + * After moving children of one object, advancing {nursery_grey_lo, nursery_free_ptr} + * + * wwwwwwwwwwwwwwwwwwwWWWWgggggggggggggggggGGGGGGGGGGG______... + * ^ ^ ^ + * to_lo grey_lo(N) free_ptr(N) + * + * Invariant: + * + * objects in [to_lo, gray_lo) are white. + * all gray objects are in [gray_lo, free_ptr) + * memory starting at free_ptr is free. + * + * deep_move terminates when gray_lo catches up to free_ptr + * + * Above is simplified. Complication is that GC (including incremental) may + * promote objects from nursery (N) to tenured (T) + * + * So more accurate before/after picture + * + * N wwwwwwwwwwwwwwwwwwwggggggggggggggggggggg_________________... + * ^ ^ ^ + * to_lo(N) grey_lo(N) free_ptr(N) + * + * T wwwwwwwwwwwwwwgggggggggggg_______________________________... + * ^ ^ ^ + * to_lo(T) grey_lo(T) free_ptr(N) + * + * After moving children of one object, advancing {nursery_grey_lo, nursery_free_ptr} + * + * N wwwwwwwwwwwwwwwwwwwWWWWgggggggggggggggggGGGGGGGGGGG_____... + * ^ ^ ^ + * to_lo(N) grey_lo(N) free_ptr(N) + * + * T wwwwwwwwwwwwwwggggggggggggGGGGG_________________________... + * ^ ^ ^ + * to_lo(T) grey_lo(T) free_ptr(T) + * + * deep_move terminates when both: + * - gray_lo(N) catches up with free_ptr(N) + * - gray_lo(T) catches up with free_ptr(T) + * + **/ + + std::array gray_lo_v + = { gc->free_ptr(generation::nursery), gc->free_ptr(generation::tenured) }; + + Object * to_src = Object::_shallow_move(from_src, gc); + + std::size_t fixup_work = 0; + do { + fixup_work = 0; + + auto fixup_generation = [gc, &gray_lo_v](generation gen) { + std::size_t work = 0; + while(gray_lo_v[gen2int(gen)] < gc->free_ptr(gen)) { + Object * x = reinterpret_cast(gray_lo_v[gen2int(gen)]); + + // update per-class stats here + + std::size_t xz = x->_forward_children(); + + // must pad xz to multiple of word size, + // to match behavior of LinearAlloc::alloc() + // + xz += gc::IAlloc::alloc_padding(xz); + + gray_lo_v[gen2int(gen)] += xz; + ++work; + } + + return work; + }; + + fixup_work += fixup_generation(generation::nursery); + fixup_work += fixup_generation(generation::tenured); + } while (fixup_work > 0); + + return to_src; + } /*deep_move*/ + + Object * + Object::_shallow_move(Object * src, gc::GC * gc) + { + /* filter for source objects that are owned by GC. + * Care required though -- during GC from/to spaces have been swapped already + */ + if (gc->fromspace_contains(src)) + { + Object * dest = src->_shallow_copy(); + + if (dest != src) + src->_forward_to(dest); + + return dest; + } else { + return src; + } + } + + void + Object::_forward_to(Object * dest) + { + char * mem = reinterpret_cast(this); + + Forwarding1 * fwd = new (mem) Forwarding1(dest); + + (void)fwd; + } + +} /*namespace xo*/ + +/* end Object.cpp*/ diff --git a/utest/ArenaAlloc.test.cpp b/utest/ArenaAlloc.test.cpp new file mode 100644 index 00000000..aae2695b --- /dev/null +++ b/utest/ArenaAlloc.test.cpp @@ -0,0 +1,87 @@ +/* @file ArenaAlloc.test.cpp + * + * author: Roland Conybeare, Jul 2025 + */ + +#include "xo/alloc/ArenaAlloc.hpp" +#include + +namespace xo { + using xo::gc::ArenaAlloc; + + namespace ut { + + namespace { + struct testcase_alloc { + testcase_alloc(std::size_t rz, std::size_t z) + : redline_z_{rz}, arena_z_{z} {} + + std::size_t redline_z_; + std::size_t arena_z_; + + }; + + std::vector + s_testcase_v = { + testcase_alloc(0, 4096) + }; + } + + + TEST_CASE("linearalloc", "[alloc]") + { + for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + const testcase_alloc & tc = s_testcase_v[i_tc]; + + constexpr bool c_debug_flag = false; + + auto alloc = ArenaAlloc::make("linearalloc", tc.redline_z_, tc.arena_z_, c_debug_flag); + + REQUIRE(alloc.get()); + REQUIRE(alloc->name() == "linearalloc"); + REQUIRE(alloc->size() == tc.arena_z_); + REQUIRE(alloc->available() == tc.arena_z_); + REQUIRE(alloc->allocated() == 0); + REQUIRE(alloc->is_before_checkpoint(alloc->free_ptr()) == false); + REQUIRE(alloc->before_checkpoint() == 0); + REQUIRE(alloc->after_checkpoint() == 0); + + auto free0 = alloc->free_ptr(); + + auto mem = alloc->alloc(tc.arena_z_); + + REQUIRE(mem != nullptr); + + REQUIRE(mem == free0); + + REQUIRE(alloc->size() == tc.arena_z_); + REQUIRE(alloc->available() == 0); + REQUIRE(alloc->allocated() == tc.arena_z_); + REQUIRE(alloc->is_before_checkpoint(mem) == false); + REQUIRE(alloc->before_checkpoint() == 0); + REQUIRE(alloc->after_checkpoint() == tc.arena_z_); + + alloc->clear(); + + REQUIRE(alloc->free_ptr() == free0); + REQUIRE(alloc->available() == tc.arena_z_); + REQUIRE(alloc->allocated() == 0); + REQUIRE(alloc->is_before_checkpoint(free0) == false); + REQUIRE(alloc->before_checkpoint() == 0); + REQUIRE(alloc->after_checkpoint() == 0); + + mem = alloc->alloc(1); + + auto used = sizeof(void*); + REQUIRE(alloc->size() == tc.arena_z_); + REQUIRE(alloc->available() == tc.arena_z_ - used); + REQUIRE(alloc->allocated() == used); + REQUIRE(alloc->is_before_checkpoint(free0) == false); + REQUIRE(alloc->before_checkpoint() == 0); + REQUIRE(alloc->after_checkpoint() == used); + + } + } + + } /*namespace ut */ +} /*namespace xo*/ diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index e845f729..d37786e3 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -3,7 +3,8 @@ set(SELF_EXE utest.alloc) set(SELF_SRCS alloc_utest_main.cpp - LinearAlloc.test.cpp) + ArenaAlloc.test.cpp + GC.test.cpp) xo_add_utest_executable(${SELF_EXE} ${SELF_SRCS}) xo_self_dependency(${SELF_EXE} xo_alloc) diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp new file mode 100644 index 00000000..dc175615 --- /dev/null +++ b/utest/GC.test.cpp @@ -0,0 +1,69 @@ +/* @file GC.test.cpp + * + * author: Roland Conybeare, Jul 2025 + */ + +#include "xo/alloc/GC.hpp" +#include + +namespace xo { + using xo::gc::GC; + using xo::gc::generation; + using xo::gc::Config; + + namespace ut { + + namespace { + struct testcase_gc { + testcase_gc(std::size_t nz, std::size_t tz) : nursery_z_{nz}, tenured_z_{tz} {} + + std::size_t nursery_z_; + std::size_t tenured_z_; + }; + + std::vector + s_testcase_v = { + testcase_gc(1024, 4096) + }; + } + + TEST_CASE("gc", "[alloc][gc]") + { + for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + const testcase_gc & tc = s_testcase_v[i_tc]; + + up gc = GC::make( + {.initial_nursery_z_ = tc.nursery_z_, + .initial_tenured_z_ = tc.tenured_z_}); + + REQUIRE(gc.get()); + REQUIRE(gc->size() == tc.nursery_z_ + tc.tenured_z_); + REQUIRE(gc->allocated() == 0); + REQUIRE(gc->available() == tc.nursery_z_); + REQUIRE(gc->before_checkpoint() == 0); + // ListAlloc model is that nothing is before checkpoint + // until it's first established + REQUIRE(gc->after_checkpoint() == 0); + + REQUIRE(gc->gc_in_progress() == false); + REQUIRE(gc->is_gc_enabled() == true); + REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 0); + REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0); + + /* gc with empty state */ + gc->request_gc(generation::nursery); + + REQUIRE(gc->gc_in_progress() == false); + REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); + REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0); + + /* still empty state */ + gc->request_gc(generation::tenured); + + REQUIRE(gc->gc_in_progress() == false); + REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); + REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 1); + } + } + } /*namespace ut*/ +} /*namespace xo*/ diff --git a/utest/LinearAlloc.test.cpp b/utest/LinearAlloc.test.cpp index 5d3a1fcd..b1909991 100644 --- a/utest/LinearAlloc.test.cpp +++ b/utest/LinearAlloc.test.cpp @@ -3,7 +3,7 @@ * author: Roland Conybeare, Jul 2025 */ -#include "xo/alloc/LinearAlloc.hpp" +#include "xo/alloc/ArenaAlloc.hpp" #include namespace xo { @@ -33,15 +33,53 @@ namespace xo { for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { const testcase_alloc & tc = s_testcase_v[i_tc]; - auto alloc = LinearAlloc::make(tc.redline_z_, tc.arena_z_); + constexpr bool c_debug_flag = false; + + auto alloc = LinearAlloc::make("linearalloc", tc.redline_z_, tc.arena_z_, c_debug_flag); REQUIRE(alloc.get()); + REQUIRE(alloc->name() == "linearalloc"); REQUIRE(alloc->size() == tc.arena_z_); REQUIRE(alloc->available() == tc.arena_z_); REQUIRE(alloc->allocated() == 0); REQUIRE(alloc->is_before_checkpoint(alloc->free_ptr()) == false); REQUIRE(alloc->before_checkpoint() == 0); REQUIRE(alloc->after_checkpoint() == 0); + + auto free0 = alloc->free_ptr(); + + auto mem = alloc->alloc(tc.arena_z_); + + REQUIRE(mem != nullptr); + + REQUIRE(mem == free0); + + REQUIRE(alloc->size() == tc.arena_z_); + REQUIRE(alloc->available() == 0); + REQUIRE(alloc->allocated() == tc.arena_z_); + REQUIRE(alloc->is_before_checkpoint(mem) == false); + REQUIRE(alloc->before_checkpoint() == 0); + REQUIRE(alloc->after_checkpoint() == tc.arena_z_); + + alloc->clear(); + + REQUIRE(alloc->free_ptr() == free0); + REQUIRE(alloc->available() == tc.arena_z_); + REQUIRE(alloc->allocated() == 0); + REQUIRE(alloc->is_before_checkpoint(free0) == false); + REQUIRE(alloc->before_checkpoint() == 0); + REQUIRE(alloc->after_checkpoint() == 0); + + mem = alloc->alloc(1); + + auto used = sizeof(void*); + REQUIRE(alloc->size() == tc.arena_z_); + REQUIRE(alloc->available() == tc.arena_z_ - used); + REQUIRE(alloc->allocated() == used); + REQUIRE(alloc->is_before_checkpoint(free0) == false); + REQUIRE(alloc->before_checkpoint() == 0); + REQUIRE(alloc->after_checkpoint() == used); + } } From c7488cbfd5a649542e89e0a72dde1f5f47b64c7d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 5 Aug 2025 11:08:36 -0500 Subject: [PATCH 002/342] xo-alloc: mutation log tracking in working state + unit test --- docs/index.rst | 3 + include/xo/alloc/ArenaAlloc.hpp | 24 +- include/xo/alloc/Forwarding1.hpp | 14 +- include/xo/alloc/GC.hpp | 136 +++++++-- include/xo/alloc/IAlloc.hpp | 16 +- include/xo/alloc/ListAlloc.hpp | 23 +- include/xo/alloc/Object.hpp | 25 +- src/alloc/Forwarding1.cpp | 5 + src/alloc/GC.cpp | 488 ++++++++++++++++++++++++++++--- src/alloc/IAlloc.cpp | 6 + src/alloc/ListAlloc.cpp | 10 + src/alloc/Object.cpp | 4 +- utest/CMakeLists.txt | 12 +- utest/GC.test.cpp | 3 + 14 files changed, 667 insertions(+), 102 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 198cf01c..de643009 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -12,3 +12,6 @@ xo-alloc provides arena allocators and a generation garbage collector install introduction implementation + glossary + genindex + search diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index e2e74e8f..12033646 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -45,24 +45,24 @@ namespace xo { std::size_t z, bool debug_flag); - const std::string & name() const { return name_; } std::byte * free_ptr() const { return free_ptr_; } void set_free_ptr(std::byte * x); // inherited from IAlloc... - virtual std::size_t size() const override; - virtual std::size_t available() const override; - virtual std::size_t allocated() const override; - virtual bool contains(const void * x) const override; - virtual bool is_before_checkpoint(const void * x) const override; - virtual std::size_t before_checkpoint() const override; - virtual std::size_t after_checkpoint() const override; + virtual const std::string & name() const final override { return name_; } + virtual std::size_t size() const final override; + virtual std::size_t available() const final override; + virtual std::size_t allocated() const final override; + virtual bool contains(const void * x) const final override; + virtual bool is_before_checkpoint(const void * x) const final override; + virtual std::size_t before_checkpoint() const final override; + virtual std::size_t after_checkpoint() const final override; - virtual void clear() override; - virtual void checkpoint() override; - virtual std::byte * alloc(std::size_t z) override; - virtual void release_redline_memory() override; + virtual void clear() final override; + virtual void checkpoint() final override; + virtual std::byte * alloc(std::size_t z) final override; + virtual void release_redline_memory() final override; private: ArenaAlloc(const std::string & name, std::size_t rz, std::size_t z, bool debug_flag); diff --git a/include/xo/alloc/Forwarding1.hpp b/include/xo/alloc/Forwarding1.hpp index 62536651..4fb61d08 100644 --- a/include/xo/alloc/Forwarding1.hpp +++ b/include/xo/alloc/Forwarding1.hpp @@ -12,11 +12,15 @@ namespace xo { explicit Forwarding1(gp dest); // inherited from Object.. - virtual bool _is_forwarded() const override { return true; } - virtual Object * _offset_destination(Object * src) const; - virtual std::size_t _shallow_size() const override; - virtual Object * _shallow_copy() const override; - virtual std::size_t _forward_children() override; + virtual bool _is_forwarded() const final override { return true; } + virtual Object * _offset_destination(Object * src) const final override; + virtual Object * _destination() final override; + /** never called on Forwarding1 **/ + virtual std::size_t _shallow_size() const final override; + /** never called on Forwarding1 **/ + virtual Object * _shallow_copy() const final override; + /** never called on Forwarding1 **/ + virtual std::size_t _forward_children() final override; private: /** the object that used to be located at this address (i.e. @c this) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index f42864b7..0c50a722 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -23,6 +23,12 @@ namespace xo { constexpr std::size_t gen2int(generation x) { return static_cast(x); } + enum class generation_result { + nursery, + tenured, + not_found + }; + enum class role { /** nursery: generation for new objects **/ from_space, @@ -131,6 +137,17 @@ namespace xo { /** total bytes promoted from nursery->tenured since inception **/ std::size_t total_promoted_ = 0; + /** total number of mutations to already-allocated objects, + * whether or not GC needs to log them. + **/ + std::size_t n_mutation_ = 0; + /** total number of mutation eligible for logging **/ + std::size_t n_logged_mutation_ = 0; + /** total number of cross-generation mutations (tenured->nursery when reported) **/ + std::size_t n_xgen_mutation_ = 0; + /** total number of cross-checkpoint mutations (N0 -> N1 when reported) **/ + std::size_t n_xckp_mutation_ = 0; + /** per-type statistics (placeholder) **/ ObjectStatistics per_type_stats_; }; @@ -163,6 +180,35 @@ namespace xo { bool full_move_ = false; }; + class MutationLogEntry { + public: + MutationLogEntry(Object * parent, Object ** lhs) : parent_{parent}, lhs_{lhs} {} + + Object * parent() const { return parent_; } + Object ** lhs() const { return lhs_; } + + Object * child() const { return *lhs_; } + + bool is_child_forwarded() const; + bool is_parent_forwarded() const; + + Object * parent_destination() const; + + /** Flag obsolete mutation. + * Future proofing, never happens for regular objects + **/ + bool is_dead() const { return false; } + + MutationLogEntry update_parent_moved(Object * parent_to) const; + void fixup_parent_child_moved(Object * child_to) { *lhs_ = child_to; } + + private: + Object * parent_; + Object ** lhs_; + }; + + using MutationLog = std::vector; + /** @class GC * @brief generational garbage collector * @@ -185,16 +231,18 @@ namespace xo { /** true iff GC permitted in current state **/ bool is_gc_enabled() const { return gc_enabled_ == 0; } - /** @return generation to which object at @p x belongs **/ - generation generation_of(const void * x) const; - /** @return generation that contains @p x, given it's in from-space **/ - generation fromspace_generation_of(const void * x) const; - /** true iff from-space contains @p x **/ - bool fromspace_contains(const void * x) const; /** true during (and only during) a GC cycle **/ bool gc_in_progress() const { return runstate_.in_progress(); } - /** return free pointer for generation @p gen, i.e. nursery or tenured space **/ + /** @return generation to which object at @p x belongs **/ + generation_result tospace_generation_of(const void * x) const; + /** @return generation that contains @p x, given it's in from-space **/ + generation_result fromspace_generation_of(const void * x) const; + /** true iff from-space contains @p x **/ + bool fromspace_contains(const void * x) const; + /** @return free pointer for generation @p gen, i.e. nursery or tenured space **/ std::byte * free_ptr(generation gen); + /** @return current size of (number of entries in) mutation log **/ + std::size_t mlog_size() const; /** add gc root at address @p addr . Gc will keep alive anything reachable * from @c *addr @@ -217,27 +265,43 @@ namespace xo { // inherited from IAlloc.. + virtual const std::string & name() const final override; /** capacity in bytes (counting both free+allocated) for object storage. * only counts one of {to-space, from-space}, * since one role is always held empty between collections. **/ - virtual std::size_t size() const override; + virtual std::size_t size() const final override; - virtual std::size_t allocated() const override; - virtual std::size_t available() const override; + virtual std::size_t allocated() const final override; + virtual std::size_t available() const final override; /** only tests to-space **/ - virtual bool contains(const void * x) const override; - virtual bool is_before_checkpoint(const void * x) const override; - virtual std::size_t before_checkpoint() const override; - virtual std::size_t after_checkpoint() const override; + virtual bool contains(const void * x) const final override; + virtual bool is_before_checkpoint(const void * x) const final override; + virtual std::size_t before_checkpoint() const final override; + virtual std::size_t after_checkpoint() const final override; + virtual bool debug_flag() const final override; - virtual void clear() override; - virtual void checkpoint() override; + virtual void clear() final override; + virtual void checkpoint() final override; - virtual std::byte * alloc(std::size_t z) override; - virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) override; + /** GC bookkeeping for an assignment that modifes an Object reference. + * Whenever an @ref Object instance P contains a member variable that can refer + * to another @ref Object, then we need to involve GC to perform the assignment. + * In particular a side-effect that changes the target of such reference to Q after P + * has been promoted, may lead to a tenured->nursery cross-generational pointer. + * GC needs to know about such pointers to it can update them as part of subsequent + * incremental collections. + * + * @param parent. object with member variable being modified + * @param lhs. address of a member variable within the allocation of @p parent. + * @param rhs. new target for @p *lhs + **/ + virtual void assign_member(Object * parent, Object ** lhs, Object* rhs) final override; - virtual void release_redline_memory() override; + virtual std::byte * alloc(std::size_t z) final override; + virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; + + virtual void release_redline_memory() final override; private: /** begin GC now **/ @@ -248,12 +312,35 @@ namespace xo { void swap_nursery(); /** swap roles of From/To spaces for tenured generation **/ void swap_tenured(); + /** swap roles of From/To spaces for mutation log **/ + void swap_mutation_log(); /** swap roles of FromSpace/ToSpace **/ void swap_spaces(generation g); /** copy object **/ void copy_object(Object ** addr, generation upto, ObjectStatistics * object_stats); /** copy everything reachable from global gc roots **/ void copy_globals(generation g); + /** review mutation log; may discover+rescue reachable objects. + **/ + void forward_mutation_log(generation upto); + /** Aux function for @ref execute_gc. Updates bookkeeping for cross-generational + * (T->N, aka xgen) and (N1->N0, aka xckp) pointers + **/ + void incremental_gc_forward_mlog(ObjectStatistics * per_type_stats); + + /** + * Aux function for @ref incremental_gc_forward_mlog. Calls this function until + * fixpoint. + * + * @param from_mlog incoming mutation log. Contains {xgen,xckp} pointers before GC. + * Contents of this log is consumed (+discarded) before method returns. + * @param to_mlog outgoing mutation log. Will contain {xgen,xckp} pointers after GC. + * @param defer_mlog contains log entries associated with possible garbage. + **/ + void incremental_gc_forward_mlog_phase(MutationLog * from_mlog, + MutationLog * to_mlog, + MutationLog * defer_mlog, + ObjectStatistics * per_type_stats); private: /** garbage collector configuration **/ @@ -262,11 +349,11 @@ namespace xo { /** contains allocated objects, along with unreachable garbage to be collected. * roles reverse after each incremental, or full, collection. **/ - std::array, static_cast(role::N)> nursery_; + std::array, role2int(role::N)> nursery_; /** empty space, destination for objects that survive collection. * roles reverse after each full collection. **/ - std::array, static_cast(role::N)> tenured_; + std::array, role2int(role::N)> tenured_; /** current state of GC activity. * @text @@ -286,6 +373,13 @@ namespace xo { **/ std::vector gc_root_v_; + /** log cross-generational and cross-checkpoint mutations. + * These need to be adjusted on next incremental collection + **/ + std::array, role2int(role::N)> mutation_log_; + /** temporary mutation log (for deferred entries) **/ + up defer_mutation_log_; + /** allocation/collection counters **/ GcStatistics gc_statistics_; diff --git a/include/xo/alloc/IAlloc.hpp b/include/xo/alloc/IAlloc.hpp index 2f759c53..272fe9ad 100644 --- a/include/xo/alloc/IAlloc.hpp +++ b/include/xo/alloc/IAlloc.hpp @@ -12,6 +12,8 @@ namespace xo { template using up = std::unique_ptr; + class Object; + namespace gc { /** @class IAllocator * @brief memory allocation interface with limited garbaga collector support @@ -27,6 +29,8 @@ namespace xo { /** z + alloc_padding(z) **/ static std::size_t with_padding(std::size_t z); + /** optional name for this allocator; labelling for diagnostics **/ + virtual const std::string & name() const = 0; /** allocator size in bytes (up to soft limit). * Includes unallocated mmeory **/ @@ -47,15 +51,25 @@ namespace xo { virtual std::size_t before_checkpoint() const = 0; /** number of bytes allocated since @ref checkpoint **/ virtual std::size_t after_checkpoint() const = 0; + /** @return true iff debug logging enabled **/ + virtual bool debug_flag() const { return false; } /** reset allocator to empty state. **/ virtual void clear() = 0; - /** remember allocator state. All currently-allocated addresses x + /** remember allocator state. All currently-allocated addresses xo * will satisfy is_before_checkpoint(x). Subsequent allocations x * will fail is_before_checkpoint(x), until checkpoint superseded * by @ref clear or another call to @ref checkpoint **/ virtual void checkpoint() = 0; + /** perform assignment + * @code + * *lhs = rhs + * @endcode + * plus additional book keeping if needed (e.g. in @ref GC) + * Default implementation just does the assignment. + **/ + virtual void assign_member(Object * parent, Object ** lhs, Object * rhs); /** allocate @p z bytes of memory. returns pointer to first address **/ virtual std::byte * alloc(std::size_t z) = 0; /** allocate @p z bytes for copy of object at @p src. diff --git a/include/xo/alloc/ListAlloc.hpp b/include/xo/alloc/ListAlloc.hpp index 8d27e6b4..db1a2df7 100644 --- a/include/xo/alloc/ListAlloc.hpp +++ b/include/xo/alloc/ListAlloc.hpp @@ -45,18 +45,19 @@ namespace xo { // inherited from IAlloc.. - virtual std::size_t size() const override; - virtual std::size_t available() const override; - virtual std::size_t allocated() const override; - virtual bool contains(const void * x) const override; - virtual bool is_before_checkpoint(const void * x) const override; - virtual std::size_t before_checkpoint() const override; - virtual std::size_t after_checkpoint() const override; + virtual const std::string & name() const final override; + virtual std::size_t size() const final override; + virtual std::size_t available() const final override; + virtual std::size_t allocated() const final override; + virtual bool contains(const void * x) const final override; + virtual bool is_before_checkpoint(const void * x) const final override; + virtual std::size_t before_checkpoint() const final override; + virtual std::size_t after_checkpoint() const final override; - virtual void clear() override; - virtual void checkpoint() override; - virtual std::byte * alloc(std::size_t z) override; - virtual void release_redline_memory() override; + virtual void clear() final override; + virtual void checkpoint() final override; + virtual std::byte * alloc(std::size_t z) final override; + virtual void release_redline_memory() final override; private: /** **/ diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index f66e8e9a..f8e45e84 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -15,8 +15,6 @@ namespace xo { class ObjectStatistics; }; - class Object; - template class gc_ptr; @@ -88,6 +86,13 @@ namespace xo { **/ static gc::IAlloc * mm; + /** assign value @p rhs to member @p *lhs of @p parent. + * if assignment creates a cross-generational or cross-checkpoint pointer, + * add mutation log entry + **/ + template + static void assign_member(gp parent, gp * lhs, gp rhs); + /** use from GC aux functions **/ static gc::GC * _gc() { return reinterpret_cast(mm); } @@ -127,6 +132,13 @@ namespace xo { * initially all reachable objects are black. * GC is complete when all reachable objects are white. * GC needs a variable amount of temporary storage to keep track of all gray objects + * + * Evacuate reachable object graph rooted at @p src to to-space. + * On return all objects reachable from @p src are white + * + * @param src address of object to evacuate + * @param gc garbage collector + * @param stats per-object-type GC statistics **/ static Object * _deep_move(Object * src, gc::GC * gc, gc::ObjectStatistics * stats); @@ -213,6 +225,15 @@ namespace xo { virtual std::size_t _forward_children() = 0; }; + template + void + Object::assign_member(gp parent, gp * lhs, gp rhs) + { + Object::mm->assign_member(parent.ptr(), + reinterpret_cast(lhs->ptr_address()), + rhs.ptr()); + } + /** @class Cpof * @brief argument to operator new used for garbage collector evacuation phase * diff --git a/src/alloc/Forwarding1.cpp b/src/alloc/Forwarding1.cpp index 825115a2..ca4f051b 100644 --- a/src/alloc/Forwarding1.cpp +++ b/src/alloc/Forwarding1.cpp @@ -21,6 +21,11 @@ namespace xo { return dest_.ptr() + offset; } + Object * + Forwarding1::_destination() { + return dest_.ptr(); + } + std::size_t Forwarding1::_shallow_size() const { assert(false); diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index ec4aa647..6dd8a929 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -71,6 +71,51 @@ namespace xo { << ">"; } + bool + MutationLogEntry::is_child_forwarded() const + { + assert(!parent_->_is_forwarded()); + + return (*lhs_)->_is_forwarded(); + } + + bool + MutationLogEntry::is_parent_forwarded() const + { + return parent_->_is_forwarded(); + } + + Object * + MutationLogEntry::parent_destination() const + { + //const bool c_debug_flag = true; + //scope log(XO_DEBUG(c_debug_flag)); + + if (parent_->_is_forwarded()) { + //log && log("parent is forwarded", xtag("parent", (void*)parent_)); + + return parent_->_destination(); + } else { + //log && log("parent is ordinary", xtag("parent", (void*)parent_)); + + return parent_; + } + } + + MutationLogEntry + MutationLogEntry::update_parent_moved(Object * parent_to) const + { + std::byte * parent_from = reinterpret_cast(parent_); + std::byte * lhs_from = reinterpret_cast(lhs_); + + std::ptrdiff_t offset = (lhs_from - parent_from); + + std::byte * lhs_to = reinterpret_cast(parent_to) + offset; + + return MutationLogEntry(parent_to, + reinterpret_cast(lhs_to)); + } + GC::GC(const Config & config) : config_{config} { @@ -89,6 +134,10 @@ namespace xo { tenured_[role2int(role::to_space) ] = ListAlloc::make("TB", tenured_size, 2 * tenured_size, config.debug_flag_); + mutation_log_[role2int(role::from_space)] = std::make_unique(); + mutation_log_[role2int(role::to_space)] = std::make_unique(); + defer_mutation_log_ = std::make_unique(); + this->checkpoint(); } @@ -100,6 +149,13 @@ namespace xo { return up{gc}; } + const std::string & + GC::name() const + { + static std::string s_default_name = "GC"; + return s_default_name; + } + std::size_t GC::size() const { @@ -151,22 +207,34 @@ namespace xo { return nursery_[role2int(role::to_space)]->after_checkpoint(); } - generation + bool + GC::debug_flag() const + { + return config_.debug_flag_; + } + + generation_result GC::fromspace_generation_of(const void * x) const { if (tenured_[role2int(role::from_space)]->contains(x)) - return generation::tenured; + return generation_result::tenured; - return generation::nursery; + if (nursery_[role2int(role::from_space)]->contains(x)) + return generation_result::nursery; + + return generation_result::not_found; } - generation - GC::generation_of(const void * x) const + generation_result + GC::tospace_generation_of(const void * x) const { if (tenured_[role2int(role::to_space)]->contains(x)) - return generation::tenured; + return generation_result::tenured; - return generation::nursery; + if (nursery_[role2int(role::to_space)]->contains(x)) + return generation_result::nursery; + + return generation_result::not_found; } std::byte * @@ -184,6 +252,11 @@ namespace xo { return nullptr; } + std::size_t + GC::mlog_size() const { + return mutation_log_[role2int(role::to_space)]->size(); + } + void GC::clear() { @@ -231,39 +304,55 @@ namespace xo { { scope log(XO_DEBUG(config_.debug_flag_), xtag("z", z), xtag("+pad", IAlloc::alloc_padding(z))); - generation g = this->fromspace_generation_of(src); + generation_result gr = this->fromspace_generation_of(src); std::byte * retval = nullptr; - if (g == generation::tenured) - { - log && log("tenured"); + switch (gr) { + case generation_result::tenured: + { + log && log("tenured"); - retval = tenured_[role2int(role::to_space)]->alloc(z); - } else if (nursery_[role2int(role::from_space)]->is_before_checkpoint(src)) - { - log && log("promote"); - - /* nursery object has survived 2nd collection cycle - * -> promote into tenured generation - */ - retval = tenured_[role2int(role::to_space)]->alloc(z); - - this->gc_statistics_.total_promoted_ += IAlloc::with_padding(z); - } else { - log && log("nursery"); - - retval = nursery_[role2int(role::to_space)]->alloc(z); - - if (!retval) { - /* nursery space exhausted */ - - this->request_gc(generation::nursery); - - nursery_[role2int(role::to_space)]->release_redline_memory(); - - retval = nursery_[role2int(role::to_space)]->alloc(z); + retval = tenured_[role2int(role::to_space)]->alloc(z); } + break; + case generation_result::nursery: + { + if (nursery_[role2int(role::from_space)]->is_before_checkpoint(src)) + { + /* nursery object has survived 2nd collection cycle + * -> promote into tenured generation + */ + retval = tenured_[role2int(role::to_space)]->alloc(z); + + log && log("promote", xtag("addr", (void*)retval)); + + assert(this->tospace_generation_of(retval) == generation_result::tenured); + + this->gc_statistics_.total_promoted_ += IAlloc::with_padding(z); + } else { + log && log("nursery"); + + retval = nursery_[role2int(role::to_space)]->alloc(z); + + if (!retval) { + /* nursery space exhausted !? */ + + this->request_gc(generation::nursery); + + nursery_[role2int(role::to_space)]->release_redline_memory(); + + retval = nursery_[role2int(role::to_space)]->alloc(z); + } + } + } + break; + case generation_result::not_found: + /* something wrong -- we only copy objects that are known to be in from-space + */ + + assert(false); + break; } assert(retval); @@ -271,6 +360,63 @@ namespace xo { return retval; } + void + GC::assign_member(Object * parent, Object ** lhs, Object * rhs) + { + ++gc_statistics_.n_mutation_; + + *lhs = rhs; + + if (runstate_.in_progress()) { + /* don't log mutations (if any) during GC */ + return; + } + + if (!config_.allow_incremental_gc_) { + /* full GCs don't need mutation log, since no cross-generational pointers */ + return; + } + + switch (tospace_generation_of(rhs)) + { + case generation_result::tenured: + /* only need to log mutations that create tenured->nursery pointers */ + return; + + case generation_result::nursery: + switch (tospace_generation_of(parent)) { + case generation_result::nursery: + if (is_before_checkpoint(parent)) { + // N1->N0, so must log + this->mutation_log_[role2int(role::to_space)]->push_back(MutationLogEntry(parent, lhs)); + ++(this->gc_statistics_.n_logged_mutation_); + ++(this->gc_statistics_.n_xckp_mutation_); + } else { + // parent in N0, not an xckp mutation + return; + } + break; + case generation_result::tenured: + // T->N, so must log + this->mutation_log_[role2int(role::to_space)]->push_back(MutationLogEntry(parent, lhs)); + ++(this->gc_statistics_.n_logged_mutation_); + ++(this->gc_statistics_.n_xgen_mutation_); + break; + case generation_result::not_found: + // parent is global + // This may be ok (provided lhs is a gc root) + break; + } + break; + + case generation_result::not_found: + + // child is global; + // logging not required + break; + } + } + void GC::release_redline_memory() { @@ -293,10 +439,20 @@ namespace xo { tenured_[role2int(role::from_space)] = std::move(tmp); } + void + GC::swap_mutation_log() + { + up tmp = std::move(mutation_log_[role2int(role::to_space)]); + mutation_log_[role2int(role::to_space)] = std::move(mutation_log_[role2int(role::from_space)]); + mutation_log_[role2int(role::from_space)] = std::move(tmp); + } + void GC::swap_spaces(generation target) { - // will be copying into storage currently labelled FromSpace + scope log(XO_DEBUG(this->debug_flag())); + + // will be copying into the memory regions currently labelled FromSpace /* gc will copy some to-be-determined amount in [0..promote_z] from nursery->tenured generation. @@ -321,6 +477,14 @@ namespace xo { - promote_z + incr_gc_threshold_); this->swap_nursery(); + + this->swap_mutation_log(); + + log && log(xtag("nursery.from", nursery_[role2int(role::from_space)]->name())); + log && log(xtag("nursery.to", nursery_[role2int(role::to_space) ]->name())); + log && log(xtag("tenured.from", tenured_[role2int(role::from_space)]->name())); + log && log(xtag("tenured.to", tenured_[role2int(role::to_space) ]->name())); + } /*swap_spaces*/ void @@ -351,6 +515,242 @@ namespace xo { } } + void + GC::incremental_gc_forward_mlog_phase(MutationLog * from_mlog, + MutationLog * to_mlog, + MutationLog * defer_mlog, + ObjectStatistics * per_type_stats) + { + scope log(XO_DEBUG(config_.debug_flag_), xtag("from_mlog.size", from_mlog->size())); + + /* categorize pointers based on combination of {source address, destination address}, + * only care about the generation associated with an address. + * + * N0 : nursery(from), before checkpoint + * N0': nursery(to), before checkpoint + * N1 : nursery(from), after checkpoint + * N1': nursery(to), after checkpoint + * T : tenured(to) + * + * loc(P): parent region before GC + * loc(C): child region before GC + * + * | | forwarded | loc now post | loc after | + * | | already? | root copy | action | + * | loc(P) loc(C) | P C | P' C' | P' C' | defer | action + * ----|---------------+--------------+---------------+---------------+-------+--------------- + * (a) | T N0 | no no | T N0 | T N1' | | C->N1', +mlog + * (b) | | yes | N1' | N1' | | +mlog + * (c) | T N1 | no no | T N1 | T T | | C->T, -mlog + * (d) | | yes | T T | T T | | -mlog + * (e) | N1 N0 | no no | N1 N0 | N1 N0 | P ->C | defer + * (f) | | yes | N1 N1' | N1 N1' | P ->C'| defer + * (g) | | yes yes | T N1' | T N1' | | +mlog + * + * notes: + * (a) C survives due to xgen ptr {T -> N0}; after collection have xgen ptr {T -> N1}. + * (b) C already evac'd; after collection stil have xgen ptr {T -> N1} + * (c) C survives due to xgen ptr (T -> N1): promote to T, so no longer xgen + * (d) C already evac'd: after collection no longer xgen (T -> T) + * (e) P,C maybe garbage. don't move either, but defer mlog incase P saved by a subsequent mutation. + * in that case C saved alto, + will still have an xgen ptr, so still need an mlog entry + * (f) P maybe garbage, C survives. defer mlog incase P saved+promoted by a subsequent mutation; + * in that case will still have an xgen (T -> N) ptr, so still need an mlog entry. + */ + + std::size_t i_from = 0; + // number of rescued subgraphs via mutation log entries + std::size_t n_rescue = 0; + + for (MutationLogEntry & from_entry : *from_mlog) + { + if (log) { + if (i_from % 10000 == 0) + log(xtag("i_from", i_from)); + } + + void * parent = from_entry.parent(); + + if (tospace_generation_of(parent) == generation_result::tenured) + { + // cases (a)(b)(c)(d) + // loc(P) is T. T didn't move b/c incremental gc. + + if (from_entry.is_dead()) { + // obsolete mutation -- no longer belongs to parent, discard + } else { + // note: child obtained (as it must be) by reading from parent's memory _now_. + Object * child_from = from_entry.child(); + + if (child_from) { + if (!child_from->_is_forwarded()) { + // P->C*. + // either: + // - C*=C in from-space, so needs evac + // - C*=C' in to-space, P already updated b/c of another mutation + // + if (fromspace_generation_of(child_from) != generation_result::not_found) { + // C*=C in from-space. needs evac, along with reachable descendants + // + // Includes cases: + // (a) T->N0 + // (c) T->N1 + + ++n_rescue; + + Object::_deep_move(child_from, this, per_type_stats); + + // C forwards to C', fall thru to parent fixup below + // (a) T->N1' + // (c) T->T + } else { + // P updated via some other mutation + // so don't need this mlog + ; + } + } + + // re-test, state may have changed above + if (from_entry.is_child_forwarded()) { + // P->C, C moved to C' + // Includes cases (a),(c) from above + + Object * child_to = child_from->_destination(); + + from_entry.fixup_parent_child_moved(child_to); + + // P->C', loc(C') in {N1', T'} + + if (tospace_generation_of(child_to) == generation_result::nursery) { + // (b) loc(P)=T, loc(C')=N1'; also case (a) + + // still have xgen pointer, so need mlog for it + to_mlog->push_back(from_entry); + } else { + // (d) loc(P)=T, loc(C')=T; also case (c) + // no longer xgen, so does not require mlog + } + } + + } else { + // nullptr child, discard + } + } + } else if (from_entry.is_parent_forwarded()) { + // Must have: + // loc(P) = N1, because: + // loc(P)=N0 -> ineligible for mlog; + // loc(P)=T -> not moved on incr GC + // + // follows that loc(P') = T + // already have P'->C' when parent moved separately + + Object * parent_to = from_entry.parent_destination(); + + log(xtag("parent_to", (void*)parent_to)); + + assert(tospace_generation_of(parent_to) == generation_result::tenured); + + MutationLogEntry to_entry = from_entry.update_parent_moved(parent_to); + + Object * child_to = to_entry.child(); // after moving + + if (tospace_generation_of(child_to) == generation_result::nursery) { + if (to_entry.is_dead()) { + ; + } else { + // (g) loc(P)=N1, loc(C)=N0, loc(P')=T, loc(C')=N1 + to_mlog->push_back(to_entry); + } + + } + } else { + // loc(P) = N1, loc(C) = N0, P may be garbage + // Includes cases: + // (e) P->C, C not moved + // (f) P->C, C moved to C' + // + // P may yet be rescued by another mlog entry, so defer + + if (!from_entry.is_dead()) { + defer_mlog->push_back(from_entry); + } + } + + ++i_from; + } + + from_mlog->clear(); + + if (n_rescue == 0) { + // if we didn't rescue any objects + // then we now confirm that otherwise-unreachable parents in defer_mlog + // are garbage + + defer_mlog->clear(); + } + } + + void + GC::incremental_gc_forward_mlog(ObjectStatistics * per_type_stats) + { + /* control here: + * - incremental gc. + * - gc roots have been copied, along with everything reachable from them. + * + * plan: + * - forward mutation in *from_mutation_log, writing them to + * *to_mutationlog and/or *defer_mutation_log. + * Use defer when mutation P->C encountered, but P was not copied. + * P appears to be garbage, but may turn out to be live if encountered + * in another mutation. + * + */ + + MutationLog * to_mlog = mutation_log_[role2int(role::to_space)].get(); + + for (;;) { + MutationLog * from_mlog = mutation_log_[role2int(role::from_space)].get(); + MutationLog * defer_mlog = defer_mutation_log_.get(); + + this->incremental_gc_forward_mlog_phase(from_mlog, + to_mlog, + defer_mlog, + per_type_stats); + + assert(from_mlog->empty()); + + if (defer_mlog->empty()) { + /* fixpoint reached */ + break; + } + + /* control here: + * 1. at least one mlog triggered a rescue + * 2. at least one mlog was deferred (b/c otherwise-unreachable parent) + * + * it's conceivable deferred parent now reachable thanks to rescues; + * revisit entries in defer_mlog, + * + * using now-empty from_mlog as scratch for any remaining deferred entries + */ + + std::swap(mutation_log_[role2int(role::from_space)], defer_mutation_log_); + } + } + + void + GC::forward_mutation_log(generation upto) + { + scope log(XO_DEBUG(config_.debug_flag_)); + + if (upto == generation::tenured) { + log && log("TODO: forward mutation log for full GC"); + } else { + this->incremental_gc_forward_mlog(&gc_statistics_.per_type_stats_); + } + } + void GC::cleanup_phase(generation upto) { @@ -401,11 +801,11 @@ namespace xo { } void - GC::execute_gc(generation target) + GC::execute_gc(generation upto) { scope log(XO_DEBUG(config_.debug_flag_)); - bool full_move = (target == generation::tenured); + bool full_move = (upto == generation::tenured); // TODO: RAII version in case of exceptions this->runstate_ = GCRunstate(true /*in_progress*/, full_move); @@ -415,7 +815,7 @@ namespace xo { /* new allocation since last GC */ std::size_t new_alloc = this->after_checkpoint(); - ++(gc_statistics_.gen_v_[static_cast(target)].n_gc_); + ++(gc_statistics_.gen_v_[static_cast(upto)].n_gc_); gc_statistics_.total_allocated_ += new_alloc; gc_statistics_.total_promoted_sab_ = gc_statistics_.total_promoted_; @@ -423,15 +823,17 @@ namespace xo { log && log("step 1: swap to/from roles"); - this->swap_spaces(target); + this->swap_spaces(upto); log && log("step 2a: copy globals"); - this->copy_globals(target); + this->copy_globals(upto); log && log("step 2b: TODO: copy pinned"); - log && log("step 3: TODO: forward mutation log"); + log && log("step 3: forward mutation log"); + + this->forward_mutation_log(upto); log && log("step 4: TODO: notify destructor log"); @@ -439,7 +841,7 @@ namespace xo { log && log("step 6: cleanup"); - this->cleanup_phase(target); + this->cleanup_phase(upto); this->runstate_ = GCRunstate(); diff --git a/src/alloc/IAlloc.cpp b/src/alloc/IAlloc.cpp index 4fbdd556..6e06a644 100644 --- a/src/alloc/IAlloc.cpp +++ b/src/alloc/IAlloc.cpp @@ -41,6 +41,12 @@ namespace xo { return z + alloc_padding(z); } + void + IAlloc::assign_member(Object * /*parent*/, Object ** lhs, Object * rhs) + { + *lhs = rhs; + } + std::byte * IAlloc::alloc_gc_copy(std::size_t /*z*/, const void * /*src*/) { diff --git a/src/alloc/ListAlloc.cpp b/src/alloc/ListAlloc.cpp index 76da8b19..a5ae38e7 100644 --- a/src/alloc/ListAlloc.cpp +++ b/src/alloc/ListAlloc.cpp @@ -50,6 +50,16 @@ namespace xo { return retval; } + const std::string & + ListAlloc::name() const { + if (hd_) { + return hd_->name(); + } + + static std::string s_default_name = "ListAlloc"; + return s_default_name; + } + std::size_t ListAlloc::size() const { return total_z_; diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index 7aa1a8d0..d3772003 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -34,7 +34,7 @@ namespace xo { bool full_move = gc->runstate().full_move(); - if (!full_move && (gc->generation_of(src) == gc::generation::tenured)) { + if (!full_move && (gc->tospace_generation_of(src) == gc::generation_result::tenured)) { /* don't move tenured objects during incremental collection */ return src; } @@ -61,7 +61,7 @@ namespace xo { bool full_move = gc->runstate().full_move(); - if (!full_move && gc->generation_of(from_src) == generation::tenured) { + if (!full_move && gc->tospace_generation_of(from_src) == gc::generation_result::tenured) { /** incremental collection does not move already-tenured objects **/ return from_src; } diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index d37786e3..50882bba 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -1,11 +1,13 @@ # build unittest alloc/utest +# +# NOTE: more GC tests in xo-object/utest -set(SELF_EXE utest.alloc) -set(SELF_SRCS +set(UTEST_EXE utest.alloc) +set(UTEST_SRCS alloc_utest_main.cpp ArenaAlloc.test.cpp GC.test.cpp) -xo_add_utest_executable(${SELF_EXE} ${SELF_SRCS}) -xo_self_dependency(${SELF_EXE} xo_alloc) -xo_external_target_dependency(${SELF_EXE} Catch2 Catch2::Catch2) +xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) +xo_self_dependency(${UTEST_EXE} xo_alloc) +xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2) diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp index dc175615..12445624 100644 --- a/utest/GC.test.cpp +++ b/utest/GC.test.cpp @@ -65,5 +65,8 @@ namespace xo { REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 1); } } + } /*namespace ut*/ } /*namespace xo*/ + +/* GC.test.cpp */ From 19520f017b24329776af966d7920f9b5294f3f64 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 5 Aug 2025 11:09:26 -0500 Subject: [PATCH 003/342] xo-object: GC unit test --- docs/glossary.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 docs/glossary.rst diff --git a/docs/glossary.rst b/docs/glossary.rst new file mode 100644 index 00000000..4e50a499 --- /dev/null +++ b/docs/glossary.rst @@ -0,0 +1,28 @@ +.. _glossary: + +Glossary +-------- + +.. glossary:: + GC + | garbage collector + + mlog + | mutation log. + | Remembers cross-generation and cross-checkpoint pointers + + nursery + | in garbage collector, memory region dedicated to young objects. + | These are objects that have survived less than 2 incremental collection cycles. + + tenured + | in garbage collector, memory region dedicated to older objects. + | These are defined as objects that have survived 2 or more incremental collection cycles. + + xgen + | cross-generation tenured->nursery pointer; requires special GC bookkeeping + + xckp + | cross-checkpoint pointer; requires special GC bookkeeping + +.. toctree:: From fc9180363d1a57510b190ca9bf85c118b284c2a1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 6 Aug 2025 09:30:37 -0500 Subject: [PATCH 004/342] xo-object: generative GC utest + reinstate coverage build --- include/xo/alloc/GC.hpp | 1 + src/alloc/ArenaAlloc.cpp | 11 ++++++----- src/alloc/Forwarding1.cpp | 6 ++++++ src/alloc/GC.cpp | 19 ++++++++++++++++++- src/alloc/IAlloc.cpp | 2 ++ utest/CMakeLists.txt | 1 + 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 0c50a722..6f9573f3 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -218,6 +218,7 @@ namespace xo { public: /** create new GC instance with configuration @p config **/ explicit GC(const Config & config); + virtual ~GC(); /** create GC allocator. * diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index 227e2d63..c3f70d8c 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -56,6 +56,8 @@ namespace xo { if (lo_ <= x && x < limit_) { this->free_ptr_ = x; + if (this->checkpoint_ > free_ptr_) + this->checkpoint_ = free_ptr_; } else { throw std::runtime_error(tostr("LinearAllog::set_free_ptr(x): expected lo <= x < limit", xtag("lo", lo_), xtag("x", x), xtag("limit", limit_))); @@ -102,8 +104,7 @@ namespace xo { void ArenaAlloc::clear() { - this->checkpoint_ = lo_; - this->free_ptr_ = lo_; + this->set_free_ptr(lo_); this->limit_ = hi_ - redline_z_; } @@ -133,14 +134,14 @@ namespace xo { std::byte * retval = this->free_ptr_; - this->free_ptr_ += z1; - log && log(xtag("self", name_), xtag("z0", z0), xtag("+pad", dz), xtag("z1", z1)); - if (free_ptr_ > limit_) { + if (free_ptr_ + z1 > limit_) { return nullptr; } + this->free_ptr_ += z1; + return retval; } diff --git a/src/alloc/Forwarding1.cpp b/src/alloc/Forwarding1.cpp index ca4f051b..32d95b60 100644 --- a/src/alloc/Forwarding1.cpp +++ b/src/alloc/Forwarding1.cpp @@ -26,23 +26,29 @@ namespace xo { return dest_.ptr(); } + // LCOV_EXCL_START std::size_t Forwarding1::_shallow_size() const { assert(false); return 0; } + // LCOV_EXCL_STOP + // LCOV_EXCL_START Object * Forwarding1::_shallow_copy() const { assert(false); return nullptr; } + // LCOV_EXCL_STOP + // LCOV_EXCL_START std::size_t Forwarding1::_forward_children() { assert(false); return 0; } + // LCOV_EXCL_STOP } /*namespace obj*/ } /*namespace xo*/ diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 6dd8a929..4f106779 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -141,6 +141,21 @@ namespace xo { this->checkpoint(); } + GC::~GC() { + /* hygiene */ + this->clear(); + + nursery_[role2int(role::from_space)].reset(); + nursery_[role2int(role::to_space) ].reset(); + + tenured_[role2int(role::from_space)].reset(); + tenured_[role2int(role::to_space) ].reset(); + + mutation_log_[role2int(role::from_space)].reset(); + mutation_log_[role2int(role::to_space) ].reset(); + defer_mutation_log_.reset(); + } + up GC::make(const Config & config) { @@ -245,8 +260,10 @@ namespace xo { return nursery_[role2int(role::to_space)]->free_ptr(); case generation::tenured: return tenured_[role2int(role::to_space)]->free_ptr(); + // LCOV_EXCL_START case generation::N: assert(false); + // LCOV_EXCL_STOP } return nullptr; @@ -647,7 +664,7 @@ namespace xo { Object * parent_to = from_entry.parent_destination(); - log(xtag("parent_to", (void*)parent_to)); + log && log(xtag("parent_to", (void*)parent_to)); assert(tospace_generation_of(parent_to) == generation_result::tenured); diff --git a/src/alloc/IAlloc.cpp b/src/alloc/IAlloc.cpp index 6e06a644..8fe4789a 100644 --- a/src/alloc/IAlloc.cpp +++ b/src/alloc/IAlloc.cpp @@ -47,12 +47,14 @@ namespace xo { *lhs = rhs; } + // LCOV_EXCL_START std::byte * IAlloc::alloc_gc_copy(std::size_t /*z*/, const void * /*src*/) { assert(false); return nullptr; } + // LCOV_EXCL_STOP } /*namespace gc*/ } /*namespace xo*/ diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 50882bba..b38a442f 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -5,6 +5,7 @@ set(UTEST_EXE utest.alloc) set(UTEST_SRCS alloc_utest_main.cpp + IAlloc.test.cpp ArenaAlloc.test.cpp GC.test.cpp) From ff5b0cfb8aa478b5888858bed9587b4235052c8f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 6 Aug 2025 09:32:09 -0500 Subject: [PATCH 005/342] xo-alloc xo-object; + utests --- utest/IAlloc.test.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 utest/IAlloc.test.cpp diff --git a/utest/IAlloc.test.cpp b/utest/IAlloc.test.cpp new file mode 100644 index 00000000..b0214749 --- /dev/null +++ b/utest/IAlloc.test.cpp @@ -0,0 +1,29 @@ +/* @file IAlloc.test.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "xo/alloc/IAlloc.hpp" +#include + +namespace xo { + using xo::gc::IAlloc; + + namespace ut { + TEST_CASE("ialloc", "[alloc]") + { + REQUIRE(IAlloc::alloc_padding(0) == 0); + REQUIRE(IAlloc::alloc_padding(1) == 7); + REQUIRE(IAlloc::alloc_padding(2) == 6); + REQUIRE(IAlloc::alloc_padding(3) == 5); + REQUIRE(IAlloc::alloc_padding(4) == 4); + REQUIRE(IAlloc::alloc_padding(5) == 3); + REQUIRE(IAlloc::alloc_padding(6) == 2); + REQUIRE(IAlloc::alloc_padding(7) == 1); + REQUIRE(IAlloc::alloc_padding(8) == 0); + REQUIRE(IAlloc::alloc_padding(9) == 7); + } + } /*namespace ut*/ +} /*namespace xo*/ + +/* end IAlloc.test.cpp */ From 432e0efce2acfa5008a7a054d32d5e70eb4ab5d6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 6 Aug 2025 13:53:31 -0500 Subject: [PATCH 006/342] xo-object: improve GC unittest + prep to integrate w/ xo::reflect --- include/xo/alloc/GC.hpp | 116 +-------------------- include/xo/alloc/GcStatistics.hpp | 161 ++++++++++++++++++++++++++++++ include/xo/alloc/Object.hpp | 1 + include/xo/alloc/generation.hpp | 26 +++++ src/alloc/CMakeLists.txt | 3 +- src/alloc/GC.cpp | 38 +++++++ src/alloc/GcStatistics.cpp | 68 +++++++++++++ utest/GC.test.cpp | 12 +-- 8 files changed, 305 insertions(+), 120 deletions(-) create mode 100644 include/xo/alloc/GcStatistics.hpp create mode 100644 include/xo/alloc/generation.hpp create mode 100644 src/alloc/GcStatistics.cpp diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 6f9573f3..4fb9f518 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -6,6 +6,7 @@ #pragma once #include "ListAlloc.hpp" +#include "GcStatistics.hpp" #include "xo/indentlog/print/array.hpp" #include #include @@ -15,20 +16,6 @@ namespace xo { class Object; namespace gc { - enum class generation { - nursery, - tenured, - N - }; - - constexpr std::size_t gen2int(generation x) { return static_cast(x); } - - enum class generation_result { - nursery, - tenured, - not_found - }; - enum class role { /** nursery: generation for new objects **/ from_space, @@ -59,104 +46,6 @@ namespace xo { bool debug_flag_ = false; }; - /** @class ObjectStatistics - * @brief placeholder for type-driven allocation statistics - * - * Passed to @ref Object::deep_move for example - **/ - class ObjectStatistics { - }; - - /** @class PerGenerationStatistics - * @brief garbage collection statistics for particular GC generation - **/ - class PerGenerationStatistics { - public: - /** update statistics after a GC cycle - * @param alloc_z. new allocations (since preceding GC) - * @param before_z. generation size (bytes allocated) before collection - * @param after_z. generation size after collection - * @param promote_z. bytes promoted to next generation - **/ - void include_gc(std::size_t alloc_z, std::size_t before_z, std::size_t after_z, - std::size_t promote_z); - /** update with current state (use at end of gc cycle) **/ - void update_snapshot(std::size_t after_z); - - /** @param os. write stats on this output stream **/ - void display(std::ostream & os) const; - - /** number of bytes currently in use **/ - std::size_t used_z_ = 0; - - /** number of collection cycles completed **/ - std::size_t n_gc_ = 0; - /** sum of new alloc bytes, sampled at start of each collection cycle **/ - std::size_t new_alloc_z_ = 0; - /** sum of allocated bytes sampled at beginning of each collection cycle **/ - std::size_t scanned_z_ = 0; - /** sum of bytes remaining after collection cycle **/ - std::size_t survive_z_ = 0; - /** sum of bytes promoted to next generation **/ - std::size_t promote_z_ = 0; - }; - - inline std::ostream & operator<< (std::ostream & os, const PerGenerationStatistics & x) { - x.display(os); - return os; - } - - /** @class GcStatistics - * @brief garbage collection statistics - **/ - class GcStatistics { - public: - /** update statistics after a GC cycle - * @param upto. nursery -> incremental collection; tenured -> full collection - * @param alloc_z. new allocations (since preceding GC) - * @param before_z. generation size (bytes allocated) before collection - * @param after_z. generation size after collection - * @param promote_z. bytes promoted to next generation - **/ - void include_gc(generation upto, std::size_t alloc_z, - std::size_t before_z, std::size_t after_z, std::size_t promote_z); - /** update snapshot for current state. - * Use with tenured stats after incremental gc - **/ - void update_snapshot(generation upto, std::size_t after_z); - - /** @param os. write stats on this output stream **/ - void display(std::ostream & os) const; - - /** statistics gathered across {incr, full} GCs respectively **/ - std::array(generation::N)> gen_v_; - /** total bytes allocated since inception **/ - std::size_t total_allocated_ = 0; - /** snapshot of total bytes promoted asof beginning of last gc cycle **/ - std::size_t total_promoted_sab_ = 0; - /** total bytes promoted from nursery->tenured since inception **/ - std::size_t total_promoted_ = 0; - - /** total number of mutations to already-allocated objects, - * whether or not GC needs to log them. - **/ - std::size_t n_mutation_ = 0; - /** total number of mutation eligible for logging **/ - std::size_t n_logged_mutation_ = 0; - /** total number of cross-generation mutations (tenured->nursery when reported) **/ - std::size_t n_xgen_mutation_ = 0; - /** total number of cross-checkpoint mutations (N0 -> N1 when reported) **/ - std::size_t n_xckp_mutation_ = 0; - - /** per-type statistics (placeholder) **/ - ObjectStatistics per_type_stats_; - }; - - inline std::ostream & operator<< (std::ostream & os, const GcStatistics & x) { - x.display(os); - return os; - } - /** @class GCRunstate * @brief encapsulate state needed while GC is running * @@ -228,7 +117,8 @@ namespace xo { static up make(const Config & config); const GCRunstate & runstate() const { return runstate_; } - const GcStatistics & gc_statistics() const { return gc_statistics_; } + const GcStatistics & native_gc_statistics() const { return gc_statistics_; } + GcStatisticsExt get_gc_statistics() const; /** true iff GC permitted in current state **/ bool is_gc_enabled() const { return gc_enabled_ == 0; } diff --git a/include/xo/alloc/GcStatistics.hpp b/include/xo/alloc/GcStatistics.hpp new file mode 100644 index 00000000..01cfc80b --- /dev/null +++ b/include/xo/alloc/GcStatistics.hpp @@ -0,0 +1,161 @@ +/* GcStatistics.hpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#pragma once + +#include "generation.hpp" +#include "xo/indentlog/print/pretty.hpp" +#include +#include + +namespace xo { + namespace gc { + /** @class ObjectStatistics + * @brief placeholder for type-driven allocation statistics + * + * Passed to @ref Object::deep_move for example + **/ + class ObjectStatistics { + }; + + /** @class PerGenerationStatistics + * @brief garbage collection statistics for particular GC generation + **/ + class PerGenerationStatistics { + public: + /** update statistics after a GC cycle + * @param alloc_z. new allocations (since preceding GC) + * @param before_z. generation size (bytes allocated) before collection + * @param after_z. generation size after collection + * @param promote_z. bytes promoted to next generation + **/ + void include_gc(std::size_t alloc_z, std::size_t before_z, std::size_t after_z, + std::size_t promote_z); + /** update with current state (use at end of gc cycle) **/ + void update_snapshot(std::size_t after_z); + + /** @param os. write stats on this output stream **/ + void display(std::ostream & os) const; + + /** number of bytes currently in use **/ + std::size_t used_z_ = 0; + + /** number of collection cycles completed **/ + std::size_t n_gc_ = 0; + /** sum of new alloc bytes, sampled at start of each collection cycle **/ + std::size_t new_alloc_z_ = 0; + /** sum of allocated bytes sampled at beginning of each collection cycle **/ + std::size_t scanned_z_ = 0; + /** sum of bytes remaining after collection cycle **/ + std::size_t survive_z_ = 0; + /** sum of bytes promoted to next generation **/ + std::size_t promote_z_ = 0; + }; + + inline std::ostream & operator<< (std::ostream & os, const PerGenerationStatistics & x) { + x.display(os); + return os; + } + + /** @class GcStatistics + * @brief garbage collection statistics + **/ + class GcStatistics { + public: + /** update statistics after a GC cycle + * @param upto. nursery -> incremental collection; tenured -> full collection + * @param alloc_z. new allocations (since preceding GC) + * @param before_z. generation size (bytes allocated) before collection + * @param after_z. generation size after collection + * @param promote_z. bytes promoted to next generation + **/ + void include_gc(generation upto, std::size_t alloc_z, + std::size_t before_z, std::size_t after_z, std::size_t promote_z); + /** update snapshot for current state. + * Use with tenured stats after incremental gc + **/ + void update_snapshot(generation upto, std::size_t after_z); + + /** @param os. write stats on this output stream **/ + void display(std::ostream & os) const; + + /** statistics gathered across {incr, full} GCs respectively **/ + std::array(generation::N)> gen_v_; + /** total bytes allocated since inception **/ + std::size_t total_allocated_ = 0; + /** snapshot of total bytes promoted asof beginning of last gc cycle **/ + std::size_t total_promoted_sab_ = 0; + /** total bytes promoted from nursery->tenured since inception **/ + std::size_t total_promoted_ = 0; + + /** total number of mutations to already-allocated objects, + * whether or not GC needs to log them. + **/ + std::size_t n_mutation_ = 0; + /** total number of mutation eligible for logging (cumulative across GCs) **/ + std::size_t n_logged_mutation_ = 0; + /** total number of cross-generation mutations + * (tenured->nursery when reported; cumulative across GCs) **/ + std::size_t n_xgen_mutation_ = 0; + /** total number of cross-checkpoint mutations + * (N0 -> N1 when reported; cumulative across GCs) + **/ + std::size_t n_xckp_mutation_ = 0; + + /** per-type statistics (placeholder) **/ + ObjectStatistics per_type_stats_; + }; + + inline std::ostream & operator<< (std::ostream & os, const GcStatistics & x) { + x.display(os); + return os; + } + + /** @class GcStatisticsExt + * @brief extend GcStatistics for application convenience + **/ + class GcStatisticsExt : public GcStatistics { + public: + explicit GcStatisticsExt(const GcStatistics & x) : GcStatistics{x} {} + + /** @param os. write stats on this output stream **/ + void display(std::ostream & os) const; + + /** current capacity of nursery generation **/ + std::size_t nursery_z_ = 0; + /** current nursery survivor size **/ + std::size_t nursery_before_checkpoint_z_ = 0; + /** current nursery new alloc size **/ + std::size_t nursery_after_checkpoint_z_ = 0; + /** current capacity of tenured generation **/ + std::size_t tenured_z_ = 0; + }; + + inline std::ostream & operator<< (std::ostream & os, const GcStatisticsExt & x) { + x.display(os); + return os; + } + + } /*namespace gc*/ + + namespace print { + template <> + struct ppdetail { + static bool print_pretty(const ppindentinfo &, const xo::gc::PerGenerationStatistics &); + }; + + template<> + struct ppdetail { + static bool print_pretty(const ppindentinfo &, const xo::gc::GcStatistics &); + }; + + template<> + struct ppdetail { + static bool print_pretty(const ppindentinfo &, const xo::gc::GcStatisticsExt &); + }; + } /*namespace print*/ +} /*namespace xo*/ + +/* end GcStatistics.hpp */ diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index f8e45e84..347b5018 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -5,6 +5,7 @@ #pragma once +#include "xo/reflect/SelfTagging.hpp" #include "IAlloc.hpp" #include #include diff --git a/include/xo/alloc/generation.hpp b/include/xo/alloc/generation.hpp new file mode 100644 index 00000000..6a5a7c2e --- /dev/null +++ b/include/xo/alloc/generation.hpp @@ -0,0 +1,26 @@ +/* generation.hpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include + +namespace xo { + namespace gc { + enum class generation { + nursery, + tenured, + N + }; + + constexpr std::size_t gen2int(generation x) { return static_cast(x); } + + enum class generation_result { + nursery, + tenured, + not_found + }; + } /*namespace gc*/ +} /*namespace xo*/ + +/* end generation.hpp */ diff --git a/src/alloc/CMakeLists.txt b/src/alloc/CMakeLists.txt index bc0f919f..180b936f 100644 --- a/src/alloc/CMakeLists.txt +++ b/src/alloc/CMakeLists.txt @@ -6,11 +6,12 @@ set(SELF_SRCS ArenaAlloc.cpp ListAlloc.cpp GC.cpp + GcStatistics.cpp Object.cpp Forwarding1.cpp ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) -xo_dependency(${SELF_LIB} indentlog) +xo_dependency(${SELF_LIB} reflect) #end CMakeLists.txt diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 4f106779..d3b3c978 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -3,6 +3,7 @@ * author: Roland Conybeare, Jul 2025 */ +#include "GcStatistics.hpp" #include "GC.hpp" #include "Object.hpp" #include "xo/indentlog/scope.hpp" @@ -67,6 +68,31 @@ namespace xo { os << ""; + } + + void + GcStatisticsExt::display(std::ostream & os) const + { + os << ""; } @@ -228,6 +254,18 @@ namespace xo { return config_.debug_flag_; } + GcStatisticsExt + GC::get_gc_statistics() const + { + GcStatisticsExt retval = GcStatisticsExt(this->native_gc_statistics()); + + retval.nursery_z_ = nursery_[role2int(role::to_space)]->size(); + retval.nursery_before_checkpoint_z_ = nursery_[role2int(role::to_space)]->before_checkpoint(); + retval.tenured_z_ = tenured_[role2int(role::to_space)]->size(); + + return retval; + } + generation_result GC::fromspace_generation_of(const void * x) const { diff --git a/src/alloc/GcStatistics.cpp b/src/alloc/GcStatistics.cpp new file mode 100644 index 00000000..b78b693b --- /dev/null +++ b/src/alloc/GcStatistics.cpp @@ -0,0 +1,68 @@ +/* GcStatistics.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "GcStatistics.hpp" +#include "xo/indentlog/print/pretty_vector.hpp" + +namespace xo { + namespace print { + bool + ppdetail::print_pretty(const ppindentinfo & ppii, + const xo::gc::PerGenerationStatistics & x) + { + return ppii.pps()->pretty_struct(ppii, + "PerGenerationStatistics", + refrtag("used_z", x.used_z_), + refrtag("n_gc", x.n_gc_), + refrtag("new_alloc_z", x.new_alloc_z_), + refrtag("scanned_z", x.scanned_z_), + refrtag("survive_z", x.survive_z_), + refrtag("promote_z", x.promote_z_) + ); + } + + bool + ppdetail::print_pretty(const ppindentinfo & ppii, + const xo::gc::GcStatistics & x) + { + return ppii.pps()->pretty_struct(ppii, + "GcStatistics", + refrtag("gen_v", x.gen_v_), + refrtag("total_allocated", x.total_allocated_), + refrtag("total_promoted_sab", x.total_promoted_sab_), + refrtag("total_promoted", x.total_promoted_), + refrtag("n_mutation", x.n_mutation_), + refrtag("n_logged_mutation", x.n_logged_mutation_), + refrtag("n_xgen_mutation", x.n_xgen_mutation_), + refrtag("n_xckp_mutation", x.n_xckp_mutation_) + ); + } + + + bool + ppdetail::print_pretty(const ppindentinfo & ppii, + const xo::gc::GcStatisticsExt & x) + { + return ppii.pps()->pretty_struct(ppii, + "GcStatisticsExt", + refrtag("gen_v", x.gen_v_), + refrtag("total_allocated", x.total_allocated_), + refrtag("total_promoted_sab", x.total_promoted_sab_), + refrtag("total_promoted", x.total_promoted_), + refrtag("n_mutation", x.n_mutation_), + refrtag("n_logged_mutation", x.n_logged_mutation_), + refrtag("n_xgen_mutation", x.n_xgen_mutation_), + refrtag("n_xckp_mutation", x.n_xckp_mutation_), + refrtag("nursery_z", x.nursery_z_), + refrtag("nursery_before_checkpoint_z", x.nursery_before_checkpoint_z_), + refrtag("nursery_after_checkpoint_z", x.nursery_after_checkpoint_z_), + refrtag("tenured_z", x.tenured_z_)); + } + + + } /*namespace print*/ +} /*namespace xo*/ + +/* end GcStatistics.cpp */ diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp index 12445624..c36deb2e 100644 --- a/utest/GC.test.cpp +++ b/utest/GC.test.cpp @@ -47,22 +47,22 @@ namespace xo { REQUIRE(gc->gc_in_progress() == false); REQUIRE(gc->is_gc_enabled() == true); - REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 0); - REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 0); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0); /* gc with empty state */ gc->request_gc(generation::nursery); REQUIRE(gc->gc_in_progress() == false); - REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); - REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0); /* still empty state */ gc->request_gc(generation::tenured); REQUIRE(gc->gc_in_progress() == false); - REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); - REQUIRE(gc->gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 1); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 1); } } From 227b2e5cf7155a10276a8e3b31767b36d130d518 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 6 Aug 2025 14:11:28 -0500 Subject: [PATCH 007/342] xo-alloc xo-object: + Object.self_tp --- include/xo/alloc/Forwarding1.hpp | 1 + include/xo/alloc/Object.hpp | 11 ++++++++++- src/alloc/Forwarding1.cpp | 10 ++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/xo/alloc/Forwarding1.hpp b/include/xo/alloc/Forwarding1.hpp index 4fb61d08..17a38df2 100644 --- a/include/xo/alloc/Forwarding1.hpp +++ b/include/xo/alloc/Forwarding1.hpp @@ -12,6 +12,7 @@ namespace xo { explicit Forwarding1(gp dest); // inherited from Object.. + virtual TaggedPtr self_tp() const final override; virtual bool _is_forwarded() const final override { return true; } virtual Object * _offset_destination(Object * src) const final override; virtual Object * _destination() final override; diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 347b5018..47b26261 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -5,7 +5,7 @@ #pragma once -#include "xo/reflect/SelfTagging.hpp" +#include "xo/reflect/TaggedPtr.hpp" #include "IAlloc.hpp" #include #include @@ -79,6 +79,9 @@ namespace xo { * but cost would be an extra layer of indirection **/ class Object { + public: + using TaggedPtr = xo::reflect::TaggedPtr; + public: virtual ~Object() = default; @@ -148,6 +151,12 @@ namespace xo { **/ static Object * _shallow_move(Object * src, gc::GC * gc); + // Reflection support + + /** tagged pointer with runtime type information + **/ + virtual TaggedPtr self_tp() const = 0; + // GC support /** true iff this object represents a forwarding pointer. diff --git a/src/alloc/Forwarding1.cpp b/src/alloc/Forwarding1.cpp index 32d95b60..2122d248 100644 --- a/src/alloc/Forwarding1.cpp +++ b/src/alloc/Forwarding1.cpp @@ -4,15 +4,25 @@ */ #include "Forwarding1.hpp" +#include "xo/reflect/Reflect.hpp" #include #include namespace xo { + using xo::reflect::Reflect; + using xo::reflect::TaggedPtr; + namespace obj { Forwarding1::Forwarding1(gp dest) : dest_{dest} {} + TaggedPtr + Forwarding1::self_tp() const + { + return Reflect::make_tp(const_cast(this)); + } + Object * Forwarding1::_offset_destination(Object * src) const { From 593dc064f9e8fb8c439d0c872314de3482a10f18 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 6 Aug 2025 22:34:20 -0500 Subject: [PATCH 008/342] xo-allod: + per-type stats + pretty printing --- include/xo/alloc/ArenaAlloc.hpp | 4 + include/xo/alloc/Forwarding1.hpp | 1 + include/xo/alloc/GC.hpp | 8 ++ include/xo/alloc/GcStatistics.hpp | 12 +-- include/xo/alloc/ListAlloc.hpp | 9 ++ include/xo/alloc/Object.hpp | 6 ++ include/xo/alloc/ObjectStatistics.hpp | 86 +++++++++++++++++ src/alloc/ArenaAlloc.cpp | 39 ++++++++ src/alloc/CMakeLists.txt | 1 + src/alloc/Forwarding1.cpp | 6 ++ src/alloc/GC.cpp | 128 +++++++------------------- src/alloc/GcStatistics.cpp | 87 +++++++++++++++++ src/alloc/ListAlloc.cpp | 11 +++ src/alloc/Object.cpp | 12 +++ src/alloc/ObjectStatistics.cpp | 73 +++++++++++++++ utest/LinearAlloc.test.cpp | 87 ----------------- 16 files changed, 379 insertions(+), 191 deletions(-) create mode 100644 include/xo/alloc/ObjectStatistics.hpp create mode 100644 src/alloc/ObjectStatistics.cpp delete mode 100644 utest/LinearAlloc.test.cpp diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 12033646..9f41a8f1 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -6,6 +6,7 @@ #pragma once #include "IAlloc.hpp" +#include "ObjectStatistics.hpp" namespace xo { namespace gc { @@ -48,6 +49,9 @@ namespace xo { std::byte * free_ptr() const { return free_ptr_; } void set_free_ptr(std::byte * x); + void capture_object_statistics(capture_phase phase, + ObjectStatistics * p_dest) const; + // inherited from IAlloc... virtual const std::string & name() const final override { return name_; } diff --git a/include/xo/alloc/Forwarding1.hpp b/include/xo/alloc/Forwarding1.hpp index 17a38df2..cf54597d 100644 --- a/include/xo/alloc/Forwarding1.hpp +++ b/include/xo/alloc/Forwarding1.hpp @@ -13,6 +13,7 @@ namespace xo { // inherited from Object.. virtual TaggedPtr self_tp() const final override; + virtual void display(std::ostream & os) const final override; virtual bool _is_forwarded() const final override { return true; } virtual Object * _offset_destination(Object * src) const final override; virtual Object * _destination() final override; diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 4fb9f518..daef1881 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -42,6 +42,8 @@ namespace xo { std::size_t initial_tenured_z_ = 0; /** true to permit incremental garbage collection **/ bool allow_incremental_gc_ = true; + /** true to report statistics **/ + bool stats_flag_ = false; /** true to enable debug logging **/ bool debug_flag_ = false; }; @@ -207,6 +209,8 @@ namespace xo { void swap_mutation_log(); /** swap roles of FromSpace/ToSpace **/ void swap_spaces(generation g); + /** scan to-space for object statistics before GC */ + void capture_object_statistics(generation upto, capture_phase phase); /** copy object **/ void copy_object(Object ** addr, generation upto, ObjectStatistics * object_stats); /** copy everything reachable from global gc roots **/ @@ -273,6 +277,10 @@ namespace xo { /** allocation/collection counters **/ GcStatistics gc_statistics_; + /** optional per-object-type counters. snapshot at beginning of collection cycle **/ + std::array object_statistics_sab_; + /** optional per-object-type counters. snapshot at end of collection cycle **/ + std::array object_statistics_sae_; /** trigger full GC whenever this much data arrives in tenured generation **/ std::size_t full_gc_threshold_ = 0; diff --git a/include/xo/alloc/GcStatistics.hpp b/include/xo/alloc/GcStatistics.hpp index 01cfc80b..24cac461 100644 --- a/include/xo/alloc/GcStatistics.hpp +++ b/include/xo/alloc/GcStatistics.hpp @@ -6,20 +6,13 @@ #pragma once #include "generation.hpp" +#include "xo/reflect/TypeDescr.hpp" #include "xo/indentlog/print/pretty.hpp" #include #include namespace xo { namespace gc { - /** @class ObjectStatistics - * @brief placeholder for type-driven allocation statistics - * - * Passed to @ref Object::deep_move for example - **/ - class ObjectStatistics { - }; - /** @class PerGenerationStatistics * @brief garbage collection statistics for particular GC generation **/ @@ -103,9 +96,6 @@ namespace xo { * (N0 -> N1 when reported; cumulative across GCs) **/ std::size_t n_xckp_mutation_ = 0; - - /** per-type statistics (placeholder) **/ - ObjectStatistics per_type_stats_; }; inline std::ostream & operator<< (std::ostream & os, const GcStatistics & x) { diff --git a/include/xo/alloc/ListAlloc.hpp b/include/xo/alloc/ListAlloc.hpp index db1a2df7..f9c20d00 100644 --- a/include/xo/alloc/ListAlloc.hpp +++ b/include/xo/alloc/ListAlloc.hpp @@ -6,6 +6,7 @@ #pragma once #include "IAlloc.hpp" +#include "ObjectStatistics.hpp" #include #include #include @@ -43,6 +44,14 @@ namespace xo { /** current free pointer **/ std::byte * free_ptr() const; + /** scan space (must not contain forwarding pointers, because loses size info) + * + gather stats by object type + * + * See @ref Object::self_tp + **/ + void capture_object_statistics(capture_phase phase, + ObjectStatistics * p_dest) const; + // inherited from IAlloc.. virtual const std::string & name() const final override; diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 47b26261..0f50bfed 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -157,6 +157,9 @@ namespace xo { **/ virtual TaggedPtr self_tp() const = 0; + /** print on stream @p os **/ + virtual void display(std::ostream & os) const = 0; + // GC support /** true iff this object represents a forwarding pointer. @@ -244,6 +247,9 @@ namespace xo { rhs.ptr()); } + std::ostream & + operator<< (std::ostream & os, gp x); + /** @class Cpof * @brief argument to operator new used for garbage collector evacuation phase * diff --git a/include/xo/alloc/ObjectStatistics.hpp b/include/xo/alloc/ObjectStatistics.hpp new file mode 100644 index 00000000..ced3b463 --- /dev/null +++ b/include/xo/alloc/ObjectStatistics.hpp @@ -0,0 +1,86 @@ +/* file ObjectStatistics.hpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#pragma once + +#include "xo/indentlog/print/pretty.hpp" +#include +#include + +namespace xo { + namespace reflect { class TypeDescrBase; } + + namespace gc { + enum class capture_phase { + /** snapshot-at-beginning **/ + sab, + /** snapshot-at-end **/ + sae, + }; + + /** @class PerObjectTypeStatistics + * @brief statistics for a particular object type + * + * Gathered for each leaf type descended from xo::obj::Object. + * See @ref xo::obj::Object::self_tp + * + * See @ref GC::capture_object_statistics + * (gathers @ref scanned_n_, @ref scanned_z_) + **/ + struct PerObjectTypeStatistics { + using TypeDescr = xo::reflect::TypeDescrBase const *; + + void display(std::ostream & os) const; + + /** stats here are for objects of this type **/ + TypeDescr td_ = nullptr; + /** number of objects scanned **/ + std::size_t scanned_n_ = 0; + /** number of bytes scanned **/ + std::size_t scanned_z_ = 0; + /** number of objects surviving **/ + std::size_t survive_n_ = 0; + /** number of bytes from surviving objects **/ + std::size_t survive_z_ = 0; + }; + + inline std::ostream & operator<< (std::ostream & os, const PerObjectTypeStatistics & x) { + x.display(os); + return os; + } + + /** @class ObjectStatistics + * @brief placeholder for type-driven allocation statistics + * + * Passed to @ref Object::deep_move for example + **/ + struct ObjectStatistics { + void display(std::ostream & os) const; + + /** per-object-type statistics, indexed by TypeId **/ + std::vector per_type_stats_v_; + }; + + inline std::ostream & operator<< (std::ostream & os, const ObjectStatistics & x) { + x.display(os); + return os; + } + + } /*namespace gc*/ + + namespace print { + template <> + struct ppdetail { + static bool print_pretty(const ppindentinfo &, const xo::gc::PerObjectTypeStatistics &); + }; + + template <> + struct ppdetail { + static bool print_pretty(const ppindentinfo &, const xo::gc::ObjectStatistics &); + }; + } /*namespace print*/ +} /*namespace xo*/ + +/* end ObjectStatistics.hpp */ diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index c3f70d8c..ae67365a 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -4,6 +4,8 @@ */ #include "ArenaAlloc.hpp" +#include "Object.hpp" +#include "ObjectStatistics.hpp" #include "xo/indentlog/scope.hpp" #include "xo/indentlog/print/tag.hpp" #include @@ -64,6 +66,43 @@ namespace xo { } } + void + ArenaAlloc::capture_object_statistics(capture_phase phase, + ObjectStatistics * p_dest) const + { + using xo::reflect::TaggedPtr; + + std::byte * p = lo_; + + while (p < free_ptr_) { + Object * obj = reinterpret_cast(p); + TaggedPtr tp = obj->self_tp(); + std::size_t z = obj->_shallow_size(); + std::uint32_t id = tp.td()->id().id(); + + if (p_dest->per_type_stats_v_.size() < id + 1) + p_dest->per_type_stats_v_.resize(id + 1); + + PerObjectTypeStatistics & dest = p_dest->per_type_stats_v_.at(id); + + dest.td_ = tp.td(); + switch (phase) { + case capture_phase::sab: + ++dest.scanned_n_; + dest.scanned_z_ += z; + break; + case capture_phase::sae: + ++dest.survive_n_; + dest.survive_z_ += z; + break; + } + + p += z; + } + + assert(p == free_ptr_); + } + std::size_t ArenaAlloc::size() const { return limit_ - lo_; diff --git a/src/alloc/CMakeLists.txt b/src/alloc/CMakeLists.txt index 180b936f..55b8641c 100644 --- a/src/alloc/CMakeLists.txt +++ b/src/alloc/CMakeLists.txt @@ -7,6 +7,7 @@ set(SELF_SRCS ListAlloc.cpp GC.cpp GcStatistics.cpp + ObjectStatistics.cpp Object.cpp Forwarding1.cpp ) diff --git a/src/alloc/Forwarding1.cpp b/src/alloc/Forwarding1.cpp index 2122d248..5a941c82 100644 --- a/src/alloc/Forwarding1.cpp +++ b/src/alloc/Forwarding1.cpp @@ -23,6 +23,12 @@ namespace xo { return Reflect::make_tp(const_cast(this)); } + void + Forwarding1::display(std::ostream & os) const + { + os << ""; + } + Object * Forwarding1::_offset_destination(Object * src) const { diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index d3b3c978..afac26df 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -12,91 +12,6 @@ namespace xo { namespace gc { - void - PerGenerationStatistics::include_gc(std::size_t alloc_z, - std::size_t before_z, - std::size_t after_z, - std::size_t promote_z) - { - this->update_snapshot(after_z); - - new_alloc_z_ += alloc_z; - scanned_z_ += before_z; - survive_z_ += after_z; - promote_z_ += promote_z; - } - - void - PerGenerationStatistics::update_snapshot(std::size_t after_z) - { - used_z_ = after_z; - } - - void - PerGenerationStatistics::display(std::ostream & os) const - { - os << ""; - } - - void - GcStatistics::include_gc(generation upto, - std::size_t alloc_z, - std::size_t before_z, - std::size_t after_z, - std::size_t promote_z) - { - gen_v_[static_cast(upto)].include_gc(alloc_z, before_z, after_z, promote_z); - } - - void - GcStatistics::update_snapshot(generation upto, - std::size_t after_z) - { - gen_v_[static_cast(upto)].update_snapshot(after_z); - } - - void - GcStatistics::display(std::ostream & os) const - { - os << ""; - } - - void - GcStatisticsExt::display(std::ostream & os) const - { - os << ""; - } - bool MutationLogEntry::is_child_forwarded() const { @@ -542,6 +457,22 @@ namespace xo { } /*swap_spaces*/ + void + GC::capture_object_statistics(generation upto, capture_phase phase) + { + /* scan nursery */ + this->nursery_[role2int(role::to_space)]->capture_object_statistics + (phase, + &object_statistics_sab_[gen2int(generation::nursery)]); + + if (upto == generation::tenured) { + /* scan tenured */ + this->tenured_[role2int(role::to_space)]->capture_object_statistics + (phase, + &object_statistics_sab_[gen2int(generation::tenured)]); + } + } + void GC::copy_object(Object ** pp_object, generation upto, ObjectStatistics * object_stats) { @@ -566,7 +497,7 @@ namespace xo { GC::copy_globals(generation upto) { for (Object ** pp_root : gc_root_v_) { - this->copy_object(pp_root, upto, &gc_statistics_.per_type_stats_); + this->copy_object(pp_root, upto, &object_statistics_sae_[gen2int(upto)]); } } @@ -802,7 +733,7 @@ namespace xo { if (upto == generation::tenured) { log && log("TODO: forward mutation log for full GC"); } else { - this->incremental_gc_forward_mlog(&gc_statistics_.per_type_stats_); + this->incremental_gc_forward_mlog(&object_statistics_sae_[gen2int(generation::nursery)]); } } @@ -858,7 +789,7 @@ namespace xo { void GC::execute_gc(generation upto) { - scope log(XO_DEBUG(config_.debug_flag_)); + scope log(XO_DEBUG(config_.stats_flag_)); bool full_move = (upto == generation::tenured); @@ -876,7 +807,11 @@ namespace xo { log && log(xtag("new_alloc", new_alloc)); - log && log("step 1: swap to/from roles"); + log && log("step 0: (optional) scan for object statistics"); + + this->capture_object_statistics(upto, capture_phase::sab); + + log && log("step 1 : swap to/from roles"); this->swap_spaces(upto); @@ -886,18 +821,25 @@ namespace xo { log && log("step 2b: TODO: copy pinned"); - log && log("step 3: forward mutation log"); + log && log("step 3 : forward mutation log"); this->forward_mutation_log(upto); - log && log("step 4: TODO: notify destructor log"); + log && log("step 4 : TODO: notify destructor log"); - log && log("step 5: TODO: keep reachable weak pointers"); + log && log("step 5 : TODO: keep reachable weak pointers"); - log && log("step 6: cleanup"); + log && log("step 6 : cleanup"); this->cleanup_phase(upto); + this->capture_object_statistics(upto, capture_phase::sae); + + log && log("object statistics [nursery]:"); + log && log(refrtag("stats", object_statistics_sab_[gen2int(generation::nursery)])); + log && log("object statistics [tenured]:"); + log && log(refrtag("stats", object_statistics_sab_[gen2int(generation::tenured)])); + this->runstate_ = GCRunstate(); log && log("statistics:"); diff --git a/src/alloc/GcStatistics.cpp b/src/alloc/GcStatistics.cpp index b78b693b..d54c3cf2 100644 --- a/src/alloc/GcStatistics.cpp +++ b/src/alloc/GcStatistics.cpp @@ -7,6 +7,93 @@ #include "xo/indentlog/print/pretty_vector.hpp" namespace xo { + namespace gc { + void + PerGenerationStatistics::include_gc(std::size_t alloc_z, + std::size_t before_z, + std::size_t after_z, + std::size_t promote_z) + { + this->update_snapshot(after_z); + + new_alloc_z_ += alloc_z; + scanned_z_ += before_z; + survive_z_ += after_z; + promote_z_ += promote_z; + } + + void + PerGenerationStatistics::update_snapshot(std::size_t after_z) + { + used_z_ = after_z; + } + + void + PerGenerationStatistics::display(std::ostream & os) const + { + os << ""; + } + + void + GcStatistics::include_gc(generation upto, + std::size_t alloc_z, + std::size_t before_z, + std::size_t after_z, + std::size_t promote_z) + { + gen_v_[static_cast(upto)].include_gc(alloc_z, before_z, after_z, promote_z); + } + + void + GcStatistics::update_snapshot(generation upto, + std::size_t after_z) + { + gen_v_[static_cast(upto)].update_snapshot(after_z); + } + + void + GcStatistics::display(std::ostream & os) const + { + os << ""; + } + + void + GcStatisticsExt::display(std::ostream & os) const + { + os << ""; + } + } /*namespace gc*/ + namespace print { bool ppdetail::print_pretty(const ppindentinfo & ppii, diff --git a/src/alloc/ListAlloc.cpp b/src/alloc/ListAlloc.cpp index a5ae38e7..9d727591 100644 --- a/src/alloc/ListAlloc.cpp +++ b/src/alloc/ListAlloc.cpp @@ -50,6 +50,17 @@ namespace xo { return retval; } + void + ListAlloc::capture_object_statistics(capture_phase phase, + ObjectStatistics * p_dest) const + { + hd_->capture_object_statistics(phase, p_dest); + + for (const auto & arena : full_l_) + arena->capture_object_statistics(phase, p_dest); + + } + const std::string & ListAlloc::name() const { if (hd_) { diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index d3772003..b3db11ca 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -191,6 +191,18 @@ namespace xo { (void)fwd; } + std::ostream & + operator<< (std::ostream & os, gp x) + { + if (x.ptr()) { + x->display(os); + } else { + os << ""; + } + + return os; + } + } /*namespace xo*/ /* end Object.cpp*/ diff --git a/src/alloc/ObjectStatistics.cpp b/src/alloc/ObjectStatistics.cpp new file mode 100644 index 00000000..a69928dc --- /dev/null +++ b/src/alloc/ObjectStatistics.cpp @@ -0,0 +1,73 @@ +/* file ObjectStatistics.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "ObjectStatistics.hpp" +#include "xo/reflect/TypeDescr.hpp" +#include "xo/indentlog/print/pretty_vector.hpp" + +namespace xo { + namespace gc { + void + PerObjectTypeStatistics::display(std::ostream & os) const + { + os << "short_name()); + else + os << rtag("td", "nullptr"); + os << rtag("scanned_n", scanned_n_) + << rtag("scanned_z", scanned_z_) + << rtag("survive_n", survive_n_) + << rtag("survive_z", survive_z_) + << ">"; + } + + void + ObjectStatistics::display(std::ostream & os) const + { + os << ""; + } + } /*namespace gc*/ + + namespace print { + bool + ppdetail::print_pretty(const ppindentinfo & ppii, + const xo::gc::PerObjectTypeStatistics & x) + { + static constexpr std::string_view c_nullptr_str = "nullptr"; + + if (x.td_) { + return ppii.pps()->pretty_struct(ppii, + "PerObjectTypeStatistics", + refrtag("td", x.td_ ? x.td_->short_name() : c_nullptr_str), + refrtag("scanned_n", x.scanned_n_), + refrtag("scanned_z", x.scanned_z_), + refrtag("survive_n", x.survive_n_), + refrtag("survive_z", x.survive_z_)); + } else { + /* print nothing -- empty struct */ + return true; + } + } + + bool + ppdetail::print_pretty(const ppindentinfo & ppii, + const xo::gc::ObjectStatistics & x) + { + return ppii.pps()->pretty_struct(ppii, + "ObjectTypeStatistics", + refrtag("per_type_stats_v", x.per_type_stats_v_)); + } + } /*namespace gc*/ +} /*namespace xo*/ + +/* end ObjectStatistics.cpp */ diff --git a/utest/LinearAlloc.test.cpp b/utest/LinearAlloc.test.cpp deleted file mode 100644 index b1909991..00000000 --- a/utest/LinearAlloc.test.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* @file LinearAlloc.test.cpp - * - * author: Roland Conybeare, Jul 2025 - */ - -#include "xo/alloc/ArenaAlloc.hpp" -#include - -namespace xo { - using xo::gc::LinearAlloc; - - namespace ut { - - namespace { - struct testcase_alloc { - testcase_alloc(std::size_t rz, std::size_t z) - : redline_z_{rz}, arena_z_{z} {} - - std::size_t redline_z_; - std::size_t arena_z_; - - }; - - std::vector - s_testcase_v = { - testcase_alloc(0, 4096) - }; - } - - - TEST_CASE("linearalloc", "[alloc]") - { - for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { - const testcase_alloc & tc = s_testcase_v[i_tc]; - - constexpr bool c_debug_flag = false; - - auto alloc = LinearAlloc::make("linearalloc", tc.redline_z_, tc.arena_z_, c_debug_flag); - - REQUIRE(alloc.get()); - REQUIRE(alloc->name() == "linearalloc"); - REQUIRE(alloc->size() == tc.arena_z_); - REQUIRE(alloc->available() == tc.arena_z_); - REQUIRE(alloc->allocated() == 0); - REQUIRE(alloc->is_before_checkpoint(alloc->free_ptr()) == false); - REQUIRE(alloc->before_checkpoint() == 0); - REQUIRE(alloc->after_checkpoint() == 0); - - auto free0 = alloc->free_ptr(); - - auto mem = alloc->alloc(tc.arena_z_); - - REQUIRE(mem != nullptr); - - REQUIRE(mem == free0); - - REQUIRE(alloc->size() == tc.arena_z_); - REQUIRE(alloc->available() == 0); - REQUIRE(alloc->allocated() == tc.arena_z_); - REQUIRE(alloc->is_before_checkpoint(mem) == false); - REQUIRE(alloc->before_checkpoint() == 0); - REQUIRE(alloc->after_checkpoint() == tc.arena_z_); - - alloc->clear(); - - REQUIRE(alloc->free_ptr() == free0); - REQUIRE(alloc->available() == tc.arena_z_); - REQUIRE(alloc->allocated() == 0); - REQUIRE(alloc->is_before_checkpoint(free0) == false); - REQUIRE(alloc->before_checkpoint() == 0); - REQUIRE(alloc->after_checkpoint() == 0); - - mem = alloc->alloc(1); - - auto used = sizeof(void*); - REQUIRE(alloc->size() == tc.arena_z_); - REQUIRE(alloc->available() == tc.arena_z_ - used); - REQUIRE(alloc->allocated() == used); - REQUIRE(alloc->is_before_checkpoint(free0) == false); - REQUIRE(alloc->before_checkpoint() == 0); - REQUIRE(alloc->after_checkpoint() == used); - - } - } - - } /*namespace ut */ -} /*namespace xo*/ From 8b622e69995fb58f40d38931412fb4332e102b01 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 6 Aug 2025 22:50:29 -0500 Subject: [PATCH 009/342] xo-alloc: retire redline-memory feature --- include/xo/alloc/ArenaAlloc.hpp | 12 +++++++++- include/xo/alloc/GC.hpp | 2 ++ include/xo/alloc/IAlloc.hpp | 2 ++ include/xo/alloc/ListAlloc.hpp | 13 +++++++++-- src/alloc/ArenaAlloc.cpp | 39 ++++++++++++++++++++++++++++++--- src/alloc/GC.cpp | 8 +++++++ src/alloc/ListAlloc.cpp | 26 ++++++++++++++++++++-- utest/ArenaAlloc.test.cpp | 14 ++++++++++-- 8 files changed, 106 insertions(+), 10 deletions(-) diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 9f41a8f1..51b72c9e 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -42,7 +42,9 @@ namespace xo { * with reserved capacity @p redline_z. **/ static up make(const std::string & name, +#ifdef REDLINE_MEMORY std::size_t redline_z, +#endif std::size_t z, bool debug_flag); @@ -66,10 +68,16 @@ namespace xo { virtual void clear() final override; virtual void checkpoint() final override; virtual std::byte * alloc(std::size_t z) final override; +#ifdef REDLINE_MEMORY virtual void release_redline_memory() final override; +#endif private: - ArenaAlloc(const std::string & name, std::size_t rz, std::size_t z, bool debug_flag); + ArenaAlloc(const std::string & name, +#ifdef REDLINE_MEMORY + std::size_t rz, +#endif + std::size_t z, bool debug_flag); private: /** @@ -91,8 +99,10 @@ namespace xo { std::byte * free_ptr_ = nullptr; /** soft limit: end of released memory **/ std::byte * limit_ = nullptr; +#ifdef REDLINE_MEMORY /** amount of last-resort memory to reserve **/ std::size_t redline_z_ = 0; +#endif /** hard limit: end of allocated memory **/ std::byte * hi_ = nullptr; /** true to enable detailed debug logging **/ diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index daef1881..679e5286 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -194,7 +194,9 @@ namespace xo { virtual std::byte * alloc(std::size_t z) final override; virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; +#ifdef REDLINE_MEMORY virtual void release_redline_memory() final override; +#endif private: /** begin GC now **/ diff --git a/include/xo/alloc/IAlloc.hpp b/include/xo/alloc/IAlloc.hpp index 272fe9ad..2eacd9cc 100644 --- a/include/xo/alloc/IAlloc.hpp +++ b/include/xo/alloc/IAlloc.hpp @@ -76,8 +76,10 @@ namespace xo { * Only used in @ref GC. Default implementation asserts and returns nullptr **/ virtual std::byte * alloc_gc_copy(std::size_t z, const void * src); +#ifdef REDLINE_MEMORY /** release last-resort reserved memory **/ virtual void release_redline_memory() = 0; +#endif }; } /*namespace gc*/ diff --git a/include/xo/alloc/ListAlloc.hpp b/include/xo/alloc/ListAlloc.hpp index f9c20d00..627bbf50 100644 --- a/include/xo/alloc/ListAlloc.hpp +++ b/include/xo/alloc/ListAlloc.hpp @@ -29,7 +29,9 @@ namespace xo { ListAlloc(std::unique_ptr hd, ArenaAlloc * marked, std::size_t cz, std::size_t nz, std::size_t tz, +#ifdef REDLINE_MEMORY bool use_redline, +#endif bool debug_flag); ~ListAlloc(); @@ -66,7 +68,9 @@ namespace xo { virtual void clear() final override; virtual void checkpoint() final override; virtual std::byte * alloc(std::size_t z) final override; +#ifdef REDLINE_MEMORY virtual void release_redline_memory() final override; +#endif private: /** **/ @@ -79,11 +83,16 @@ namespace xo { * from trying to converge on app working set size **/ std::list> full_l_; - std::size_t current_z_ = 0;; - std::size_t next_z_ = 0;; + /** size of current arena @ref hd_ **/ + std::size_t current_z_ = 0; + /** if @ref hd_ fills, size of next arena to allocate **/ + std::size_t next_z_ = 0; + /** total size of @ref hd_ + contents of @ref full_l_ **/ std::size_t total_z_ = 0; +#ifdef REDLINE_MEMORY bool use_redline_ = false; bool redlined_flag_ = false; +#endif /** true to enable debug logging **/ bool debug_flag_ = false; diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index ae67365a..94053560 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -12,20 +12,37 @@ namespace xo { namespace gc { - ArenaAlloc::ArenaAlloc(const std::string & name, std::size_t rz, std::size_t z, bool debug_flag) + ArenaAlloc::ArenaAlloc(const std::string & name, +#ifdef REDLINE_MEMORY + std::size_t rz, +#endif + std::size_t z, bool debug_flag) { this->name_ = name; +#ifdef REDLINE_MEMORY this->lo_ = (new std::byte [rz + z]); +#else + this->lo_ = (new std::byte [z]); +#endif this->checkpoint_ = lo_; this->free_ptr_ = lo_; this->limit_ = lo_ + z; +#ifdef REDLINE_MEMORY this->redline_z_ = rz; this->hi_ = limit_ + rz; +#else + this->hi_ = limit_; +#endif this->debug_flag_ = debug_flag; if (!lo_) { +#ifdef REDLINE_MEMORY throw std::runtime_error(tostr("ArenaAlloc: allocation failed", xtag("size", rz + z))); +#else + throw std::runtime_error(tostr("ArenaAlloc: allocation failed", + xtag("size", z))); +#endif } } @@ -39,15 +56,25 @@ namespace xo { this->checkpoint_ = nullptr; this->free_ptr_ = nullptr; this->limit_ = nullptr; +#ifdef REDLINE_MEMORY this->redline_z_ = 0; +#endif this->hi_ = nullptr; this->debug_flag_ = false; } up - ArenaAlloc::make(const std::string & name, std::size_t rz, std::size_t z, bool debug_flag) + ArenaAlloc::make(const std::string & name, +#ifdef REDLINE_MEMORY + std::size_t rz, +#endif + std::size_t z, bool debug_flag) { - return up(new ArenaAlloc(name, rz, z, debug_flag)); + return up(new ArenaAlloc(name, +#ifdef REDLINE_MEMORY + rz, +#endif + z, debug_flag)); } void @@ -144,7 +171,11 @@ namespace xo { ArenaAlloc::clear() { this->set_free_ptr(lo_); +#ifdef REDLINE_MEMORY this->limit_ = hi_ - redline_z_; +#else + this->limit_ = hi_; +#endif } void @@ -184,10 +215,12 @@ namespace xo { return retval; } +#ifdef REDLINE_MEMORY void ArenaAlloc::release_redline_memory() { this->limit_ = this->hi_; } +#endif } /*namespace gc*/ } /*namespace xo*/ diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index afac26df..460ac770 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -255,13 +255,17 @@ namespace xo { std::byte * x = nursery_[role2int(role::to_space)]->alloc(z); if (!x) { + /* ListAlloc won't fail -- instead will increase heap size */ + this->request_gc(generation::nursery); +#ifdef REDLINE_MEMORY if (incr_gc_pending_ || full_gc_pending_) nursery_[role2int(role::to_space)]->release_redline_memory(); /* try (just once) more, maybe request fits in redline space */ x = nursery_[role2int(role::to_space)]->alloc(z); +#endif assert(x); } @@ -310,7 +314,9 @@ namespace xo { this->request_gc(generation::nursery); +#ifdef REDLINE_MEMORY nursery_[role2int(role::to_space)]->release_redline_memory(); +#endif retval = nursery_[role2int(role::to_space)]->alloc(z); } @@ -387,11 +393,13 @@ namespace xo { } } +#ifdef REDLINE_MEMORY void GC::release_redline_memory() { // not supported feature for GC } +#endif void GC::swap_nursery() diff --git a/src/alloc/ListAlloc.cpp b/src/alloc/ListAlloc.cpp index 9d727591..1f84d5c6 100644 --- a/src/alloc/ListAlloc.cpp +++ b/src/alloc/ListAlloc.cpp @@ -13,7 +13,9 @@ namespace xo { ListAlloc::ListAlloc(std::unique_ptr hd, ArenaAlloc * marked, std::size_t cz, std::size_t nz, std::size_t tz, +#ifdef REDLINE_MEMORY bool use_redline, +#endif bool debug_flag) : start_z_{cz}, hd_{std::move(hd)}, @@ -22,7 +24,9 @@ namespace xo { current_z_{cz}, next_z_{nz}, total_z_{tz}, +#ifdef REDLINE_MEMOORY use_redline_{use_redline}, +#endif debug_flag_{debug_flag} {} @@ -34,7 +38,11 @@ namespace xo { up ListAlloc::make(const std::string & name, std::size_t cz, std::size_t nz, bool debug_flag) { - std::unique_ptr hd{ArenaAlloc::make(name, 0, cz, debug_flag)}; + std::unique_ptr hd{ArenaAlloc::make(name, +#ifdef REDLINE_MEMORY + 0, +#endif + cz, debug_flag)}; if (!hd) return nullptr; @@ -44,7 +52,9 @@ namespace xo { up retval{new ListAlloc(std::move(hd), marked, cz, nz, cz, +#ifdef REDLINE_MEMORY false /*!use_redline*/, +#endif debug_flag)}; return retval; @@ -248,20 +258,26 @@ namespace xo { current_z_ = 0; next_z_ = 0; total_z_ = 0; +#ifdef REDLINE_MEMORY use_redline_ = false; +#endif } bool ListAlloc::reset(std::size_t z) { +#ifdef REDLINE_MEMORY // warning: hd_->size() does not include redline memory hd_->release_redline_memory(); +#endif bool recycle_head_bucket = hd_ && (z <= hd_->size()); this->full_l_.clear(); this->marked_ = nullptr; +#ifdef REDLINE_MEMORY this->redlined_flag_ = false; +#endif if (recycle_head_bucket) { this->hd_->clear(); @@ -291,7 +307,11 @@ namespace xo { std::string name = hd_->name() + "+exp"; - std::unique_ptr new_alloc = ArenaAlloc::make(name, 0, cz, debug_flag_); + std::unique_ptr new_alloc = ArenaAlloc::make(name, +#ifdef REDLINE_MEMORY + 0, +#endif + cz, debug_flag_); if (!new_alloc) return false; @@ -325,6 +345,7 @@ namespace xo { return nullptr; } +#ifdef REDLINE_MEMORY void ListAlloc::release_redline_memory() { @@ -333,6 +354,7 @@ namespace xo { this->hd_->release_redline_memory(); } +#endif } /*namespace gc*/ } /*namespace xo*/ diff --git a/utest/ArenaAlloc.test.cpp b/utest/ArenaAlloc.test.cpp index aae2695b..0e4582e9 100644 --- a/utest/ArenaAlloc.test.cpp +++ b/utest/ArenaAlloc.test.cpp @@ -14,9 +14,15 @@ namespace xo { namespace { struct testcase_alloc { testcase_alloc(std::size_t rz, std::size_t z) - : redline_z_{rz}, arena_z_{z} {} + : +#ifdef REDLINE_MEMORY + redline_z_{rz}, +#endif + arena_z_{z} {} +#ifdef REDLINE_MEMORY std::size_t redline_z_; +#endif std::size_t arena_z_; }; @@ -35,7 +41,11 @@ namespace xo { constexpr bool c_debug_flag = false; - auto alloc = ArenaAlloc::make("linearalloc", tc.redline_z_, tc.arena_z_, c_debug_flag); + auto alloc = ArenaAlloc::make("linearalloc", +#ifdef REDLINE_MEMORY + tc.redline_z_, +#endif + tc.arena_z_, c_debug_flag); REQUIRE(alloc.get()); REQUIRE(alloc->name() == "linearalloc"); From a6e44308257817f6ce085e52cb7d4666365b4b9a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 7 Aug 2025 18:32:14 -0500 Subject: [PATCH 010/342] xo-alloc / xo-object: utest coverage + assorted bugfixes --- include/xo/alloc/ArenaAlloc.hpp | 29 +---- include/xo/alloc/GC.hpp | 9 ++ include/xo/alloc/IAlloc.hpp | 6 +- include/xo/alloc/ListAlloc.hpp | 16 +-- include/xo/alloc/generation.hpp | 10 ++ src/alloc/ArenaAlloc.cpp | 70 +++++------ src/alloc/CMakeLists.txt | 1 + src/alloc/Forwarding1.cpp | 2 +- src/alloc/GC.cpp | 137 ++++++++++---------- src/alloc/GcStatistics.cpp | 40 +++--- src/alloc/ListAlloc.cpp | 199 +++++++++++++++-------------- src/alloc/ObjectStatistics.cpp | 12 +- src/alloc/generation.cpp | 22 ++++ utest/ArenaAlloc.test.cpp | 9 -- utest/CMakeLists.txt | 8 +- utest/Forwarding1.test.cpp | 85 +++++++++++++ utest/GC.test.cpp | 1 + utest/GcStatistics.test.cpp | 216 ++++++++++++++++++++++++++++++++ utest/ListAlloc.test.cpp | 58 +++++++++ utest/ObjectStatistics.test.cpp | 185 +++++++++++++++++++++++++++ utest/generation.test.cpp | 38 ++++++ 21 files changed, 865 insertions(+), 288 deletions(-) create mode 100644 src/alloc/generation.cpp create mode 100644 utest/Forwarding1.test.cpp create mode 100644 utest/GcStatistics.test.cpp create mode 100644 utest/ListAlloc.test.cpp create mode 100644 utest/ObjectStatistics.test.cpp create mode 100644 utest/generation.test.cpp diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 51b72c9e..8e162a95 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -15,36 +15,20 @@ namespace xo { * * @text * - * before @ref release_redline_memory - * - * <-----allocated----> <-free-> <-reserved-> - * XXXXXXXXXXXXXXXXXXXX______________________ - * ^ ^ ^ ^ - * lo free redline hi - * limit - * - * after @ref release_redline_memory - * * <-----allocated----> <--------free-------> * XXXXXXXXXXXXXXXXXXXX______________________ * ^ ^ ^ * lo free hi * limit * @endtext - * - * TODO: rename to ArenaAlloc **/ class ArenaAlloc : public IAlloc { public: ~ArenaAlloc(); /** create allocator with capacity @p z, - * with reserved capacity @p redline_z. **/ static up make(const std::string & name, -#ifdef REDLINE_MEMORY - std::size_t redline_z, -#endif std::size_t z, bool debug_flag); @@ -56,7 +40,7 @@ namespace xo { // inherited from IAlloc... - virtual const std::string & name() const final override { return name_; } + virtual const std::string & name() const final override; virtual std::size_t size() const final override; virtual std::size_t available() const final override; virtual std::size_t allocated() const final override; @@ -64,19 +48,14 @@ namespace xo { virtual bool is_before_checkpoint(const void * x) const final override; virtual std::size_t before_checkpoint() const final override; virtual std::size_t after_checkpoint() const final override; + virtual bool debug_flag() const final override; virtual void clear() final override; virtual void checkpoint() final override; virtual std::byte * alloc(std::size_t z) final override; -#ifdef REDLINE_MEMORY - virtual void release_redline_memory() final override; -#endif private: ArenaAlloc(const std::string & name, -#ifdef REDLINE_MEMORY - std::size_t rz, -#endif std::size_t z, bool debug_flag); private: @@ -99,10 +78,6 @@ namespace xo { std::byte * free_ptr_ = nullptr; /** soft limit: end of released memory **/ std::byte * limit_ = nullptr; -#ifdef REDLINE_MEMORY - /** amount of last-resort memory to reserve **/ - std::size_t redline_z_ = 0; -#endif /** hard limit: end of allocated memory **/ std::byte * hi_ = nullptr; /** true to enable detailed debug logging **/ diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 679e5286..4560f3ac 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -199,6 +199,15 @@ namespace xo { #endif private: + ListAlloc * nursery_to() const { return nursery(role::to_space); } + ListAlloc * nursery_from() const { return nursery(role::from_space); } + + ListAlloc * tenured_to() const { return tenured(role::to_space); } + ListAlloc * tenured_from() const { return tenured(role::from_space); } + + ListAlloc * nursery(role r) const { return nursery_[role2int(r)].get(); } + ListAlloc * tenured(role r) const { return tenured_[role2int(r)].get(); } + /** begin GC now **/ void execute_gc(generation g); /** cleanup phase. aux function for @ref execute_gc **/ diff --git a/include/xo/alloc/IAlloc.hpp b/include/xo/alloc/IAlloc.hpp index 2eacd9cc..b8270f53 100644 --- a/include/xo/alloc/IAlloc.hpp +++ b/include/xo/alloc/IAlloc.hpp @@ -52,7 +52,7 @@ namespace xo { /** number of bytes allocated since @ref checkpoint **/ virtual std::size_t after_checkpoint() const = 0; /** @return true iff debug logging enabled **/ - virtual bool debug_flag() const { return false; } + virtual bool debug_flag() const = 0; /** reset allocator to empty state. **/ virtual void clear() = 0; @@ -76,10 +76,6 @@ namespace xo { * Only used in @ref GC. Default implementation asserts and returns nullptr **/ virtual std::byte * alloc_gc_copy(std::size_t z, const void * src); -#ifdef REDLINE_MEMORY - /** release last-resort reserved memory **/ - virtual void release_redline_memory() = 0; -#endif }; } /*namespace gc*/ diff --git a/include/xo/alloc/ListAlloc.hpp b/include/xo/alloc/ListAlloc.hpp index 627bbf50..ac2f9894 100644 --- a/include/xo/alloc/ListAlloc.hpp +++ b/include/xo/alloc/ListAlloc.hpp @@ -29,9 +29,6 @@ namespace xo { ListAlloc(std::unique_ptr hd, ArenaAlloc * marked, std::size_t cz, std::size_t nz, std::size_t tz, -#ifdef REDLINE_MEMORY - bool use_redline, -#endif bool debug_flag); ~ListAlloc(); @@ -40,8 +37,8 @@ namespace xo { /** reset to have at least @p z bytes of storage **/ bool reset(std::size_t z); - /** expand bucket list to accomodate a requrest of size @p z **/ - bool expand(std::size_t z); + /** expand bucket list to accomodate a request of size @p z **/ + bool expand(std::size_t z, const std::string & name); /** current free pointer **/ std::byte * free_ptr() const; @@ -64,13 +61,11 @@ namespace xo { virtual bool is_before_checkpoint(const void * x) const final override; virtual std::size_t before_checkpoint() const final override; virtual std::size_t after_checkpoint() const final override; + virtual bool debug_flag() const final override; virtual void clear() final override; virtual void checkpoint() final override; virtual std::byte * alloc(std::size_t z) final override; -#ifdef REDLINE_MEMORY - virtual void release_redline_memory() final override; -#endif private: /** **/ @@ -89,11 +84,6 @@ namespace xo { std::size_t next_z_ = 0; /** total size of @ref hd_ + contents of @ref full_l_ **/ std::size_t total_z_ = 0; -#ifdef REDLINE_MEMORY - bool use_redline_ = false; - bool redlined_flag_ = false; -#endif - /** true to enable debug logging **/ bool debug_flag_ = false; }; diff --git a/include/xo/alloc/generation.hpp b/include/xo/alloc/generation.hpp index 6a5a7c2e..82c48808 100644 --- a/include/xo/alloc/generation.hpp +++ b/include/xo/alloc/generation.hpp @@ -3,6 +3,9 @@ * author: Roland Conybeare, Aug 2025 */ +#pragma once + +#include #include namespace xo { @@ -15,6 +18,13 @@ namespace xo { constexpr std::size_t gen2int(generation x) { return static_cast(x); } + const char * gen2str(generation x); + + inline std::ostream & operator<<(std::ostream & os, generation x) { + os << gen2str(x); + return os; + } + enum class generation_result { nursery, tenured, diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index 94053560..e978f566 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -13,36 +13,19 @@ namespace xo { namespace gc { ArenaAlloc::ArenaAlloc(const std::string & name, -#ifdef REDLINE_MEMORY - std::size_t rz, -#endif std::size_t z, bool debug_flag) { this->name_ = name; -#ifdef REDLINE_MEMORY - this->lo_ = (new std::byte [rz + z]); -#else this->lo_ = (new std::byte [z]); -#endif this->checkpoint_ = lo_; this->free_ptr_ = lo_; this->limit_ = lo_ + z; -#ifdef REDLINE_MEMORY - this->redline_z_ = rz; - this->hi_ = limit_ + rz; -#else this->hi_ = limit_; -#endif this->debug_flag_ = debug_flag; if (!lo_) { -#ifdef REDLINE_MEMORY - throw std::runtime_error(tostr("ArenaAlloc: allocation failed", - xtag("size", rz + z))); -#else throw std::runtime_error(tostr("ArenaAlloc: allocation failed", xtag("size", z))); -#endif } } @@ -56,24 +39,15 @@ namespace xo { this->checkpoint_ = nullptr; this->free_ptr_ = nullptr; this->limit_ = nullptr; -#ifdef REDLINE_MEMORY - this->redline_z_ = 0; -#endif this->hi_ = nullptr; this->debug_flag_ = false; } up ArenaAlloc::make(const std::string & name, -#ifdef REDLINE_MEMORY - std::size_t rz, -#endif std::size_t z, bool debug_flag) { return up(new ArenaAlloc(name, -#ifdef REDLINE_MEMORY - rz, -#endif z, debug_flag)); } @@ -97,22 +71,36 @@ namespace xo { ArenaAlloc::capture_object_statistics(capture_phase phase, ObjectStatistics * p_dest) const { + scope log(XO_DEBUG(debug_flag_), + xtag("name", name_), + xtag("capacity", limit_ - lo_), + xtag("alloc", free_ptr_ - lo_), + xtag("lo", (void*)lo_), + xtag("free_ptr", (void*)free_ptr_)); + using xo::reflect::TaggedPtr; std::byte * p = lo_; while (p < free_ptr_) { - Object * obj = reinterpret_cast(p); - TaggedPtr tp = obj->self_tp(); - std::size_t z = obj->_shallow_size(); + Object * obj = reinterpret_cast(p); + TaggedPtr tp = obj->self_tp(); + std::size_t z = obj->_shallow_size(); std::uint32_t id = tp.td()->id().id(); + log && log(xtag("obj", (void*)obj), + xtag("z", z), + xtag("typeid", id)); + if (p_dest->per_type_stats_v_.size() < id + 1) p_dest->per_type_stats_v_.resize(id + 1); PerObjectTypeStatistics & dest = p_dest->per_type_stats_v_.at(id); dest.td_ = tp.td(); + + log && log(xtag("td", tp.td()->short_name())); + switch (phase) { case capture_phase::sab: ++dest.scanned_n_; @@ -130,6 +118,11 @@ namespace xo { assert(p == free_ptr_); } + const std::string & + ArenaAlloc::name() const { + return name_; + } + std::size_t ArenaAlloc::size() const { return limit_ - lo_; @@ -167,15 +160,17 @@ namespace xo { return free_ptr_ - checkpoint_; } + bool + ArenaAlloc::debug_flag() const + { + return debug_flag_; + } + void ArenaAlloc::clear() { this->set_free_ptr(lo_); -#ifdef REDLINE_MEMORY - this->limit_ = hi_ - redline_z_; -#else this->limit_ = hi_; -#endif } void @@ -204,7 +199,7 @@ namespace xo { std::byte * retval = this->free_ptr_; - log && log(xtag("self", name_), xtag("z0", z0), xtag("+pad", dz), xtag("z1", z1)); + log && log(xtag("self", name_), xtag("z0", z0), xtag("+pad", dz), xtag("z1", z1), xtag("avail", this->available())); if (free_ptr_ + z1 > limit_) { return nullptr; @@ -215,13 +210,6 @@ namespace xo { return retval; } -#ifdef REDLINE_MEMORY - void - ArenaAlloc::release_redline_memory() { - this->limit_ = this->hi_; - } -#endif - } /*namespace gc*/ } /*namespace xo*/ diff --git a/src/alloc/CMakeLists.txt b/src/alloc/CMakeLists.txt index 55b8641c..589f3b90 100644 --- a/src/alloc/CMakeLists.txt +++ b/src/alloc/CMakeLists.txt @@ -10,6 +10,7 @@ set(SELF_SRCS ObjectStatistics.cpp Object.cpp Forwarding1.cpp + generation.cpp ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) diff --git a/src/alloc/Forwarding1.cpp b/src/alloc/Forwarding1.cpp index 5a941c82..4b47e4f2 100644 --- a/src/alloc/Forwarding1.cpp +++ b/src/alloc/Forwarding1.cpp @@ -26,7 +26,7 @@ namespace xo { void Forwarding1::display(std::ostream & os) const { - os << ""; + os << "self_tp().td()->short_name()) << ">"; } Object * diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 460ac770..2990adf6 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -175,7 +175,8 @@ namespace xo { GcStatisticsExt retval = GcStatisticsExt(this->native_gc_statistics()); retval.nursery_z_ = nursery_[role2int(role::to_space)]->size(); - retval.nursery_before_checkpoint_z_ = nursery_[role2int(role::to_space)]->before_checkpoint(); + retval.nursery_before_checkpoint_z_ = this->nursery_to()->before_checkpoint(); + retval.nursery_after_checkpoint_z_ = this->nursery_to()->after_checkpoint(); retval.tenured_z_ = tenured_[role2int(role::to_space)]->size(); return retval; @@ -254,21 +255,9 @@ namespace xo { { std::byte * x = nursery_[role2int(role::to_space)]->alloc(z); - if (!x) { - /* ListAlloc won't fail -- instead will increase heap size */ + /* ListAlloc won't fail unless we exhaust memory -- instead will increase heap size */ - this->request_gc(generation::nursery); - -#ifdef REDLINE_MEMORY - if (incr_gc_pending_ || full_gc_pending_) - nursery_[role2int(role::to_space)]->release_redline_memory(); - - /* try (just once) more, maybe request fits in redline space */ - x = nursery_[role2int(role::to_space)]->alloc(z); -#endif - - assert(x); - } + assert(x); return x; } @@ -308,18 +297,6 @@ namespace xo { log && log("nursery"); retval = nursery_[role2int(role::to_space)]->alloc(z); - - if (!retval) { - /* nursery space exhausted !? */ - - this->request_gc(generation::nursery); - -#ifdef REDLINE_MEMORY - nursery_[role2int(role::to_space)]->release_redline_memory(); -#endif - - retval = nursery_[role2int(role::to_space)]->alloc(z); - } } } break; @@ -393,14 +370,6 @@ namespace xo { } } -#ifdef REDLINE_MEMORY - void - GC::release_redline_memory() - { - // not supported feature for GC - } -#endif - void GC::swap_nursery() { @@ -428,40 +397,62 @@ namespace xo { void GC::swap_spaces(generation target) { - scope log(XO_DEBUG(this->debug_flag())); + scope log(XO_DEBUG(this->debug_flag()), xtag("upto", target)); // will be copying into the memory regions currently labelled FromSpace /* gc will copy some to-be-determined amount in [0..promote_z] from nursery->tenured generation. */ - std::size_t promote_z = nursery_[role2int(role::to_space)]->before_checkpoint(); + std::size_t max_promote_z = nursery_[role2int(role::to_space)]->before_checkpoint(); + + log && log(xtag("max_promote_z", max_promote_z)); + if (target == generation::tenured) { /* gc on tenured generation may need this much space */ - std::size_t tenured_z = (tenured_[role2int(role::to_space)]->allocated() - + promote_z - + full_gc_threshold_); + std::size_t need_tenured_z = (tenured_[role2int(role::to_space)]->allocated() + + max_promote_z + + full_gc_threshold_); - tenured_[role2int(role::from_space)]->reset(tenured_z); + log && log("need_tenured_z", need_tenured_z); + + tenured_from()->reset(need_tenured_z); this->swap_tenured(); } else { - if (tenured_[role2int(role::to_space)]->available() < promote_z) { - tenured_[role2int(role::to_space)]->expand(promote_z); + std::size_t avail_tenured_z = tenured_[role2int(role::to_space)]->available(); + + log && log(xtag("avail_tenured_z", avail_tenured_z)); + + if (avail_tenured_z < max_promote_z) { + ListAlloc * tenured_to = this->tenured_to(); + + tenured_to->expand(max_promote_z, tenured_to->name() + "+"); } } - nursery_[role2int(role::from_space)]->reset(nursery_[role2int(role::to_space)]->allocated() - - promote_z - + incr_gc_threshold_); + /* subtracting max_promote_z is correct here, since anything not promoted is garbage */ + std::size_t need_nursery_z = (nursery(role::to_space)->allocated() + - max_promote_z + + incr_gc_threshold_); + + log && log(xtag("need_nursery_z", need_nursery_z)); + + /* (from-space is about to become to-space, to receive surviving nursery objects) */ + nursery(role::from_space)->reset(need_nursery_z); + this->swap_nursery(); this->swap_mutation_log(); - log && log(xtag("nursery.from", nursery_[role2int(role::from_space)]->name())); - log && log(xtag("nursery.to", nursery_[role2int(role::to_space) ]->name())); - log && log(xtag("tenured.from", tenured_[role2int(role::from_space)]->name())); - log && log(xtag("tenured.to", tenured_[role2int(role::to_space) ]->name())); + ListAlloc * N_from = nursery(role::from_space); + log && log(xtag("nursery.from", N_from->name()), xtag("size", N_from->size())); + ListAlloc * N_to = nursery(role::to_space); + log && log(xtag("nursery.to", N_to->name()), xtag("size", N_to->size())); + ListAlloc * T_from = tenured(role::from_space); + log && log(xtag("tenured.from", T_from->name()), xtag("size", T_from->size())); + ListAlloc * T_to = tenured(role::to_space); + log && log(xtag("tenured.to", T_to->name()), xtag("size", T_to->size())); } /*swap_spaces*/ @@ -504,8 +495,12 @@ namespace xo { void GC::copy_globals(generation upto) { + scope log(XO_DEBUG(config_.debug_flag_), + xtag("roots", gc_root_v_.size())); + for (Object ** pp_root : gc_root_v_) { - this->copy_object(pp_root, upto, &object_statistics_sae_[gen2int(upto)]); + this->copy_object(pp_root, upto, + &object_statistics_sae_[gen2int(upto)]); } } @@ -750,28 +745,30 @@ namespace xo { { scope log(XO_DEBUG(config_.debug_flag_)); - std::size_t N_allocated = nursery_[role2int(role::from_space)]->after_checkpoint(); - std::size_t T_allocated = tenured_[role2int(role::from_space)]->after_checkpoint(); + std::size_t N_allocated = nursery_from()->after_checkpoint(); + std::size_t T_allocated = tenured_from()->after_checkpoint(); - std::size_t N_before_gc = nursery_[role2int(role::from_space)]->allocated(); - std::size_t T_before_gc = tenured_[role2int(role::from_space)]->allocated(); + std::size_t N_before_gc = nursery_from()->allocated(); + std::size_t T_before_gc = tenured_from()->allocated(); - std::size_t N_after_gc = nursery_[role2int(role::to_space)]->allocated(); - std::size_t T_after_gc = tenured_[role2int(role::to_space)]->allocated(); + std::size_t N_after_gc = nursery_to()->allocated(); + std::size_t T_after_gc = tenured_to()->allocated(); //std::byte * N_free_ptr = nursery_[role2int(role::to_space)]->free_ptr(); - std::size_t promote_z = gc_statistics_.total_promoted_ - gc_statistics_.total_promoted_sab_; + std::size_t promote_z = (gc_statistics_.total_promoted_ + - gc_statistics_.total_promoted_sab_); - this->nursery_[role2int(role::from_space)]->reset(0); - this->tenured_[role2int(role::from_space)]->reset(0); + /* Don't reset from-space here, it's unnecessary. + * Would be permissible, but interferes with GC object modelling in + * xo-object/utest/GC.test.cpp + */ + //this->nursery_[role2int(role::from_space)]->reset(0); + //this->tenured_[role2int(role::from_space)]->reset(0); /* objects currenty in to-space nursery have survived one collection */ - this->nursery_[role2int(role::to_space)]->checkpoint(); - - // nursery_[role2int(role::to_space)]->set_redline(nursery_[role2int(role::to_space)]->allocated() + incr_gc_threshold_) - + this->nursery_to()->checkpoint(); if (upto == generation::tenured) - this->tenured_[role2int(role::to_space)]->checkpoint(); + this->tenured_to()->checkpoint(); if (log) { log(xtag("N_allocated", N_allocated)); @@ -819,7 +816,7 @@ namespace xo { this->capture_object_statistics(upto, capture_phase::sab); - log && log("step 1 : swap to/from roles"); + log && log("step 1 : swap to/from roles"); this->swap_spaces(upto); @@ -829,15 +826,15 @@ namespace xo { log && log("step 2b: TODO: copy pinned"); - log && log("step 3 : forward mutation log"); + log && log("step 3 : forward mutation log"); this->forward_mutation_log(upto); - log && log("step 4 : TODO: notify destructor log"); + log && log("step 4 : TODO: notify destructor log"); - log && log("step 5 : TODO: keep reachable weak pointers"); + log && log("step 5 : TODO: keep reachable weak pointers"); - log && log("step 6 : cleanup"); + log && log("step 6 : cleanup"); this->cleanup_phase(upto); diff --git a/src/alloc/GcStatistics.cpp b/src/alloc/GcStatistics.cpp index d54c3cf2..7b7a6ff9 100644 --- a/src/alloc/GcStatistics.cpp +++ b/src/alloc/GcStatistics.cpp @@ -32,12 +32,12 @@ namespace xo { PerGenerationStatistics::display(std::ostream & os) const { os << ""; } @@ -62,9 +62,9 @@ namespace xo { GcStatistics::display(std::ostream & os) const { os << ""; } diff --git a/src/alloc/ListAlloc.cpp b/src/alloc/ListAlloc.cpp index 1f84d5c6..6e37a325 100644 --- a/src/alloc/ListAlloc.cpp +++ b/src/alloc/ListAlloc.cpp @@ -5,6 +5,7 @@ #include "ListAlloc.hpp" #include "ArenaAlloc.hpp" +#include "xo/indentlog/scope.hpp" #include #include @@ -13,9 +14,6 @@ namespace xo { ListAlloc::ListAlloc(std::unique_ptr hd, ArenaAlloc * marked, std::size_t cz, std::size_t nz, std::size_t tz, -#ifdef REDLINE_MEMORY - bool use_redline, -#endif bool debug_flag) : start_z_{cz}, hd_{std::move(hd)}, @@ -24,9 +22,6 @@ namespace xo { current_z_{cz}, next_z_{nz}, total_z_{tz}, -#ifdef REDLINE_MEMOORY - use_redline_{use_redline}, -#endif debug_flag_{debug_flag} {} @@ -39,9 +34,6 @@ namespace xo { ListAlloc::make(const std::string & name, std::size_t cz, std::size_t nz, bool debug_flag) { std::unique_ptr hd{ArenaAlloc::make(name, -#ifdef REDLINE_MEMORY - 0, -#endif cz, debug_flag)}; if (!hd) @@ -52,9 +44,6 @@ namespace xo { up retval{new ListAlloc(std::move(hd), marked, cz, nz, cz, -#ifdef REDLINE_MEMORY - false /*!use_redline*/, -#endif debug_flag)}; return retval; @@ -134,34 +123,31 @@ namespace xo { bool ListAlloc::is_before_checkpoint(const void * x) const { if (!marked_) - return false; + return true; - if ((marked_ == hd_.get()) && hd_->contains(x)) - return hd_->is_before_checkpoint(x); + if (marked_ && marked_->contains(x)) + return marked_->is_before_checkpoint(x); /* - * 1. allocs in full_l_ appear in youngest-to-oldest order - * 2. allocators that appear before marked_ in full_l_ count as 'after checkpoint' - * 3. allocators that appear after marked_ in full_l_ count as 'before checkpoint' + * 1. allocs in full_l_ appear in oldest-to-youngest order + * 2. allocators that appear before marked_ in full_l_ count as 'before checkpoint' + * 3. allocators that appear after marked_ in full_l_ count as 'after checkpoint' */ - bool younger_than_marked = true; + bool older_than_marked = true; for (const auto & alloc : full_l_) { - if (younger_than_marked) { + if (older_than_marked) { if (alloc.get() == marked_) { /* nothing else to test on this iteration, * already checked .marked_ specifically */ - younger_than_marked = false; + break; } else { - /* after checkpoint */ + /* before checkpoint */ if (alloc->contains(x)) - return false; + return true; } - } else { - if (alloc->contains(x)) - return true; } } @@ -171,55 +157,63 @@ namespace xo { std::size_t ListAlloc::before_checkpoint() const { + scope log(XO_DEBUG(false && debug_flag_), xtag("marked", marked_ ? marked_->name() : "")); + if (marked_) { if (full_l_.empty()) { assert(marked_ == hd_.get()); return marked_->before_checkpoint(); + } else { + std::size_t z = 0; + + /* control here: .marked & .full_l non-empty. */ + if (hd_.get() == marked_) { + z += hd_->before_checkpoint(); + + /* anything in .full_l is older than marked .hd */ + for (const auto & alloc : full_l_) { + z += alloc->allocated(); + } + + return z; + } else { + /* messiest case: .marked is true, + * and not the youngest arena + */ + + /* full_l always in increasing time order: oldest-to-youngest order */ + size_t i_alloc = 0; + for (const auto & alloc : full_l_) { + log && log(xtag("i_alloc", i_alloc), + xtag("alloc", alloc->name()), + xtag("z", z)); + + if (alloc.get() == marked_) { + log && log("marked", xtag("+z", marked_->before_checkpoint())); + z += marked_->before_checkpoint(); + break; + } else { + log && log("older than marked", xtag("+z", alloc->allocated())); + z += alloc->allocated(); + } + ++i_alloc; + } + } + + return z; } } else { - /* count everything allocated */ + /* count *everything* allocated */ return this->allocated(); } - - std::size_t z = 0; - - /* control here: .marked & .full_l non-empty. */ - if (hd_.get() == marked_) { - z += hd_->before_checkpoint(); - - /* anything in .full_l older than marked .hd */ - for (const auto & alloc : full_l_) { - z += alloc->allocated(); - } - - return z; - } else { - /* messiest case: .marked is true, - * and not the youngest arena - */ - bool younger_than_marked = true; - - for (const auto & alloc : full_l_) { - if (younger_than_marked) { - if (alloc.get() == marked_) { - younger_than_marked = false; - z += marked_->before_checkpoint(); - } else { - ; - } - } else { - z += alloc->allocated(); - } - } - } - - return z; } std::size_t ListAlloc::after_checkpoint() const { + scope log(XO_DEBUG(false && debug_flag_), xtag("marked", marked_ ? marked_->name() : "")); + if (!marked_) return 0; @@ -229,25 +223,44 @@ namespace xo { return marked_->after_checkpoint(); } - bool younger_than_marked = true; + bool older_than_marked = true; std::size_t z = 0; + std::size_t i_alloc = 0; for (const auto & alloc : full_l_) { - if (younger_than_marked) { + log && log(xtag("i_alloc", i_alloc), + xtag("alloc", alloc->name()), + xtag("z", z)); + + if (older_than_marked) { if (alloc.get() == marked_) { - younger_than_marked = false; + log && log("marked", xtag("+z", marked_->after_checkpoint())); + older_than_marked = false; z += marked_->after_checkpoint(); - break; - } else { - z += alloc->allocated(); } + } else { + /* younger than marked */ + log && log("younger", xtag("+z", alloc->allocated())); + z += alloc->allocated(); } + + ++i_alloc; } + /** head must be included, since it's always the youngest bucket **/ + z += hd_->after_checkpoint(); + + log && log("z", z); + return z; } + bool + ListAlloc::debug_flag() const { + return debug_flag_; + } + void ListAlloc::clear() { // general hygiene @@ -258,26 +271,17 @@ namespace xo { current_z_ = 0; next_z_ = 0; total_z_ = 0; -#ifdef REDLINE_MEMORY - use_redline_ = false; -#endif } bool ListAlloc::reset(std::size_t z) { -#ifdef REDLINE_MEMORY - // warning: hd_->size() does not include redline memory - hd_->release_redline_memory(); -#endif + scope log(XO_DEBUG(debug_flag_), xtag("z", z)); bool recycle_head_bucket = hd_ && (z <= hd_->size()); this->full_l_.clear(); this->marked_ = nullptr; -#ifdef REDLINE_MEMORY - this->redlined_flag_ = false; -#endif if (recycle_head_bucket) { this->hd_->clear(); @@ -285,16 +289,22 @@ namespace xo { return true; } else { + std::string old_name = this->hd_->name(); + this->hd_.reset(nullptr); this->total_z_ = 0; - return this->expand(z); + return this->expand(z, old_name + "+"); } } bool - ListAlloc::expand(std::size_t z) + ListAlloc::expand(std::size_t z, const std::string & name) { + scope log(XO_DEBUG(debug_flag_), xtag("name", name)); + + //log && log("before", xtag("before_ckp", this->before_checkpoint())); + std::size_t cz = current_z_; std::size_t nz = next_z_; std::size_t tz; @@ -305,12 +315,9 @@ namespace xo { nz = tz; } while (cz < z); - std::string name = hd_->name() + "+exp"; + log && log("expand to", xtag("cz", cz)); std::unique_ptr new_alloc = ArenaAlloc::make(name, -#ifdef REDLINE_MEMORY - 0, -#endif cz, debug_flag_); if (!new_alloc) @@ -320,41 +327,43 @@ namespace xo { this->next_z_ = nz; this->total_z_ += cz; + if (hd_) + this->full_l_.push_back(std::move(hd_)); + this->hd_ = std::move(new_alloc); + //log && log("after", xtag("before_ckp", this->before_checkpoint())); + return true; } void ListAlloc::checkpoint() { + scope log(XO_DEBUG(debug_flag_)); + hd_->checkpoint(); this->marked_ = hd_.get(); + + log && log(xtag("hd", (void*)hd_.get()), xtag("marked", (void*)marked_)); } std::byte * ListAlloc::alloc(std::size_t z) { + scope log(XO_DEBUG(debug_flag_)); + std::byte * retval = hd_->alloc(z); if (retval) return retval; - if (this->expand(z)) + log && log("space exhausted -> expand"); + + if (this->expand(z, hd_->name() + "+")) return hd_->alloc(z); return nullptr; } - -#ifdef REDLINE_MEMORY - void - ListAlloc::release_redline_memory() - { - if (use_redline_) - redlined_flag_ = true; - - this->hd_->release_redline_memory(); - } -#endif } /*namespace gc*/ } /*namespace xo*/ diff --git a/src/alloc/ObjectStatistics.cpp b/src/alloc/ObjectStatistics.cpp index a69928dc..863a02cb 100644 --- a/src/alloc/ObjectStatistics.cpp +++ b/src/alloc/ObjectStatistics.cpp @@ -14,13 +14,13 @@ namespace xo { { os << "short_name()); + os << xrtag("td", td_->short_name()); else - os << rtag("td", "nullptr"); - os << rtag("scanned_n", scanned_n_) - << rtag("scanned_z", scanned_z_) - << rtag("survive_n", survive_n_) - << rtag("survive_z", survive_z_) + os << xrtag("td", "nullptr"); + os << xrtag("scanned_n", scanned_n_) + << xrtag("scanned_z", scanned_z_) + << xrtag("survive_n", survive_n_) + << xrtag("survive_z", survive_z_) << ">"; } diff --git a/src/alloc/generation.cpp b/src/alloc/generation.cpp new file mode 100644 index 00000000..54c151ac --- /dev/null +++ b/src/alloc/generation.cpp @@ -0,0 +1,22 @@ +/* generation.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "generation.hpp" + +namespace xo { + namespace gc { + const char * gen2str(generation x) { + switch (x) { + case generation::nursery: return "nursery"; + case generation::tenured: return "tenured"; + case generation::N: break; + } + return "?generation"; + } + + } /*namespace gc*/ +} /*namespace xo*/ + +/* generation.cpp */ diff --git a/utest/ArenaAlloc.test.cpp b/utest/ArenaAlloc.test.cpp index 0e4582e9..52f135f3 100644 --- a/utest/ArenaAlloc.test.cpp +++ b/utest/ArenaAlloc.test.cpp @@ -15,14 +15,8 @@ namespace xo { struct testcase_alloc { testcase_alloc(std::size_t rz, std::size_t z) : -#ifdef REDLINE_MEMORY - redline_z_{rz}, -#endif arena_z_{z} {} -#ifdef REDLINE_MEMORY - std::size_t redline_z_; -#endif std::size_t arena_z_; }; @@ -42,9 +36,6 @@ namespace xo { constexpr bool c_debug_flag = false; auto alloc = ArenaAlloc::make("linearalloc", -#ifdef REDLINE_MEMORY - tc.redline_z_, -#endif tc.arena_z_, c_debug_flag); REQUIRE(alloc.get()); diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index b38a442f..907bafcb 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -7,7 +7,13 @@ set(UTEST_SRCS alloc_utest_main.cpp IAlloc.test.cpp ArenaAlloc.test.cpp - GC.test.cpp) + ListAlloc.test.cpp + GC.test.cpp + GcStatistics.test.cpp + ObjectStatistics.test.cpp + Forwarding1.test.cpp + generation.test.cpp +) xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) xo_self_dependency(${UTEST_EXE} xo_alloc) diff --git a/utest/Forwarding1.test.cpp b/utest/Forwarding1.test.cpp new file mode 100644 index 00000000..e5dfb1fe --- /dev/null +++ b/utest/Forwarding1.test.cpp @@ -0,0 +1,85 @@ +/* Forwarding1.test.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "Forwarding1.hpp" +#include "ArenaAlloc.hpp" +#include "xo/reflect/Reflect.hpp" +#include +#include + +namespace xo { + using xo::reflect::Reflect; + using xo::obj::Forwarding1; + + namespace gc { + namespace { + class DummyObject : public Object { + public: + explicit DummyObject(const char * data) { + ::strncpy(data_.data(), data, 128); + } + + gp member() const { return member_; } + void assign_member(Object * x) { + Object::mm->assign_member(this, member_.ptr_address(), x); + } + + TaggedPtr self_tp() const final override { + return Reflect::make_tp(const_cast(this)); + } + + void display(std::ostream & os) const final override { os << data_; } + + virtual std::size_t _shallow_size() const final override { return sizeof(*this); } + virtual Object * _shallow_copy() const final override { return new (Cpof(this)) DummyObject(*this); } + virtual std::size_t _forward_children() final override { return _shallow_size(); } + + private: + std::array data_; + gp member_; + }; + } + + TEST_CASE("Forwarding1", "[gc][alloc]") + { + bool saved = tag_config::tag_color_enabled; + tag_config::tag_color_enabled = false; + + gp obj = new DummyObject("Well, I wasn't expecting that!"); + gp fwd = new Forwarding1(obj); + + REQUIRE(fwd->_destination() == obj.ptr()); + REQUIRE(fwd->_offset_destination(fwd.ptr()) == obj.ptr()); + + REQUIRE(fwd->self_tp().td()->short_name() == "Forwarding1"); + + std::stringstream ss; + ss << fwd; + + REQUIRE(ss.str() == ""); + + tag_config::tag_color_enabled = saved; + } + + TEST_CASE("IAlloc.assign_member", "[gc][alloc]") + { + /* not giving this nit it's own translation unit. + */ + + gp obj = new DummyObject("This also a surprise.."); + + up arena = ArenaAlloc::make("test", 1024, false); + + Object::mm = arena.get(); + + obj->assign_member(obj.ptr()); + + REQUIRE(obj->member().ptr() == obj.ptr()); + } + + } /*namespace gc*/ +} /*namespace xo*/ + +/* end Forwarding1.test.cpp */ diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp index c36deb2e..d961e3dd 100644 --- a/utest/GC.test.cpp +++ b/utest/GC.test.cpp @@ -37,6 +37,7 @@ namespace xo { .initial_tenured_z_ = tc.tenured_z_}); REQUIRE(gc.get()); + REQUIRE(gc->name() == "GC"); REQUIRE(gc->size() == tc.nursery_z_ + tc.tenured_z_); REQUIRE(gc->allocated() == 0); REQUIRE(gc->available() == tc.nursery_z_); diff --git a/utest/GcStatistics.test.cpp b/utest/GcStatistics.test.cpp new file mode 100644 index 00000000..5f2fbe96 --- /dev/null +++ b/utest/GcStatistics.test.cpp @@ -0,0 +1,216 @@ +/* @file GcStatistics.test.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "xo/alloc/GcStatistics.hpp" +#include "xo/indentlog/scope.hpp" +#include "xo/indentlog/print/tostr.hpp" +#include "xo/indentlog/print/hex.hpp" +#include +#include + +namespace xo { + using xo::gc::GcStatistics; + using xo::gc::GcStatisticsExt; + using xo::gc::PerGenerationStatistics; + using xo::print::ppconfig; + + namespace ut { + TEST_CASE("PerGenerationStatistics", "[alloc][gc]") + { + bool saved = tag_config::tag_color_enabled; + + tag_config::tag_color_enabled = false; + + PerGenerationStatistics stats; + + std::string s = tostr(stats); + + //std::cerr << hex_view(s.c_str(), s.c_str() + s.length(), true /*as_text*/) << std::endl; + + REQUIRE(s == ""); + + tag_config::tag_color_enabled = saved; + } + + TEST_CASE("GcStatistics", "[alloc][gc]") + { + bool saved = tag_config::tag_color_enabled; + + tag_config::tag_color_enabled = false; + + GcStatistics stats; + + std::string s = tostr(stats); + + REQUIRE(s == + "" + /***/ " ]" + /**/ " :total_allocated 0" + /**/ " :total_promoted_sab 0" + ">"); + + tag_config::tag_color_enabled = saved; + } + + TEST_CASE("GcStatisticsExt", "[alloc][gc]") + { + bool saved = tag_config::tag_color_enabled; + + tag_config::tag_color_enabled = false; + + GcStatisticsExt stats({}); + + std::string s = tostr(stats); + + REQUIRE(s == " ] :total_allocated 0 :total_promoted_sab 0 :nursery_z 0 :nursery_before_ckp_z 0 :nursery_after_ckp_z 0 :tenured_z 0 :n_mutation 0 :n_logged_mutation 0 :n_xgen_mutation 0 :n_xckp_mutation 0>"); + + tag_config::tag_color_enabled = saved; + } + + TEST_CASE("GcStatistics-pretty", "[alloc][gc][pretty]") + { + bool saved = tag_config::tag_color_enabled; + + tag_config::tag_color_enabled = false; + + std::stringstream ss; + ppconfig ppc; + GcStatistics stats; + + std::string actual = toppstr2(ppc, stats); + std::string expected + = (",\n" + " ]\n" + " :total_allocated 0\n" + " :total_promoted_sab 0\n" + " :total_promoted 0\n" + " :n_mutation 0\n" + " :n_logged_mutation 0\n" + " :n_xgen_mutation 0\n" + " :n_xckp_mutation 0>"); + + if (actual != expected) { + CHECK(actual == expected); + CHECK(actual.length() == expected.length()); + + auto a_ix = actual.begin(); + auto e_ix = expected.begin(); + + std::size_t pos = 0; + while (a_ix != actual.end() && e_ix != expected.end()) { + INFO(xtag("pos", pos)); + INFO(xtag("matching_prefix", std::string(actual.c_str(), pos))); + + REQUIRE(*a_ix == *e_ix); + + ++a_ix; + ++e_ix; + ++pos; + } + } + + REQUIRE(actual == expected); + + tag_config::tag_color_enabled = saved; + } + + TEST_CASE("GcStatisticsExt-pretty", "[alloc][gc][pretty]") + { + bool saved = tag_config::tag_color_enabled; + + tag_config::tag_color_enabled = false; + + std::stringstream ss; + ppconfig ppc; + GcStatisticsExt stats({}); + + std::string actual = toppstr2(ppc, stats); + std::string expected + = (",\n" + " ]\n" + " :total_allocated 0\n" + " :total_promoted_sab 0\n" + " :total_promoted 0\n" + " :n_mutation 0\n" + " :n_logged_mutation 0\n" + " :n_xgen_mutation 0\n" + " :n_xckp_mutation 0\n" + " :nursery_z 0\n" + " :nursery_before_checkpoint_z 0\n" + " :nursery_after_checkpoint_z 0\n" + " :tenured_z 0>"); + + if (actual != expected) { + CHECK(actual == expected); + CHECK(actual.length() == expected.length()); + + auto a_ix = actual.begin(); + auto e_ix = expected.begin(); + + std::size_t pos = 0; + while (a_ix != actual.end() && e_ix != expected.end()) { + INFO(xtag("pos", pos)); + INFO(xtag("matching_prefix", std::string(actual.c_str(), pos))); + + REQUIRE(*a_ix == *e_ix); + + ++a_ix; + ++e_ix; + ++pos; + } + } + + REQUIRE(actual == expected); + + tag_config::tag_color_enabled = saved; + } + } +} /*namespace xo*/ + +/* GcStatistics.test.cpp */ diff --git a/utest/ListAlloc.test.cpp b/utest/ListAlloc.test.cpp new file mode 100644 index 00000000..2db22bf2 --- /dev/null +++ b/utest/ListAlloc.test.cpp @@ -0,0 +1,58 @@ +/* ListAlloc.test.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "xo/alloc/ListAlloc.hpp" +#include + +namespace xo { + using xo::gc::ListAlloc; + + namespace ut { + TEST_CASE("ListAlloc", "[alloc][gc]") + { + /** teeny weeny allocator **/ + up alloc = ListAlloc::make("test", 16, 32, false); + + REQUIRE(alloc->name() == "test"); + REQUIRE(alloc->size() == 16); + REQUIRE(alloc->before_checkpoint() == 0); + REQUIRE(alloc->after_checkpoint() == 0); + + /* will expand */ + std::byte * mem1 = alloc->alloc(20); + + REQUIRE(mem1); + REQUIRE(alloc->size() == 16 + 32); + /* round up to multiple of 8 */ + REQUIRE(alloc->before_checkpoint() == 24); + REQUIRE(alloc->after_checkpoint() == 0); + + alloc->checkpoint(); + + std::byte * mem2 = alloc->alloc(30); + + REQUIRE(mem2); + REQUIRE(alloc->size() == 16 + 32 + 48); + REQUIRE(alloc->before_checkpoint() == 24); + /* round up to multiple of 8 */ + REQUIRE(alloc->after_checkpoint() == 32); + + std::byte * mem3 = alloc->alloc(40); + + REQUIRE(mem3); + REQUIRE(alloc->size() == 16 + 32 + 48 + 80); + REQUIRE(alloc->before_checkpoint() == 24); + /* already multiple of 8 */ + REQUIRE(alloc->after_checkpoint() == 32 + 40); + + REQUIRE(alloc->is_before_checkpoint(mem1) == true); + REQUIRE(alloc->is_before_checkpoint(mem2) == false); + REQUIRE(alloc->is_before_checkpoint(mem3) == false); + } + + } /*namespace ut*/ +} /*namespace xo*/ + +/* ListAlloc.test.cpp */ diff --git a/utest/ObjectStatistics.test.cpp b/utest/ObjectStatistics.test.cpp new file mode 100644 index 00000000..7530450d --- /dev/null +++ b/utest/ObjectStatistics.test.cpp @@ -0,0 +1,185 @@ +/* @file ObjectStatistics.test.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "xo/alloc/ObjectStatistics.hpp" +#include "xo/reflect/Reflect.hpp" +#include "xo/indentlog/scope.hpp" +#include "xo/indentlog/print/ppstr.hpp" +#include "xo/indentlog/print/tostr.hpp" +#include "xo/indentlog/print/hex.hpp" +#include + +namespace xo { + using xo::gc::ObjectStatistics; + using xo::gc::PerObjectTypeStatistics; + using xo::reflect::Reflect; + using xo::print::ppconfig; + + namespace ut { + TEST_CASE("PerObjectTypeStatistics", "[alloc][gc]") + { + bool saved = tag_config::tag_color_enabled; + + tag_config::tag_color_enabled = false; + + PerObjectTypeStatistics stats; + + std::string s = tostr(stats); + + //std::cerr << hex_view(s.c_str(), s.c_str() + s.length(), true /*as_text*/) << std::endl; + + REQUIRE(s == ""); + + tag_config::tag_color_enabled = saved; + } + + TEST_CASE("PerObjectTypeStatistics-1", "[alloc][gc]") + { + bool saved = tag_config::tag_color_enabled; + + tag_config::tag_color_enabled = false; + + PerObjectTypeStatistics stats; + stats.td_ = Reflect::require(); + stats.scanned_n_ = 4; + stats.scanned_z_ = 16; + stats.survive_n_ = 2; + stats.survive_z_ = 8; + + std::string s = tostr(stats); + + //std::cerr << hex_view(s.c_str(), s.c_str() + s.length(), true /*as_text*/) << std::endl; + + REQUIRE(s == ""); + + tag_config::tag_color_enabled = saved; + } + + TEST_CASE("ObjectStatistics", "[alloc][gc]") + { + bool saved = tag_config::tag_color_enabled; + + tag_config::tag_color_enabled = false; + + ObjectStatistics stats; + + std::string s = tostr(stats); + + REQUIRE(s == ""); + + tag_config::tag_color_enabled = saved; + } + + TEST_CASE("ObjectStatistics-1", "[alloc][gc]") + { + bool saved = tag_config::tag_color_enabled; + + tag_config::tag_color_enabled = false; + + ObjectStatistics stats; + stats.per_type_stats_v_.push_back(PerObjectTypeStatistics()); + + std::string s = tostr(stats); + + REQUIRE(s == ">"); + + tag_config::tag_color_enabled = saved; + } + + TEST_CASE("ObjectStatistics-pretty", "[alloc][gc][pretty]") + { + bool saved = tag_config::tag_color_enabled; + + tag_config::tag_color_enabled = false; + + std::stringstream ss; + ppconfig ppc; + ObjectStatistics stats; + + std::string actual = toppstr2(ppc, stats); + std::string expected + = (""); + + if (actual != expected) { + CHECK(actual == expected); + CHECK(actual.length() == expected.length()); + + auto a_ix = actual.begin(); + auto e_ix = expected.begin(); + + std::size_t pos = 0; + while (a_ix != actual.end() && e_ix != expected.end()) { + INFO(xtag("pos", pos)); + INFO(xtag("matching_prefix", std::string(actual.c_str(), pos))); + + REQUIRE(*a_ix == *e_ix); + + ++a_ix; + ++e_ix; + ++pos; + } + } + + REQUIRE(actual == expected); + + tag_config::tag_color_enabled = saved; + } + + TEST_CASE("ObjectStatistics-pretty-1", "[alloc][gc][pretty]") + { + bool saved = tag_config::tag_color_enabled; + + tag_config::tag_color_enabled = false; + + PerObjectTypeStatistics objstats; + objstats.td_ = Reflect::require(); + objstats.scanned_n_ = 4; + objstats.scanned_z_ = 16; + objstats.survive_n_ = 2; + objstats.survive_z_ = 8; + + std::stringstream ss; + ppconfig ppc; + ObjectStatistics stats; + stats.per_type_stats_v_.push_back(objstats); + + std::string actual = toppstr2(ppc, stats); + + std::string expected + = (" ]>"); + + if (actual != expected) { + CHECK(actual == expected); + CHECK(actual.length() == expected.length()); + + auto a_ix = actual.begin(); + auto e_ix = expected.begin(); + + std::size_t pos = 0; + while (a_ix != actual.end() && e_ix != expected.end()) { + INFO(xtag("pos", pos)); + INFO(xtag("matching_prefix", std::string(actual.c_str(), pos))); + + REQUIRE(*a_ix == *e_ix); + + ++a_ix; + ++e_ix; + ++pos; + } + } + + tag_config::tag_color_enabled = saved; + } + } +} /*namespace xo*/ + +/* ObjectStatistics.test.cpp */ diff --git a/utest/generation.test.cpp b/utest/generation.test.cpp new file mode 100644 index 00000000..415d6258 --- /dev/null +++ b/utest/generation.test.cpp @@ -0,0 +1,38 @@ +/* generation.test.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "xo/alloc/generation.hpp" +#include +#include + +namespace xo { + namespace gc { + TEST_CASE("generation", "[gc]") { + REQUIRE(::strcmp(gen2str(generation::nursery), "nursery") == 0); + REQUIRE(::strcmp(gen2str(generation::tenured), "tenured") == 0); + REQUIRE(::strcmp(gen2str(generation::N), "?generation") == 0); + + { + std::stringstream ss; + ss << generation::nursery; + REQUIRE(ss.str() == "nursery"); + } + + { + std::stringstream ss; + ss << generation::tenured; + REQUIRE(ss.str() == "tenured"); + } + + { + std::stringstream ss; + ss << generation::N; + REQUIRE(ss.str() == "?generation"); + } + } + } /*namespace gc*/ +} /*namespace xo*/ + +/* generation.test.cpp */ From d8b3d7a148595b265f97c85b47a8d0b6183199b6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Aug 2025 00:14:30 -0500 Subject: [PATCH 011/342] xo-alloc: reserve virtual memory, commit pages on demand --- CMakeLists.txt | 2 +- include/xo/alloc/ArenaAlloc.hpp | 20 ++++++- include/xo/alloc/GC.hpp | 9 ++- include/xo/alloc/IAlloc.hpp | 4 +- include/xo/alloc/ListAlloc.hpp | 1 + src/alloc/ArenaAlloc.cpp | 99 ++++++++++++++++++++++++++++----- src/alloc/GC.cpp | 17 +++++- src/alloc/ListAlloc.cpp | 11 ++++ 8 files changed, 140 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eebf3aff..0e9de5c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# alloc/CMakeLists.txt +# xo-alloc/CMakeLists.txt cmake_minimum_required(VERSION 3.10) diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 8e162a95..63de43e8 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -24,6 +24,8 @@ namespace xo { **/ class ArenaAlloc : public IAlloc { public: + ArenaAlloc(const ArenaAlloc &) = delete; + ArenaAlloc(ArenaAlloc &&) = delete; ~ArenaAlloc(); /** create allocator with capacity @p z, @@ -38,10 +40,14 @@ namespace xo { void capture_object_statistics(capture_phase phase, ObjectStatistics * p_dest) const; + /** expand available (i.e. committed) space to size @p z **/ + bool expand(std::size_t z); + // inherited from IAlloc... virtual const std::string & name() const final override; virtual std::size_t size() const final override; + virtual std::size_t committed() const final override; virtual std::size_t available() const final override; virtual std::size_t allocated() const final override; virtual bool contains(const void * x) const final override; @@ -54,6 +60,9 @@ namespace xo { virtual void checkpoint() final override; virtual std::byte * alloc(std::size_t z) final override; + ArenaAlloc & operator=(const ArenaAlloc &) = delete; + ArenaAlloc & operator=(ArenaAlloc &&) = delete; + private: ArenaAlloc(const std::string & name, std::size_t z, bool debug_flag); @@ -67,8 +76,15 @@ namespace xo { /** optional instance name, for diagnostics **/ std::string name_; + /** size of a VM page **/ + std::size_t page_z_; + /** allocator owns memory in range [@ref lo_, @ref hi_) **/ std::byte * lo_ = nullptr; + /** prefix of this size is actually committed. + * Remainder uses uncommitted virtual address space + **/ + std::size_t committed_z_ = 0; /** checkpoint (for GC support); divides objects into * older (addresses below checkpoint) * and younger (addresses above checkpoint) @@ -76,9 +92,9 @@ namespace xo { std::byte * checkpoint_; /** free pointer. memory in range [@ref free_, @ref limit_) available **/ std::byte * free_ptr_ = nullptr; - /** soft limit: end of released memory **/ + /** soft limit: end of committed virtual memory **/ std::byte * limit_ = nullptr; - /** hard limit: end of allocated memory **/ + /** hard limit: end of reserved virtual memory **/ std::byte * hi_ = nullptr; /** true to enable detailed debug logging **/ bool debug_flag_ = false; diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 4560f3ac..c5432935 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -164,7 +164,8 @@ namespace xo { * since one role is always held empty between collections. **/ virtual std::size_t size() const final override; - + /** for committed count both to-space and from-space **/ + virtual std::size_t committed() const final override; virtual std::size_t allocated() const final override; virtual std::size_t available() const final override; /** only tests to-space **/ @@ -194,10 +195,6 @@ namespace xo { virtual std::byte * alloc(std::size_t z) final override; virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; -#ifdef REDLINE_MEMORY - virtual void release_redline_memory() final override; -#endif - private: ListAlloc * nursery_to() const { return nursery(role::to_space); } ListAlloc * nursery_from() const { return nursery(role::from_space); } @@ -208,6 +205,8 @@ namespace xo { ListAlloc * nursery(role r) const { return nursery_[role2int(r)].get(); } ListAlloc * tenured(role r) const { return tenured_[role2int(r)].get(); } + MutationLog * mutation_log(role r) const { return mutation_log_[role2int(r)].get(); } + /** begin GC now **/ void execute_gc(generation g); /** cleanup phase. aux function for @ref execute_gc **/ diff --git a/include/xo/alloc/IAlloc.hpp b/include/xo/alloc/IAlloc.hpp index b8270f53..0b6791f0 100644 --- a/include/xo/alloc/IAlloc.hpp +++ b/include/xo/alloc/IAlloc.hpp @@ -31,10 +31,12 @@ namespace xo { /** optional name for this allocator; labelling for diagnostics **/ virtual const std::string & name() const = 0; - /** allocator size in bytes (up to soft limit). + /** allocator size in bytes (up to reserved limit) * Includes unallocated mmeory **/ virtual std::size_t size() const = 0; + /** committed size in bytes **/ + virtual std::size_t committed() const = 0; /** number of unallocated bytes available (up to soft limit) * from this allocator **/ diff --git a/include/xo/alloc/ListAlloc.hpp b/include/xo/alloc/ListAlloc.hpp index ac2f9894..7b592b4e 100644 --- a/include/xo/alloc/ListAlloc.hpp +++ b/include/xo/alloc/ListAlloc.hpp @@ -55,6 +55,7 @@ namespace xo { virtual const std::string & name() const final override; virtual std::size_t size() const final override; + virtual std::size_t committed() const final override; virtual std::size_t available() const final override; virtual std::size_t allocated() const final override; virtual bool contains(const void * x) const final override; diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index e978f566..49a2d16d 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -8,6 +8,7 @@ #include "ObjectStatistics.hpp" #include "xo/indentlog/scope.hpp" #include "xo/indentlog/print/tag.hpp" +#include #include namespace xo { @@ -15,27 +16,52 @@ namespace xo { ArenaAlloc::ArenaAlloc(const std::string & name, std::size_t z, bool debug_flag) { + scope log(XO_DEBUG(debug_flag), xtag("name", name)); + this->name_ = name; - this->lo_ = (new std::byte [z]); - this->checkpoint_ = lo_; - this->free_ptr_ = lo_; - this->limit_ = lo_ + z; - this->hi_ = limit_; - this->debug_flag_ = debug_flag; + this->page_z_ = getpagesize(); + + // reserve virtual memory + + void * base = mmap(nullptr, z, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + // could use this as fallback.. + //base = (new std::byte [z]); + + if (base == MAP_FAILED) { + throw std::runtime_error(tostr("ArenaAlloc: uncommitted allocation failed", + xtag("size", z))); + } + + this->lo_ = reinterpret_cast(base); + this->committed_z_ = 0; + this->checkpoint_ = lo_; + this->free_ptr_ = lo_; + this->limit_ = lo_ + z; + this->hi_ = limit_; + this->debug_flag_ = debug_flag; if (!lo_) { throw std::runtime_error(tostr("ArenaAlloc: allocation failed", xtag("size", z))); } + + log && log(xtag("lo", (void*)lo_), xtag("page_z", page_z_)); } ArenaAlloc::~ArenaAlloc() { - delete [] this->lo_; // hygiene.. + if (lo_) { + munmap(lo_, hi_ - lo_); + } + // could use this as fallback if not using uncommitted technique + //delete [] this->lo_; + this->lo_ = nullptr; + this->committed_z_ = 0; this->checkpoint_ = nullptr; this->free_ptr_ = nullptr; this->limit_ = nullptr; @@ -51,6 +77,46 @@ namespace xo { z, debug_flag)); } + namespace { + /* alignment better be a power of 2 */ + std::size_t + align_lub(std::size_t x, std::size_t align) + { + /* e.g: + * align = 4096, x%align = 100 -> dx = 3996 + * align = 4096, x%align = 0 -> dx = 0 + */ + std::size_t dx = (align - (x % align)) % align; + + return x + dx; + } + } + + bool + ArenaAlloc::expand(size_t offset_z) { + scope log(XO_DEBUG(debug_flag_), xtag("offset_z", offset_z), xtag("committed_z", committed_z_)); + + if (offset_z <= committed_z_) + return true; + + std::size_t align_offset_z = align_lub(offset_z, page_z_); + std::byte * commit_start = lo_ + committed_z_; + std::size_t new_commit_z = align_offset_z - committed_z_; + + log && log(xtag("align_offset_z", align_offset_z), + xtag("new_commit_z", new_commit_z)); + + if (mprotect(commit_start, new_commit_z, PROT_READ | PROT_WRITE) != 0) { + throw std::runtime_error(tostr("ArenaAlloc::expand: commit failure", + xtag("committed_z", committed_z_), + xtag("new_commit_z", new_commit_z))); + } + + this->committed_z_ = align_offset_z; + + return true; + } + void ArenaAlloc::set_free_ptr(std::byte * x) { @@ -59,7 +125,7 @@ namespace xo { if (lo_ <= x && x < limit_) { this->free_ptr_ = x; - if (this->checkpoint_ > free_ptr_) + if (checkpoint_ > free_ptr_) this->checkpoint_ = free_ptr_; } else { throw std::runtime_error(tostr("LinearAllog::set_free_ptr(x): expected lo <= x < limit", @@ -128,6 +194,11 @@ namespace xo { return limit_ - lo_; } + std::size_t + ArenaAlloc::committed() const { + return committed_z_; + } + std::size_t ArenaAlloc::available() const { return limit_ - free_ptr_; @@ -197,13 +268,15 @@ namespace xo { assert(z1 % c_bpw == 0ul); + this->expand(this->allocated() + z1); + std::byte * retval = this->free_ptr_; - log && log(xtag("self", name_), xtag("z0", z0), xtag("+pad", dz), xtag("z1", z1), xtag("avail", this->available())); - - if (free_ptr_ + z1 > limit_) { - return nullptr; - } + log && log(xtag("self", name_), + xtag("z0", z0), + xtag("+pad", dz), + xtag("z1", z1), + xtag("avail", this->available())); this->free_ptr_ += z1; diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 2990adf6..b72ac721 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -115,7 +115,16 @@ namespace xo { std::size_t GC::size() const { - return nursery_[role2int(role::to_space)]->size() + tenured_[role2int(role::to_space)]->size(); + return nursery_to()->size() + tenured_to()->size(); + } + + std::size_t + GC::committed() const + { + return (nursery_to()->committed() + + nursery_from()->committed() + + tenured_to()->committed() + + tenured_from()->committed()); } std::size_t @@ -182,6 +191,12 @@ namespace xo { return retval; } + std::size_t + GC::nursery_to_committed() const + { + return nursery_to()->committed(); + } + generation_result GC::fromspace_generation_of(const void * x) const { diff --git a/src/alloc/ListAlloc.cpp b/src/alloc/ListAlloc.cpp index 6e37a325..29cdb477 100644 --- a/src/alloc/ListAlloc.cpp +++ b/src/alloc/ListAlloc.cpp @@ -75,6 +75,17 @@ namespace xo { return total_z_; } + std::size_t + ListAlloc::committed() const { + std::size_t z = 0; + if (hd_) + z += hd_->committed(); + for (const auto & a : full_l_) + z += a->committed(); + + return z; + } + std::byte * ListAlloc::free_ptr() const { return hd_->free_ptr(); From 258555e9ebf691cca61d70d4ec139f4c51d7b209 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Aug 2025 00:16:00 -0500 Subject: [PATCH 012/342] xo-alloc: GC mutation log works for full GC --- include/xo/alloc/GC.hpp | 42 ++++++- src/alloc/GC.cpp | 254 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 269 insertions(+), 27 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index c5432935..a0bcef2b 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -40,6 +40,11 @@ namespace xo { * Will allocate more space as needed **/ std::size_t initial_tenured_z_ = 0; + /** trigger incremental GC after this many bytes allocated in nursery **/ + std::size_t incr_gc_threshold_ = 64*1024; + /** trigger full GC after this many bytes promoted to tenured **/ + std::size_t full_gc_threshold_ = 512*1024; + /** true to permit incremental garbage collection **/ bool allow_incremental_gc_ = true; /** true to report statistics **/ @@ -118,6 +123,7 @@ namespace xo { **/ static up make(const Config & config); + const Config & config() const { return config_; } const GCRunstate & runstate() const { return runstate_; } const GcStatistics & native_gc_statistics() const { return gc_statistics_; } GcStatisticsExt get_gc_statistics() const; @@ -126,6 +132,19 @@ namespace xo { bool is_gc_enabled() const { return gc_enabled_ == 0; } /** true during (and only during) a GC cycle **/ bool gc_in_progress() const { return runstate_.in_progress(); } + /** @return committed size of Nursery to-space **/ + std::size_t nursery_to_committed() const; + /** @return nursery bytes used before checkpoint **/ + std::size_t nursery_before_checkpoint() const; + /** @return nursery bytes used after checkpoint **/ + std::size_t nursery_after_checkpoint() const; + /** @return committed size of Tenured to-space **/ + std::size_t tenured_to_committed() const; + /** @return tenured bytes used before checkpoint **/ + std::size_t tenured_before_checkpoint() const; + /** @return tenured bytes used after checkpoint = promoted since last GC **/ + std::size_t tenured_after_checkpoint() const; + /** @return generation to which object at @p x belongs **/ generation_result tospace_generation_of(const void * x) const; /** @return generation that contains @p x, given it's in from-space **/ @@ -232,7 +251,6 @@ namespace xo { * (T->N, aka xgen) and (N1->N0, aka xckp) pointers **/ void incremental_gc_forward_mlog(ObjectStatistics * per_type_stats); - /** * Aux function for @ref incremental_gc_forward_mlog. Calls this function until * fixpoint. @@ -246,6 +264,23 @@ namespace xo { MutationLog * to_mlog, MutationLog * defer_mlog, ObjectStatistics * per_type_stats); + /** Aux function for @ref execute_gc. Updates bookkeeping for cross-generational + * (T->N, aka xgen) and (N1->N0, aka xckcp) pointers on full gc + **/ + void full_gc_forward_mlog(ObjectStatistics * per_type_stats); + /** + * Aux function for @ref full_gc_forward_mlog. Calls this function until fixpoint. + * + * @param from_mlog incoming mutation log. Contains {xgen,xckp} pointers before GC. + * Contents of this log is consumed (+discarded) before method returns. + * @param to_mlog outgoing mutation log. Will contain {xgen,xckp} pointers after GC. + * @param defer_mlog contains log entries associated with possible garbage. + * + **/ + void full_gc_forward_mlog_phase(MutationLog * from_mlog, + MutationLog * to_mlog, + MutationLog * defer_mlog, + ObjectStatistics * per_type_stats); private: /** garbage collector configuration **/ @@ -292,11 +327,6 @@ namespace xo { /** optional per-object-type counters. snapshot at end of collection cycle **/ std::array object_statistics_sae_; - /** trigger full GC whenever this much data arrives in tenured generation **/ - std::size_t full_gc_threshold_ = 0; - /** trigger incr GC whenever this much data arrives in nuresery generation **/ - std::size_t incr_gc_threshold_ = 0; - /** true when GC requested, * remains true until GC.. completes? begins? **/ diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index b72ac721..bcb8118b 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -163,13 +163,13 @@ namespace xo { std::size_t GC::before_checkpoint() const { - return nursery_[role2int(role::to_space)]->before_checkpoint(); + return this->nursery_to()->before_checkpoint(); } std::size_t GC::after_checkpoint() const { - return nursery_[role2int(role::to_space)]->after_checkpoint(); + return this->nursery_to()->after_checkpoint(); } bool @@ -197,16 +197,34 @@ namespace xo { return nursery_to()->committed(); } - generation_result - GC::fromspace_generation_of(const void * x) const + std::size_t + GC::nursery_before_checkpoint() const { - if (tenured_[role2int(role::from_space)]->contains(x)) - return generation_result::tenured; + return nursery_to()->before_checkpoint(); + } - if (nursery_[role2int(role::from_space)]->contains(x)) - return generation_result::nursery; + std::size_t + GC::nursery_after_checkpoint() const + { + return nursery_to()->after_checkpoint(); + } - return generation_result::not_found; + std::size_t + GC::tenured_to_committed() const + { + return tenured_to()->committed(); + } + + std::size_t + GC::tenured_before_checkpoint() const + { + return tenured_to()->before_checkpoint(); + } + + std::size_t + GC::tenured_after_checkpoint() const + { + return tenured_to()->after_checkpoint(); } generation_result @@ -221,6 +239,18 @@ namespace xo { return generation_result::not_found; } + generation_result + GC::fromspace_generation_of(const void * x) const + { + if (tenured_[role2int(role::from_space)]->contains(x)) + return generation_result::tenured; + + if (nursery_[role2int(role::from_space)]->contains(x)) + return generation_result::nursery; + + return generation_result::not_found; + } + std::byte * GC::free_ptr(generation gen) { @@ -262,16 +292,26 @@ namespace xo { void GC::checkpoint() { - nursery_[role2int(role::to_space) ]->checkpoint(); + nursery_to()->checkpoint(); + /* checkpoint T generation so we can trigger GC based on new T objects rather than + * overall T size + */ + tenured_to()->checkpoint(); } std::byte * GC::alloc(std::size_t z) { - std::byte * x = nursery_[role2int(role::to_space)]->alloc(z); + auto N_to = this->nursery_to(); + + if (!incr_gc_pending_ && (N_to->after_checkpoint() > config_.incr_gc_threshold_)) { + /* automatically ups to generation::tenured */ + this->request_gc(generation::nursery); + } + + std::byte * x = N_to->alloc(z); /* ListAlloc won't fail unless we exhaust memory -- instead will increase heap size */ - assert(x); return x; @@ -291,17 +331,17 @@ namespace xo { { log && log("tenured"); - retval = tenured_[role2int(role::to_space)]->alloc(z); + retval = this->tenured_to()->alloc(z); } break; case generation_result::nursery: { - if (nursery_[role2int(role::from_space)]->is_before_checkpoint(src)) + if (this->nursery_from()->is_before_checkpoint(src)) { /* nursery object has survived 2nd collection cycle * -> promote into tenured generation */ - retval = tenured_[role2int(role::to_space)]->alloc(z); + retval = this->tenured_to()->alloc(z); log && log("promote", xtag("addr", (void*)retval)); @@ -311,7 +351,7 @@ namespace xo { } else { log && log("nursery"); - retval = nursery_[role2int(role::to_space)]->alloc(z); + retval = this->nursery_to()->alloc(z); } } break; @@ -427,7 +467,7 @@ namespace xo { /* gc on tenured generation may need this much space */ std::size_t need_tenured_z = (tenured_[role2int(role::to_space)]->allocated() + max_promote_z - + full_gc_threshold_); + + config_.full_gc_threshold_); log && log("need_tenured_z", need_tenured_z); @@ -449,7 +489,7 @@ namespace xo { /* subtracting max_promote_z is correct here, since anything not promoted is garbage */ std::size_t need_nursery_z = (nursery(role::to_space)->allocated() - max_promote_z - + incr_gc_threshold_); + + config_.incr_gc_threshold_); log && log(xtag("need_nursery_z", need_nursery_z)); @@ -695,6 +735,139 @@ namespace xo { } } + void + GC::full_gc_forward_mlog_phase(MutationLog * from_mlog, + MutationLog * to_mlog, + MutationLog * defer_mlog, + ObjectStatistics * /*per_type_stats*/) + { + scope log(XO_DEBUG(config_.debug_flag_), xtag("from_mlog.size", from_mlog->size())); + + /* categorize pointers based on combination of {source address, destination address}, + * only care about the generation associated with an address. + * + * N0 : nursery(from), before checkpoint + * N0': nursery(to), before checkpoint + * N1 : nursery(from), after checkpoint + * N1': nursery(to), after checkpoint + * T : tenured(from) + * T': tenured(to) + * + * loc(P): parent region before GC + * loc(C): child region before GC + * + * | | forwarded | loc now post | loc after | + * | | already? | root copy | action | + * | loc(P) loc(C) | P C | P' C' | P' C' | defer | action + * ----|---------------+--------------+---------------+---------------+-------+--------------- + * (a) | T N0 | no no | T N0 | T N0 | P ->C | defer + * (b) | | yes | N1' | N1' | P ->C'| defer + * | | yes no | impossible + * (b2)| | yes | T' N1' | T' N1' | | +mlog + * (c) | T N1 | no no | T N1 | T T | P ->C | defer + * (d) | | yes | T T' | T T' | P ->C'| defer + * | | yes no | impossible + * (d2)| | yes | T' T' | T' T' | | -mlog + * (e) | N1 N0 | no no | N1 N0 | N1 N0 | P ->C | defer + * (f) | | yes | N1 N1' | N1 N1' | P ->C'| defer + * | | yes no | impossible + * (g) | | yes yes | T' N1' | T' N1' | | +mlog + * + * notes: + * (a) P,C maybe garbage. don't move either, but defer mlog incase P saved by a subsequent mutation; + * in that case C saved also, + will still have an xgen ptr, and still need an mlog entry. + * (b) C already evac'd, but P maybe garbage. defer mlog incase P rescued by a subsequent mutation; + * in that case will still have an xgen (T -> N) ptre, and still need an mlog entry. + * (b2) P,C already evac'd. Must update+rembexember xgen ptr {T -> N1} + * (c) P,C maybe garbage. don't move either, but defer mlog in case P saved by a subsequent mutation; + * in that case C promoted, no longer xgen + * (d) P maybe garbage. defer in case P saved by a subsequent mutation. + * C now tenured, so will no longer have an xgen pointer. + * (d2) P,C already evac'd. After collection no longer have xgen pointer, so no mlog. + * (e) P,C maybe garbage. don't move either, but defer mlog incase P saved by a subsequent mutation. + * in that case C saved alto, + will still have an xgen ptr, so still need an mlog entry + * (f) P maybe garbage, C survives. defer mlog incase P saved+promoted by a subsequent mutation; + * in that case will still have an xgen (T -> N) ptr, so still need an mlog entry. + * (g) P,C already evac'd. Still have xgen pointer, must mlog + */ + + std::size_t i_from = 0; + // number of rescued subgraphs via mutation log entries + std::size_t n_rescue = 0; + + for (MutationLogEntry & from_entry : *from_mlog) + { + log && (i_from % 10000 == 0) && log(xtag("i_from", i_from)); + + if (from_entry.is_parent_forwarded()) { + Object * parent_to = from_entry.parent_destination(); + + log && log(xtag("parent_to", (void*)parent_to)); + + assert(tospace_generation_of(parent_to) == generation_result::tenured); + + MutationLogEntry to_entry = from_entry.update_parent_moved(parent_to); + + // note: child obtained (as it must be) by reading from prarent's memory _now_. + // Since parent has moved, child has too + Object * child_to = to_entry.child(); // after moveing + + if (tospace_generation_of(parent_to) == generation_result::tenured) + { + // cases (b2)(d2)(g), loc(P) is T' + // In all these cases parent has already been moved; + // therefore child has also been moved. + // Just need to decide whether to keep mlog entry + + if (from_entry.is_dead()) { + // obsolete mutation -- no longer belongs to parent, discard + } else if (child_to) { + assert(!child_to->_is_forwarded()); + + if (tospace_generation_of(child_to) == generation_result::nursery) { + // case + // (b2) loc(P')=T', loc(C')=N1' --> +mlog + // (g) loc(P')=T', loc(C')=N1' --> +mlog + // + to_mlog->push_back(to_entry); + } else { + // case + // (d2) loc(P')=T', loc(C')=T' --> -mlog + } + } + } else { + // impossible - wouldn't have made mlog entry + + + assert(false); + } + } else { + // case + // (a) defer + // (b) defer + // (c) defer + // (d) defer + // (e) defer + // (f) defer + + defer_mlog->push_back(from_entry); + } + + ++i_from; + } + + from_mlog->clear(); + + if (n_rescue == 0) { + // if we didn't rescue any objects + // then we now confirm that otherwise-unreachable parents in defer_mlog + // are garbage + + defer_mlog->clear(); + } + } + + void GC::incremental_gc_forward_mlog(ObjectStatistics * per_type_stats) { @@ -703,7 +876,7 @@ namespace xo { * - gc roots have been copied, along with everything reachable from them. * * plan: - * - forward mutation in *from_mutation_log, writing them to + * - forward mutations in *from_mutation_log, writing them to * *to_mutationlog and/or *defer_mutation_log. * Use defer when mutation P->C encountered, but P was not copied. * P appears to be garbage, but may turn out to be live if encountered @@ -743,13 +916,52 @@ namespace xo { } } + void + GC::full_gc_forward_mlog(ObjectStatistics * per_type_stats) + { + /* control here: + * - full gc. + * - gc roots have been copied, along with everything reachable + * from them. + * + * plan: + * - forward mutations in *from_mutation_log, writing them to + * *to_mutation_log and/or *defer_mutation_log. + */ + + MutationLog * to_mlog = this->mutation_log(role::to_space); + + for (;;) { + MutationLog * from_mlog = this->mutation_log(role::from_space); + MutationLog * defer_mlog = defer_mutation_log_.get(); + + this->full_gc_forward_mlog_phase(from_mlog, + to_mlog, + defer_mlog, + per_type_stats); + assert(from_mlog->empty()); + + if (defer_mlog->empty()) + break; + + /* control here: + * 1. at least one mlog triggered a rescue + * 2. at least one mlog was deferred (had otherwise-unreachable parent) + * + * possible that deferred parent is now reachable thanks to a rescue; + * to confirm/refute this need to revisit entries in defer_mlog. + */ + std::swap(mutation_log_[role2int(role::from_space)], defer_mutation_log_); + } + } + void GC::forward_mutation_log(generation upto) { scope log(XO_DEBUG(config_.debug_flag_)); if (upto == generation::tenured) { - log && log("TODO: forward mutation log for full GC"); + this->full_gc_forward_mlog(&object_statistics_sae_[gen2int(generation::tenured)]); } else { this->incremental_gc_forward_mlog(&object_statistics_sae_[gen2int(generation::nursery)]); } @@ -874,7 +1086,7 @@ namespace xo { target = generation::tenured; if ((target == generation::nursery) - && (tenured_[role2int(role::to_space)]->after_checkpoint() > full_gc_threshold_)) + && (this->tenured_to()->after_checkpoint() > config_.full_gc_threshold_)) { /** full collection when >= @ref full_gc_threshold_ bytes added to tenured * generation, since last full collection From 279a1a040c6bdccf36553a5bc3b98236de56fd91 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Aug 2025 12:53:06 -0500 Subject: [PATCH 013/342] xo-callback xo-alloc: + GC copy callbacks + unique_ptr cbset support --- include/xo/alloc/GC.hpp | 28 ++++++++++++++++++++++++++++ src/alloc/CMakeLists.txt | 1 + src/alloc/GC.cpp | 20 ++++++++++++++++++-- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index a0bcef2b..64cf198d 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -7,6 +7,7 @@ #include "ListAlloc.hpp" #include "GcStatistics.hpp" +#include "xo/callback/UpCallbackSet.hpp" #include "xo/indentlog/print/array.hpp" #include #include @@ -105,12 +106,31 @@ namespace xo { using MutationLog = std::vector; + /** @class GcCopyCallback + * @brief optional callback to observe individual copy operations during GC + * + * For viz + **/ + class GcCopyCallback { + public: + virtual void notify_gc_copy(std::size_t z, const void * src_addr, const void * dest_addr, + generation src_gen, generation dest_gen) = 0; + /** invoked when added to callback set (i.e. @ref GC::GcCopyCallbackSet) **/ + void notify_add_callback() {} + /** invoked when removed from callback set **/ + void notify_remove_callback() {} + }; + /** @class GC * @brief generational garbage collector * * Works with objects of type @ref xo::Object **/ class GC : public IAlloc { + public: + using CallbackId = xo::fn::CallbackId; + using GcCopyCallbackSet = xo::fn::UpCallbackSet; + public: /** create new GC instance with configuration @p config **/ explicit GC(const Config & config); @@ -160,6 +180,11 @@ namespace xo { * from @c *addr **/ void add_gc_root(Object ** addr); + /** may optionally use this to observe GC copy phase. + * Will be invoked once _per surviving object_, so not cheap. + * Intended for GC visualization. + **/ + CallbackId add_gc_copy_callback(up fn); /** request garbage collection. **/ void request_gc(generation g); /** disable garbage collection until matching call to @ref enable_gc. @@ -335,6 +360,9 @@ namespace xo { /** enabled when 0. disabled when <0 **/ int gc_enabled_ = 0; + + /** for (optional) viz: invoke when copying individual objects **/ + GcCopyCallbackSet gc_copy_cbset_; }; } /*namespace gc*/ diff --git a/src/alloc/CMakeLists.txt b/src/alloc/CMakeLists.txt index 589f3b90..07f87784 100644 --- a/src/alloc/CMakeLists.txt +++ b/src/alloc/CMakeLists.txt @@ -15,5 +15,6 @@ set(SELF_SRCS xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) xo_dependency(${SELF_LIB} reflect) +xo_dependency(${SELF_LIB} callback) #end CMakeLists.txt diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index bcb8118b..d0aaa660 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -289,6 +289,12 @@ namespace xo { gc_root_v_.push_back(addr); } + auto + GC::add_gc_copy_callback(up fn) -> CallbackId + { + return gc_copy_cbset_.add_callback(std::move(fn)); + } + void GC::checkpoint() { @@ -322,16 +328,19 @@ namespace xo { { scope log(XO_DEBUG(config_.debug_flag_), xtag("z", z), xtag("+pad", IAlloc::alloc_padding(z))); - generation_result gr = this->fromspace_generation_of(src); + generation_result src_gr = this->fromspace_generation_of(src); std::byte * retval = nullptr; - switch (gr) { + switch (src_gr) { case generation_result::tenured: { log && log("tenured"); retval = this->tenured_to()->alloc(z); + + gc_copy_cbset_.invoke(&GcCopyCallback::notify_gc_copy, + z, src, retval, generation::tenured, generation::tenured); } break; case generation_result::nursery: @@ -347,11 +356,18 @@ namespace xo { assert(this->tospace_generation_of(retval) == generation_result::tenured); + gc_copy_cbset_.invoke(&GcCopyCallback::notify_gc_copy, + z, src, retval, generation::nursery, generation::tenured); + this->gc_statistics_.total_promoted_ += IAlloc::with_padding(z); + } else { log && log("nursery"); retval = this->nursery_to()->alloc(z); + + gc_copy_cbset_.invoke(&GcCopyCallback::notify_gc_copy, + z, src, retval, generation::nursery, generation::nursery); } } break; From 2ec50720922c6153656ef5914763c7cf0839b461 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Aug 2025 13:14:01 -0500 Subject: [PATCH 014/342] xo-alloc: alter GC to use LinearAlloc directly - retire ListAlloc --- include/xo/alloc/ArenaAlloc.hpp | 11 ++++++++--- include/xo/alloc/GC.hpp | 18 +++++++++--------- src/alloc/GC.cpp | 24 ++++++++++++------------ 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 63de43e8..64546cf3 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -28,15 +28,20 @@ namespace xo { ArenaAlloc(ArenaAlloc &&) = delete; ~ArenaAlloc(); - /** create allocator with capacity @p z, + /** Create allocator with capacity @p z, + * Reserve memory addresses for @p z bytes, + * but don't commit them until needed **/ static up make(const std::string & name, - std::size_t z, - bool debug_flag); + std::size_t z, + bool debug_flag); std::byte * free_ptr() const { return free_ptr_; } void set_free_ptr(std::byte * x); + /** Reset to empty state **/ + void reset(std::size_t /*z_ignored*/) { this->clear(); } + void capture_object_statistics(capture_phase phase, ObjectStatistics * p_dest) const; diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 64cf198d..a653b54b 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -5,7 +5,7 @@ #pragma once -#include "ListAlloc.hpp" +#include "ArenaAlloc.hpp" #include "GcStatistics.hpp" #include "xo/callback/UpCallbackSet.hpp" #include "xo/indentlog/print/array.hpp" @@ -240,14 +240,14 @@ namespace xo { virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; private: - ListAlloc * nursery_to() const { return nursery(role::to_space); } - ListAlloc * nursery_from() const { return nursery(role::from_space); } + ArenaAlloc * nursery_to() const { return nursery(role::to_space); } + ArenaAlloc * nursery_from() const { return nursery(role::from_space); } - ListAlloc * tenured_to() const { return tenured(role::to_space); } - ListAlloc * tenured_from() const { return tenured(role::from_space); } + ArenaAlloc * tenured_to() const { return tenured(role::to_space); } + ArenaAlloc * tenured_from() const { return tenured(role::from_space); } - ListAlloc * nursery(role r) const { return nursery_[role2int(r)].get(); } - ListAlloc * tenured(role r) const { return tenured_[role2int(r)].get(); } + ArenaAlloc * nursery(role r) const { return nursery_[role2int(r)].get(); } + ArenaAlloc * tenured(role r) const { return tenured_[role2int(r)].get(); } MutationLog * mutation_log(role r) const { return mutation_log_[role2int(r)].get(); } @@ -314,11 +314,11 @@ namespace xo { /** contains allocated objects, along with unreachable garbage to be collected. * roles reverse after each incremental, or full, collection. **/ - std::array, role2int(role::N)> nursery_; + std::array, role2int(role::N)> nursery_; /** empty space, destination for objects that survive collection. * roles reverse after each full collection. **/ - std::array, role2int(role::N)> tenured_; + std::array, role2int(role::N)> tenured_; /** current state of GC activity. * @text diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index d0aaa660..6ccc4d15 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -66,14 +66,14 @@ namespace xo { std::size_t tenured_size = config.initial_tenured_z_; nursery_[role2int(role::from_space)] - = ListAlloc::make("NA", nursery_size, 2 * nursery_size, config.debug_flag_); + = ArenaAlloc::make("NA", nursery_size, config.debug_flag_); nursery_[role2int(role::to_space) ] - = ListAlloc::make("NB", nursery_size, 2 * nursery_size, config.debug_flag_); + = ArenaAlloc::make("NB", nursery_size, config.debug_flag_); tenured_[role2int(role::from_space)] - = ListAlloc::make("TA", tenured_size, 2 * tenured_size, config.debug_flag_); + = ArenaAlloc::make("TA", tenured_size, config.debug_flag_); tenured_[role2int(role::to_space) ] - = ListAlloc::make("TB", tenured_size, 2 * tenured_size, config.debug_flag_); + = ArenaAlloc::make("TB", tenured_size, config.debug_flag_); mutation_log_[role2int(role::from_space)] = std::make_unique(); mutation_log_[role2int(role::to_space)] = std::make_unique(); @@ -444,7 +444,7 @@ namespace xo { void GC::swap_nursery() { - up tmp = std::move(nursery_[role2int(role::to_space)]); + up tmp = std::move(nursery_[role2int(role::to_space)]); nursery_[role2int(role::to_space)] = std::move(nursery_[role2int(role::from_space)]); nursery_[role2int(role::from_space)] = std::move(tmp); } @@ -452,7 +452,7 @@ namespace xo { void GC::swap_tenured() { - up tmp = std::move(tenured_[role2int(role::to_space)]); + up tmp = std::move(tenured_[role2int(role::to_space)]); tenured_[role2int(role::to_space)] = std::move(tenured_[role2int(role::from_space)]); tenured_[role2int(role::from_space)] = std::move(tmp); } @@ -496,9 +496,9 @@ namespace xo { log && log(xtag("avail_tenured_z", avail_tenured_z)); if (avail_tenured_z < max_promote_z) { - ListAlloc * tenured_to = this->tenured_to(); + ArenaAlloc * tenured_to = this->tenured_to(); - tenured_to->expand(max_promote_z, tenured_to->name() + "+"); + tenured_to->expand(max_promote_z); } } @@ -516,13 +516,13 @@ namespace xo { this->swap_mutation_log(); - ListAlloc * N_from = nursery(role::from_space); + ArenaAlloc * N_from = nursery(role::from_space); log && log(xtag("nursery.from", N_from->name()), xtag("size", N_from->size())); - ListAlloc * N_to = nursery(role::to_space); + ArenaAlloc * N_to = nursery(role::to_space); log && log(xtag("nursery.to", N_to->name()), xtag("size", N_to->size())); - ListAlloc * T_from = tenured(role::from_space); + ArenaAlloc * T_from = tenured(role::from_space); log && log(xtag("tenured.from", T_from->name()), xtag("size", T_from->size())); - ListAlloc * T_to = tenured(role::to_space); + ArenaAlloc * T_to = tenured(role::to_space); log && log(xtag("tenured.to", T_to->name()), xtag("size", T_to->size())); } /*swap_spaces*/ From 8fa254418a4c801f1d8d2b995279cb31d788db1e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 14 Aug 2025 09:50:59 -0500 Subject: [PATCH 015/342] xo-alloc: + gc history xo-imgui: gui examples --- include/xo/alloc/ArenaAlloc.hpp | 15 ++++ include/xo/alloc/GC.hpp | 28 +++++++ include/xo/alloc/GcStatistics.hpp | 66 +++++++++++++++++ include/xo/alloc/ListAlloc.hpp | 3 + include/xo/alloc/generation.hpp | 1 + src/alloc/ArenaAlloc.cpp | 12 +++ src/alloc/GC.cpp | 118 +++++++++++++++++++++++++++--- src/alloc/GcStatistics.cpp | 32 +++++++- src/alloc/ListAlloc.cpp | 17 ++++- utest/CMakeLists.txt | 1 + utest/GcStatistics.test.cpp | 4 +- utest/ListAlloc.test.cpp | 11 ++- 12 files changed, 290 insertions(+), 18 deletions(-) diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 64546cf3..66dd6a70 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -36,9 +36,24 @@ namespace xo { std::size_t z, bool debug_flag); + /** size of virtual address range reserved for this allocator **/ + std::size_t reserved() const { return this->size(); } + + std::size_t page_size() const { return page_z_; } std::byte * free_ptr() const { return free_ptr_; } void set_free_ptr(std::byte * x); + /** if address @p x is allocated from this arena, + * return true along with offset relative to base address @ref lo_ + * otherwise return false with 0 + **/ + std::pair location_of(const void * x) const; + + /** allocated span **/ + std::pair allocated_span() const { + return std::make_pair(lo_, free_ptr_); + } + /** Reset to empty state **/ void reset(std::size_t /*z_ignored*/) { this->clear(); } diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index a653b54b..ab58b902 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -50,6 +50,8 @@ namespace xo { bool allow_incremental_gc_ = true; /** true to report statistics **/ bool stats_flag_ = false; + /** remember basic gc statistics for this many GC's; separately for incremental + full GCs **/ + std::size_t stats_history_z_ = 256; /** true to enable debug logging **/ bool debug_flag_ = false; }; @@ -147,17 +149,24 @@ namespace xo { const GCRunstate & runstate() const { return runstate_; } const GcStatistics & native_gc_statistics() const { return gc_statistics_; } GcStatisticsExt get_gc_statistics() const; + const GcStatisticsHistory & gc_history() const { return gc_history_; } /** true iff GC permitted in current state **/ bool is_gc_enabled() const { return gc_enabled_ == 0; } /** true during (and only during) a GC cycle **/ bool gc_in_progress() const { return runstate_.in_progress(); } + /** @return reserved size of Nursery to-space **/ + std::size_t nursery_to_reserved() const; /** @return committed size of Nursery to-space **/ std::size_t nursery_to_committed() const; /** @return nursery bytes used before checkpoint **/ std::size_t nursery_before_checkpoint() const; /** @return nursery bytes used after checkpoint **/ std::size_t nursery_after_checkpoint() const; + /** @return allocated memory range for nursery **/ + std::pair nursery_span(role role) const; + /** @return reserved size of Tenured to-space **/ + std::size_t tenured_to_reserved() const; /** @return committed size of Tenured to-space **/ std::size_t tenured_to_committed() const; /** @return tenured bytes used before checkpoint **/ @@ -167,8 +176,24 @@ namespace xo { /** @return generation to which object at @p x belongs **/ generation_result tospace_generation_of(const void * x) const; + /** @return generation to which object at @p x belongs, + * location relative to base address for that generation, + * and allocated size of that generation + * @p role chooses between to-space and from-space + **/ + std::tuple location_of(role role, const void * x) const; + /** @return generation to which object at @p x belongs, + * location relative to base address for @p x, + * and allocated size of generation + **/ + std::tuple tospace_location_of(const void * x) const; /** @return generation that contains @p x, given it's in from-space **/ generation_result fromspace_generation_of(const void * x) const; + /** @return generation to which object at @p x belongs, + * location relative to base address for @p x, + * and allocated size of generation + **/ + std::tuple fromspace_location_of(const void * x) const; /** true iff from-space contains @p x **/ bool fromspace_contains(const void * x) const; /** @return free pointer for generation @p gen, i.e. nursery or tenured space **/ @@ -361,6 +386,9 @@ namespace xo { /** enabled when 0. disabled when <0 **/ int gc_enabled_ = 0; + /** rotating per-gc statistics history **/ + GcStatisticsHistory gc_history_; + /** for (optional) viz: invoke when copying individual objects **/ GcCopyCallbackSet gc_copy_cbset_; }; diff --git a/include/xo/alloc/GcStatistics.hpp b/include/xo/alloc/GcStatistics.hpp index 24cac461..d73f8947 100644 --- a/include/xo/alloc/GcStatistics.hpp +++ b/include/xo/alloc/GcStatistics.hpp @@ -6,6 +6,7 @@ #pragma once #include "generation.hpp" +#include "CircularBuffer.hpp" #include "xo/reflect/TypeDescr.hpp" #include "xo/indentlog/print/pretty.hpp" #include @@ -57,6 +58,8 @@ namespace xo { **/ class GcStatistics { public: + GcStatistics() = default; + /** update statistics after a GC cycle * @param upto. nursery -> incremental collection; tenured -> full collection * @param alloc_z. new allocations (since preceding GC) @@ -108,6 +111,7 @@ namespace xo { **/ class GcStatisticsExt : public GcStatistics { public: + GcStatisticsExt() = default; explicit GcStatisticsExt(const GcStatistics & x) : GcStatistics{x} {} /** @param os. write stats on this output stream **/ @@ -128,6 +132,63 @@ namespace xo { return os; } + /** @class GcStatisticsHistoryItem + * @brief info we want to record over time (won't have cumulative things in it) + **/ + class GcStatisticsHistoryItem { + public: + GcStatisticsHistoryItem() = default; + GcStatisticsHistoryItem(generation upto, + std::size_t new_alloc_z, + std::size_t survive_z, + std::size_t promote_z, + std::size_t persist_z, + std::size_t effort_z, + std::size_t garbage0_z, + std::size_t garbage1_z, + std::size_t garbageN_z) + : upto_{upto}, + new_alloc_z_{new_alloc_z}, + survive_z_{survive_z}, + promote_z_{promote_z}, + persist_z_{persist_z}, + effort_z_{effort_z}, + garbage0_z_{garbage0_z}, + garbage1_z_{garbage1_z}, + garbageN_z_{garbageN_z} + {} + + /** @param os. write stats on this output stream **/ + void display(std::ostream & os) const; + + /** type of GC that generated this record **/ + generation upto_; + /** #of bytes new allocation **/ + std::size_t new_alloc_z_ = 0; + /** #of bytes surviving their first collection (i.e. N0->N1) **/ + std::size_t survive_z_ = 0; + /** #of bytes promoted to tenured. + * Comprises all objects surviving their 2nd collection (i.e. N1->T) + **/ + std::size_t promote_z_ = 0; + /** #of bytes surviving 3rd of later collection **/ + std::size_t persist_z_ = 0; + /** #of bytes copied **/ + std::size_t effort_z_ = 0; + /** #of bytes garbage from N0 (i.e. survived 0 GCs) **/ + std::size_t garbage0_z_ = 0; + /** #of bytes garbage from N1 (i.e. survived 1 GCs) **/ + std::size_t garbage1_z_ = 0; + /** #of bytes garbage from T (i.e. survived 2+ GCs) **/ + std::size_t garbageN_z_ = 0; + }; + + inline std::ostream & operator<< (std::ostream & os, const GcStatisticsHistoryItem & x) { + x.display(os); + return os; + } + + using GcStatisticsHistory = CircularBuffer; } /*namespace gc*/ namespace print { @@ -145,6 +206,11 @@ namespace xo { struct ppdetail { static bool print_pretty(const ppindentinfo &, const xo::gc::GcStatisticsExt &); }; + + template<> + struct ppdetail { + static bool print_pretty(const ppindentinfo &, const xo::gc::GcStatisticsHistoryItem &); + }; } /*namespace print*/ } /*namespace xo*/ diff --git a/include/xo/alloc/ListAlloc.hpp b/include/xo/alloc/ListAlloc.hpp index 7b592b4e..75b148ac 100644 --- a/include/xo/alloc/ListAlloc.hpp +++ b/include/xo/alloc/ListAlloc.hpp @@ -34,6 +34,9 @@ namespace xo { static up make(const std::string & name, std::size_t cz, std::size_t nz, bool debug_flag); + /** page size used by underlying ArenaAlloc **/ + std::size_t page_size() const; + /** reset to have at least @p z bytes of storage **/ bool reset(std::size_t z); diff --git a/include/xo/alloc/generation.hpp b/include/xo/alloc/generation.hpp index 82c48808..2ed89276 100644 --- a/include/xo/alloc/generation.hpp +++ b/include/xo/alloc/generation.hpp @@ -30,6 +30,7 @@ namespace xo { tenured, not_found }; + } /*namespace gc*/ } /*namespace xo*/ diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index 49a2d16d..f3145bb2 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -113,6 +113,7 @@ namespace xo { } this->committed_z_ = align_offset_z; + this->limit_ = this->lo_ + committed_z_; return true; } @@ -133,6 +134,16 @@ namespace xo { } } + std::pair + ArenaAlloc::location_of(const void * x) const + { + if ((lo_ <= x) && (x < hi_)) { + return std::make_pair(true, reinterpret_cast(x) - lo_); + } else { + return std::make_pair(false, 0); + } + } + void ArenaAlloc::capture_object_statistics(capture_phase phase, ObjectStatistics * p_dest) const @@ -276,6 +287,7 @@ namespace xo { xtag("z0", z0), xtag("+pad", dz), xtag("z1", z1), + xtag("size", this->size()), xtag("avail", this->available())); this->free_ptr_ += z1; diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 6ccc4d15..a552ae1e 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -79,6 +79,8 @@ namespace xo { mutation_log_[role2int(role::to_space)] = std::make_unique(); defer_mutation_log_ = std::make_unique(); + this->gc_history_ = CircularBuffer(config.stats_history_z_); + this->checkpoint(); } @@ -191,6 +193,12 @@ namespace xo { return retval; } + std::size_t + GC::nursery_to_reserved() const + { + return nursery_to()->reserved(); + } + std::size_t GC::nursery_to_committed() const { @@ -209,6 +217,17 @@ namespace xo { return nursery_to()->after_checkpoint(); } + std::pair + GC::nursery_span(role role) const { + return nursery(role)->allocated_span(); + } + + std::size_t + GC::tenured_to_reserved() const + { + return tenured_to()->reserved(); + } + std::size_t GC::tenured_to_committed() const { @@ -239,6 +258,40 @@ namespace xo { return generation_result::not_found; } + std::tuple + GC::location_of(role role, const void *x) const + { + { + auto space = this->tenured(role); + auto [is_tenured, offset] = space->location_of(x); + + if (is_tenured) + return std::make_tuple(generation_result::tenured, offset, space->allocated()); + } + + { + auto space = this->nursery(role); + auto [is_nursery, offset] = nursery(role)->location_of(x); + + if (is_nursery) + return std::make_tuple(generation_result::nursery, offset, space->allocated()); + } + + return std::make_tuple(generation_result::not_found, 0, 0); + } + + std::tuple + GC::tospace_location_of(const void * x) const + { + return location_of(role::to_space, x); + } + + std::tuple + GC::fromspace_location_of(const void * x) const + { + return location_of(role::from_space, x); + } + generation_result GC::fromspace_generation_of(const void * x) const { @@ -988,8 +1041,11 @@ namespace xo { { scope log(XO_DEBUG(config_.debug_flag_)); - std::size_t N_allocated = nursery_from()->after_checkpoint(); - std::size_t T_allocated = tenured_from()->after_checkpoint(); + std::size_t N0_before_gc = nursery_from()->after_checkpoint(); + std::size_t N1_before_gc = nursery_from()->before_checkpoint(); + + std::size_t T0_before_gc = tenured_from()->after_checkpoint(); + std::size_t T1_before_gc = tenured_from()->before_checkpoint(); std::size_t N_before_gc = nursery_from()->allocated(); std::size_t T_before_gc = tenured_from()->allocated(); @@ -998,9 +1054,37 @@ namespace xo { std::size_t T_after_gc = tenured_to()->allocated(); //std::byte * N_free_ptr = nursery_[role2int(role::to_space)]->free_ptr(); + std::size_t new_alloc_z = N0_before_gc; + /* survive_z: bytes surviving first collection */ + std::size_t survive_z = N_after_gc; + /* promote_z: bytes surviving 2nd collection */ std::size_t promote_z = (gc_statistics_.total_promoted_ - gc_statistics_.total_promoted_sab_); + /* #of bytes copied by this collection cycle */ + std::size_t effort_z = 0; + if (upto == generation::nursery) { + effort_z = N_after_gc + promote_z; + } else { + effort_z += N_after_gc + T_after_gc; + } + + /* persist_z: bytes surviving 3rd or later collection */ + std::size_t persist_z = 0; + if (upto == generation::tenured) + persist_z = T_after_gc - promote_z; + /* #of bytes found to be garbage on first collection + * (reminder: N_after_gc consists *entirely* of survives from N0_before_gc; + * + all such survivors are in N_after_gc) + */ + std::size_t garbage0_z = (N0_before_gc - N_after_gc); + /* #of bytes found to be garbage on 2nd collection */ + std::size_t garbage1_z = (N1_before_gc - promote_z); + /* #of bytes found to be garbage on 3rd or later collection */ + std::size_t garbageN_z = 0; + if (upto == generation::tenured) + garbageN_z = (T_before_gc - T_after_gc + promote_z); + /* Don't reset from-space here, it's unnecessary. * Would be permissible, but interferes with GC object modelling in * xo-object/utest/GC.test.cpp @@ -1014,25 +1098,38 @@ namespace xo { this->tenured_to()->checkpoint(); if (log) { - log(xtag("N_allocated", N_allocated)); - log(xtag("N_before_gc", N_before_gc)); + log(xtag("N0_before_gc", N0_before_gc)); + log(xtag("N1_before_gc", N1_before_gc)); log(xtag("N_after_gc", N_after_gc)); - log(xtag("T_allocated", T_allocated)); - log(xtag("T_before_gc", T_before_gc)); + + log(xtag("T0_before_gc", T0_before_gc)); + log(xtag("T1_before_gc", T1_before_gc)); log(xtag("T_after_gc", T_after_gc)); } + GcStatisticsHistoryItem item(upto, + new_alloc_z, + survive_z, + promote_z, + persist_z, + effort_z, + garbage0_z, + garbage1_z, + garbageN_z); + + this->gc_history_.push_back(item); + this->incr_gc_pending_ = false; - this->gc_statistics_.include_gc(generation::nursery, N_allocated, N_before_gc, N_after_gc, promote_z); + this->gc_statistics_.include_gc(generation::nursery, N0_before_gc, N_before_gc, N_after_gc, promote_z); if (upto == generation::tenured) { this->full_gc_pending_ = false; - this->gc_statistics_.include_gc(generation::tenured, T_allocated, T_before_gc, T_after_gc, 0); + this->gc_statistics_.include_gc(generation::tenured, T0_before_gc, T_before_gc, T_after_gc, 0); } else { // still want to update tenured stats for current alloc size this->gc_statistics_.update_snapshot(generation::tenured, T_after_gc); } - } + } /*cleanup_phase*/ void GC::execute_gc(generation upto) @@ -1090,6 +1187,9 @@ namespace xo { this->runstate_ = GCRunstate(); + // not this way.. reports cumulative stats + // this->gc_history_.push_back(this->get_gc_statistics()); + log && log("statistics:"); log && log(gc_statistics_); } diff --git a/src/alloc/GcStatistics.cpp b/src/alloc/GcStatistics.cpp index 7b7a6ff9..cb7ebebf 100644 --- a/src/alloc/GcStatistics.cpp +++ b/src/alloc/GcStatistics.cpp @@ -92,6 +92,22 @@ namespace xo { // << xtag("per_type_stats", per_type_stats_) << ">"; } + + void + GcStatisticsHistoryItem::display(std::ostream & os) const + { + os << ""; + } + } /*namespace gc*/ namespace print { @@ -148,7 +164,21 @@ namespace xo { refrtag("tenured_z", x.tenured_z_)); } - + bool + ppdetail::print_pretty(const ppindentinfo & ppii, + const xo::gc::GcStatisticsHistoryItem & x) + { + return ppii.pps()->pretty_struct(ppii, + "GcStatisticsHistoryItem", + refrtag("upto", gen2str(x.upto_)), + refrtag("survive_z", x.survive_z_), + refrtag("promote_z", x.promote_z_), + refrtag("persist_z", x.persist_z_), + refrtag("effort_z", x.effort_z_), + refrtag("garbage0_z", x.garbage0_z_), + refrtag("garbage1_z", x.garbage1_z_), + refrtag("garbageN_z", x.garbageN_z_)); + } } /*namespace print*/ } /*namespace xo*/ diff --git a/src/alloc/ListAlloc.cpp b/src/alloc/ListAlloc.cpp index 29cdb477..8b0a2dbb 100644 --- a/src/alloc/ListAlloc.cpp +++ b/src/alloc/ListAlloc.cpp @@ -70,6 +70,11 @@ namespace xo { return s_default_name; } + std::size_t + ListAlloc::page_size() const { + return hd_->page_size(); + } + std::size_t ListAlloc::size() const { return total_z_; @@ -109,8 +114,9 @@ namespace xo { ListAlloc::allocated() const { std::size_t total = 0; - if (hd_) + if (hd_) { total += hd_->allocated(); + } for (const auto & alloc : full_l_) total += alloc->allocated(); @@ -363,10 +369,17 @@ namespace xo { ListAlloc::alloc(std::size_t z) { scope log(XO_DEBUG(debug_flag_)); + /* ArenaAlloc::alloc() may modify its own size */ + + std::size_t z_pre = hd_->size(); std::byte * retval = hd_->alloc(z); - if (retval) + if (retval) { + std::size_t z_post = hd_->size(); + this->total_z_ += (z_post - z_pre); + return retval; + } log && log("space exhausted -> expand"); diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 907bafcb..379ed925 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -12,6 +12,7 @@ set(UTEST_SRCS GcStatistics.test.cpp ObjectStatistics.test.cpp Forwarding1.test.cpp + CircularBuffer.test.cpp generation.test.cpp ) diff --git a/utest/GcStatistics.test.cpp b/utest/GcStatistics.test.cpp index 5f2fbe96..f5700f25 100644 --- a/utest/GcStatistics.test.cpp +++ b/utest/GcStatistics.test.cpp @@ -76,7 +76,7 @@ namespace xo { tag_config::tag_color_enabled = false; - GcStatisticsExt stats({}); + GcStatisticsExt stats; std::string s = tostr(stats); @@ -154,7 +154,7 @@ namespace xo { std::stringstream ss; ppconfig ppc; - GcStatisticsExt stats({}); + GcStatisticsExt stats; std::string actual = toppstr2(ppc, stats); std::string expected diff --git a/utest/ListAlloc.test.cpp b/utest/ListAlloc.test.cpp index 2db22bf2..0a62fd0b 100644 --- a/utest/ListAlloc.test.cpp +++ b/utest/ListAlloc.test.cpp @@ -12,7 +12,10 @@ namespace xo { namespace ut { TEST_CASE("ListAlloc", "[alloc][gc]") { - /** teeny weeny allocator **/ + /** teeny weeny allocator. + * but underlying ArenaAlloc works in multiples of VM page size + * (most likely 4k) + **/ up alloc = ListAlloc::make("test", 16, 32, false); REQUIRE(alloc->name() == "test"); @@ -24,7 +27,7 @@ namespace xo { std::byte * mem1 = alloc->alloc(20); REQUIRE(mem1); - REQUIRE(alloc->size() == 16 + 32); + REQUIRE(alloc->size() == alloc->page_size()); /* round up to multiple of 8 */ REQUIRE(alloc->before_checkpoint() == 24); REQUIRE(alloc->after_checkpoint() == 0); @@ -34,7 +37,7 @@ namespace xo { std::byte * mem2 = alloc->alloc(30); REQUIRE(mem2); - REQUIRE(alloc->size() == 16 + 32 + 48); + REQUIRE(alloc->size() == alloc->page_size()); REQUIRE(alloc->before_checkpoint() == 24); /* round up to multiple of 8 */ REQUIRE(alloc->after_checkpoint() == 32); @@ -42,7 +45,7 @@ namespace xo { std::byte * mem3 = alloc->alloc(40); REQUIRE(mem3); - REQUIRE(alloc->size() == 16 + 32 + 48 + 80); + REQUIRE(alloc->size() == alloc->page_size()); REQUIRE(alloc->before_checkpoint() == 24); /* already multiple of 8 */ REQUIRE(alloc->after_checkpoint() == 32 + 40); From df9ad3b8551c2d7528b07d011c3c3265fd60cf31 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 20 Aug 2025 19:53:37 -0500 Subject: [PATCH 016/342] missed files: xo-alloc/CircularBuffer --- include/xo/alloc/CircularBuffer.hpp | 245 ++++++++++++++++++++++++++++ utest/CircularBuffer.test.cpp | 174 ++++++++++++++++++++ 2 files changed, 419 insertions(+) create mode 100644 include/xo/alloc/CircularBuffer.hpp create mode 100644 utest/CircularBuffer.test.cpp diff --git a/include/xo/alloc/CircularBuffer.hpp b/include/xo/alloc/CircularBuffer.hpp new file mode 100644 index 00000000..cf1729ce --- /dev/null +++ b/include/xo/alloc/CircularBuffer.hpp @@ -0,0 +1,245 @@ +/* CircularBuffer.hpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#pragma once + +#include "xo/indentlog/scope.hpp" +#include "xo/indentlog/print/tostr.hpp" +#include "xo/indentlog/print/tag.hpp" +#include +#include +#include +//#include + +namespace xo { + namespace gc { + /** @class CircularBuffer + * @brief A circular buffer + * + * push operations may overwrite prior contents, + * i.e. buffer behavior on overflow + * old + * + * @tparam T is type for buffer elements. + **/ + template + class CircularBuffer { + public: + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = value_type &; + using const_reference = const value_type &; + using pointer = value_type *; + using const_pointer = const value_type *; + + template + class _iterator { + public: + using iterator_category = std::forward_iterator_tag; + using value_type = TT; + using difference_type = std::ptrdiff_t; + using pointer = value_type *; + using reference = value_type &; + + _iterator(Parent * p, std::int64_t ix) : parent_{p}, index_{ix} {} + + reference operator* () const { return (*parent_)[index_]; } + pointer operator->() const { return &(*parent_)[index_]; } + _iterator & operator++() { ++index_; return *this; } + _iterator operator++(int) { _iterator retval(parent_, index_); ++index_; return retval; } + + auto operator<=>(const _iterator & other) { + if (parent_ == other.parent_) + return index_ <=> other.index_; + else + return std::partial_ordering::unordered; + } + + bool operator==(const _iterator & other) const = default; + + private: + Parent * parent_ = nullptr; + /** index position + * (-1 = just before front = rend, 0 = front, z-1 = back, z = just after back = end) + **/ + std::int64_t index_ = 0; + }; + + using iterator = _iterator, T>; + using const_iterator = _iterator, const T>; + + public: + explicit CircularBuffer(std::size_t capacity = 0, bool debug_flag = false); + CircularBuffer(const CircularBuffer& other) = default; + CircularBuffer(CircularBuffer&& other) noexcept = default; + ~CircularBuffer() = default; + + static constexpr std::int64_t npos = -1; + + /** @return location of i'th element. i: 0=front, 1=second etc **/ + std::size_t location_of(std::size_t i) const; + /** @return ordinal index (relative to front) of location @p loc; + * npos if not used + **/ + //std::int64_t index_of(std::size_t loc) const; // not implemented yet + + // standard container methods + bool empty() const noexcept { return size_ == 0; } + size_type size() const noexcept { return size_; } + size_type max_size() const noexcept { return contents_.size(); } + // void reserve(size_type new_capacity); // not implemented + size_type capacity() const noexcept { return contents_.size(); } + // void shrink_to_fit(); // not implemented + + reference at(size_type pos) { + if ((pos < 0) || (pos >= size_)) { + throw std::out_of_range(tostr("CircularBuffer::at: index out of range", + xtag("pos", pos), xtag("size", size_))); + } + + return contents_[this->location_of(pos)]; + } + + const_reference at(size_type pos) const { + reference retval = const_cast(this)->at(pos); + return retval; + } + + reference operator[](size_type pos) { + return contents_[this->location_of(pos)]; + } + + const_reference operator[](size_type pos) const { + return contents_[this->location_of(pos)]; + } + + reference front() { return contents_[front_ix_]; } + const_reference front() const { + reference retval = const_cast(this)->front(); + return retval; + } + + reference back() { return contents_[location_of(size_ - 1)]; } + const_reference back() const { + reference retval = const_cast(this)->back(); + return retval; + } + + iterator begin() { return iterator(this, 0); } + iterator end() { return iterator(this, size_); } + const_iterator begin() const { return const_iterator(this, 0); } + const_iterator end() const { return const_iterator(this, size_); } + + // reverse_iterator rbegin(); + // reverse_iterator rend(); + // const_reverse_iterator rbegin() const; + // const_reverse_iterator rend() const; + + // General Methods + + void clear() { + size_ = 0; + front_ix_ = 0; + std::size_t capacity = contents_.size(); + contents_.clear(); + contents_.resize(capacity); + } + + /** push @p x on to the end of this buffer. + * If buffer is at capacity, overwrites the oldest element + **/ + CircularBuffer & push_back(const T & x); + + // template + //reference emplace_back(Args&&... args); + + CircularBuffer & pop_back(); + + // push_front(); + // pop_front(); + + CircularBuffer& operator=(const CircularBuffer& other) = default; + CircularBuffer& operator=(CircularBuffer&& other) noexcept = default; + + private: + /** number of elements in buffer. Not the same as @code contents_.size(); + * the latter represents buffer capacity. + * + * Promise: + * size_ <= contents_.size() + **/ + std::size_t size_ = 0; + /** first element is @code contents_.at(front_ix_) **/ + std::size_t front_ix_ = 0; + /** buffer contents. contents_.size() represents buffer capacity + * first element stored in @code contents_.at(front_) + * last element stored in @code contents_.at((front_ + size_ - 1) % contents_.size()) + **/ + std::vector contents_; + /** true to enable debug logging **/ + bool debug_flag_ = false; + }; + + template + CircularBuffer::CircularBuffer(std::size_t capacity, bool debug_flag) + : size_{0}, front_ix_{0}, contents_{capacity}, debug_flag_{debug_flag} + { + } + + template + std::size_t + CircularBuffer::location_of(std::size_t i) const + { + if (size_ == 0) + return 0; + else + return (front_ix_ + i) % size_; + } + + template + CircularBuffer & + CircularBuffer::push_back(const T & x) { + scope log(XO_DEBUG(debug_flag_), rtag("x", x), xrtag("size", size_)); + + if (size_ < contents_.size()) { + ++size_; + /* _after_ incr .size_ */ + std::size_t back_ix = location_of(size_ - 1); + + this->contents_[back_ix] = x; + + log && log(xtag("back_ix", back_ix), xtag("+size", size_)); + } else { + std::size_t back_ix = location_of(size_); + + this->contents_[back_ix] = x; + /* buffer was full, so oldest element replaced */ + this->front_ix_ = (this->front_ix_ + 1) % contents_.size(); + + log && log(xtag("back_ix", back_ix), xtag("+front", front_ix_)); + } + + return *this; + } + + template + CircularBuffer & + CircularBuffer::pop_back() { + if (size_ > 0) { + std::size_t back_ix = location_of(size_ - 1); + + this->contents_[back_ix] = T(); + --(this->size_); + } else { + assert(false); + } + + return *this; + } + } /*namespace gc*/ +} /*namespace xo*/ + +/* CircularBuffer.hpp */ diff --git a/utest/CircularBuffer.test.cpp b/utest/CircularBuffer.test.cpp new file mode 100644 index 00000000..f3d63c7e --- /dev/null +++ b/utest/CircularBuffer.test.cpp @@ -0,0 +1,174 @@ +/* CircularBuffer.test.cpp + * + * author: Roland Conybeare, Aug 2025 + */ + +#include "xo/alloc/CircularBuffer.hpp" +#include "xo/indentlog/print/vector.hpp" +#include + +namespace xo { + using xo::gc::CircularBuffer; + + namespace ut { + TEST_CASE("circular_buffer_0", "[circular_buffer]") + { + CircularBuffer q(10, false /*debug_flag*/); + q.push_back("a"); + REQUIRE(q.back() == "a"); + q.push_back("b"); + REQUIRE(q.back() == "b"); + q.push_back("c"); + REQUIRE(q.back() == "c"); + REQUIRE(q.location_of(0) == 0); + REQUIRE(q.location_of(1) == 1); + REQUIRE(q.location_of(2) == 2); + //REQUIRE(q.index_of(0) == 0); + + REQUIRE(q.size() == 3); + REQUIRE(q.front() == "a"); + REQUIRE(q.at(0) == "a"); + REQUIRE(q.at(1) == "b"); + REQUIRE(q.at(2) == "c"); + + CircularBuffer q2; + + q2 = q; + + q.clear(); + + REQUIRE(q2.size() == 3); + REQUIRE(q2.front() == "a"); + REQUIRE(q2.at(0) == "a"); + REQUIRE(q2.at(1) == "b"); + REQUIRE(q2.at(2) == "c"); + } + + TEST_CASE("circular_buffer_1", "[circular_buffer]") + { + CircularBuffer q(2, false /*debug_flag*/); + q.push_back("a"); + REQUIRE(q.back() == "a"); + q.push_back("b"); + REQUIRE(q.back() == "b"); + q.push_back("c"); + REQUIRE(q.back() == "c"); + REQUIRE(q.location_of(0) == 1); + REQUIRE(q.location_of(1) == 0); + //REQUIRE(q.index_of(0) == 0); + + REQUIRE(q.size() == 2); + REQUIRE(q.front() == "b"); + REQUIRE(q.at(0) == "b"); + REQUIRE(q.at(1) == "c"); + + { + std::size_t i = 0; + for (const auto & qi : q) { + REQUIRE(qi == q.at(i)); + ++i; + } + } + + CircularBuffer q2 = q; + + q.clear(); + + REQUIRE(q2.size() == 2); + REQUIRE(q2.front() == "b"); + REQUIRE(q2.at(0) == "b"); + REQUIRE(q2.at(1) == "c"); + + { + std::size_t i = 0; + for (const auto & qi : q) { + REQUIRE(qi == q2.at(i)); + ++i; + } + } + } + } + + namespace { + struct Testcase_CircularBuffer { + explicit Testcase_CircularBuffer(std::size_t capacity, + const std::vector & contents) + : capacity_{capacity}, + contents_{contents} {} + + std::size_t capacity_ = 0; + std::vector contents_; + }; + + std::vector + s_testcase_v = { + Testcase_CircularBuffer(0, {}), + Testcase_CircularBuffer(1, {"a"}), + Testcase_CircularBuffer(2, {"a", "b"}), + Testcase_CircularBuffer(2, {"a", "b", "c", "d"}) + }; + } + + namespace ut { + TEST_CASE("circular_buffer_2", "[circular_buffer]") + { + for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + const Testcase_CircularBuffer & tc = s_testcase_v[i_tc]; + + INFO(tostr(xtag("i_tc", i_tc), + xtag("capacity", tc.capacity_), + xrtag("contents", tc.contents_))); + + for (std::size_t j_phase = 0; j_phase < 2; ++j_phase) { + constexpr bool c_debug_flag = false; + + CircularBuffer q(tc.capacity_, false /*debug_flag*/); + + REQUIRE(q.empty()); + REQUIRE(q.size() == 0); + REQUIRE(q.begin() == q.end()); + REQUIRE(q.capacity() == tc.capacity_); + + std::size_t n = 0; + for (const auto & s : tc.contents_) { + INFO(tostr(xtag("n0", n), xtag("s", s))); + ++n; + INFO(xtag("n1", n)); + + q.push_back(s); + + REQUIRE(q.back() == s); + REQUIRE(q.capacity() == tc.capacity_); + REQUIRE(q.size() == std::min(n, tc.capacity_)); + + std::size_t i = 0; + for (const auto & qi : q) { + INFO(tostr(xtag("i", i), xtag("qi", qi))); + + if (n <= tc.capacity_) { + REQUIRE(qi == tc.contents_.at(i)); + REQUIRE(qi == tc.contents_[i]); + } else { + REQUIRE(qi == tc.contents_.at(n - tc.capacity_ + i)); + REQUIRE(qi == tc.contents_[n - tc.capacity_ + i]); + } + ++i; + } + + REQUIRE(i == std::min(n, tc.capacity_)); + + if (tc.contents_.size() <= tc.capacity_) + REQUIRE(q.front() == tc.contents_.at(0)); + } + + q.clear(); + + REQUIRE(q.size() == 0); + REQUIRE(q.capacity() == tc.capacity_); + } + } + } + } +} + +/* CircularBuffer.test.cpp */ From 78195b02185d80ac0e8b5c705d44fd7f35b670ce Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 22 Aug 2025 15:10:56 -0400 Subject: [PATCH 017/342] xo-alloc: + timing stats + timeseries tooltips --- include/xo/alloc/GC.hpp | 5 ++- include/xo/alloc/GcStatistics.hpp | 75 +++++++++++++++++++++++-------- src/alloc/CMakeLists.txt | 1 + src/alloc/GC.cpp | 55 +++++++++++++++-------- src/alloc/GcStatistics.cpp | 14 +++++- 5 files changed, 110 insertions(+), 40 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index ab58b902..7c4f42c6 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -132,6 +132,7 @@ namespace xo { public: using CallbackId = xo::fn::CallbackId; using GcCopyCallbackSet = xo::fn::UpCallbackSet; + using nanos = decltype(xo::qty::qty::nanosecond); public: /** create new GC instance with configuration @p config **/ @@ -224,6 +225,8 @@ namespace xo { * as number of calls to @ref disable_gc. **/ void enable_gc(); + /** same as @c this->enable_gc() followed by @c this->disable_gc() **/ + void enable_gc_once(); // inherited from IAlloc.. @@ -279,7 +282,7 @@ namespace xo { /** begin GC now **/ void execute_gc(generation g); /** cleanup phase. aux function for @ref execute_gc **/ - void cleanup_phase(generation g); + void cleanup_phase(generation g, nanos dt); /** swap roles of From/To spaces for nursery generation **/ void swap_nursery(); /** swap roles of From/To spaces for tenured generation **/ diff --git a/include/xo/alloc/GcStatistics.hpp b/include/xo/alloc/GcStatistics.hpp index d73f8947..d0f54084 100644 --- a/include/xo/alloc/GcStatistics.hpp +++ b/include/xo/alloc/GcStatistics.hpp @@ -8,6 +8,8 @@ #include "generation.hpp" #include "CircularBuffer.hpp" #include "xo/reflect/TypeDescr.hpp" +#include "xo/unit/quantity.hpp" +#include "xo/unit/quantity_iostream.hpp" #include "xo/indentlog/print/pretty.hpp" #include #include @@ -60,6 +62,13 @@ namespace xo { public: GcStatistics() = default; + /** update statistics at beginning of a GC cycle + * @param upto. nursery -> incremental collection; tenured -> full collection + * @param alloc_z. new allocations (since preceding GC) + **/ + void begin_gc(generation upto, + std::size_t alloc_z); + /** update statistics after a GC cycle * @param upto. nursery -> incremental collection; tenured -> full collection * @param alloc_z. new allocations (since preceding GC) @@ -74,6 +83,9 @@ namespace xo { **/ void update_snapshot(generation upto, std::size_t after_z); + /** number of collection cycles, whether full or incremental **/ + std::size_t n_gc() const { return gen_v_[gen2int(generation::nursery)].n_gc_; } + /** @param os. write stats on this output stream **/ void display(std::ostream & os) const; @@ -136,31 +148,54 @@ namespace xo { * @brief info we want to record over time (won't have cumulative things in it) **/ class GcStatisticsHistoryItem { + public: + using nanos = xo::qty::type::nanoseconds; + public: GcStatisticsHistoryItem() = default; - GcStatisticsHistoryItem(generation upto, - std::size_t new_alloc_z, - std::size_t survive_z, - std::size_t promote_z, - std::size_t persist_z, - std::size_t effort_z, - std::size_t garbage0_z, - std::size_t garbage1_z, - std::size_t garbageN_z) - : upto_{upto}, - new_alloc_z_{new_alloc_z}, - survive_z_{survive_z}, - promote_z_{promote_z}, - persist_z_{persist_z}, - effort_z_{effort_z}, - garbage0_z_{garbage0_z}, - garbage1_z_{garbage1_z}, - garbageN_z_{garbageN_z} - {} + constexpr GcStatisticsHistoryItem(std::size_t gc_seq, + generation upto, + std::size_t new_alloc_z, + std::size_t survive_z, + std::size_t promote_z, + std::size_t persist_z, + std::size_t effort_z, + std::size_t garbage0_z, + std::size_t garbage1_z, + std::size_t garbageN_z, + nanos dt) : gc_seq_{gc_seq}, + upto_{upto}, + new_alloc_z_{new_alloc_z}, + survive_z_{survive_z}, + promote_z_{promote_z}, + persist_z_{persist_z}, + effort_z_{effort_z}, + garbage0_z_{garbage0_z}, + garbage1_z_{garbage1_z}, + garbageN_z_{garbageN_z}, + dt_{dt} {} + constexpr GcStatisticsHistoryItem(const GcStatisticsHistoryItem &) = default; + + GcStatisticsHistoryItem & operator=(const GcStatisticsHistoryItem & x) { + gc_seq_ = x.gc_seq_; + upto_ = x.upto_; + new_alloc_z_ = x.new_alloc_z_; + survive_z_ = x.survive_z_; + promote_z_ = x.promote_z_; + persist_z_ = x.persist_z_; + effort_z_ = x.effort_z_; + garbage0_z_ = x.garbage0_z_; + garbage1_z_ = x.garbage1_z_; + garbageN_z_ = x.garbageN_z_; + this->dt_.scale_ = x.dt_.scale_; + return *this; + } /** @param os. write stats on this output stream **/ void display(std::ostream & os) const; + /** sequence number for collection being reported **/ + std::size_t gc_seq_ = 0; /** type of GC that generated this record **/ generation upto_; /** #of bytes new allocation **/ @@ -181,6 +216,8 @@ namespace xo { std::size_t garbage1_z_ = 0; /** #of bytes garbage from T (i.e. survived 2+ GCs) **/ std::size_t garbageN_z_ = 0; + /** elapsed time for this GC (see @ref GC::execute_gc) **/ + nanos dt_; }; inline std::ostream & operator<< (std::ostream & os, const GcStatisticsHistoryItem & x) { diff --git a/src/alloc/CMakeLists.txt b/src/alloc/CMakeLists.txt index 07f87784..b83e2618 100644 --- a/src/alloc/CMakeLists.txt +++ b/src/alloc/CMakeLists.txt @@ -14,6 +14,7 @@ set(SELF_SRCS ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) +xo_dependency(${SELF_LIB} xo_unit) xo_dependency(${SELF_LIB} reflect) xo_dependency(${SELF_LIB} callback) diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index a552ae1e..e6fb188f 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -7,6 +7,7 @@ #include "GC.hpp" #include "Object.hpp" #include "xo/indentlog/scope.hpp" +#include #include #include @@ -1037,9 +1038,9 @@ namespace xo { } void - GC::cleanup_phase(generation upto) + GC::cleanup_phase(generation upto, nanos dt) { - scope log(XO_DEBUG(config_.debug_flag_)); + scope log(XO_DEBUG(config_.stats_flag_)); std::size_t N0_before_gc = nursery_from()->after_checkpoint(); std::size_t N1_before_gc = nursery_from()->before_checkpoint(); @@ -1098,6 +1099,7 @@ namespace xo { this->tenured_to()->checkpoint(); if (log) { + log(xtag("gcseq_before_gc", gc_statistics_.n_gc())); log(xtag("N0_before_gc", N0_before_gc)); log(xtag("N1_before_gc", N1_before_gc)); log(xtag("N_after_gc", N_after_gc)); @@ -1107,18 +1109,6 @@ namespace xo { log(xtag("T_after_gc", T_after_gc)); } - GcStatisticsHistoryItem item(upto, - new_alloc_z, - survive_z, - promote_z, - persist_z, - effort_z, - garbage0_z, - garbage1_z, - garbageN_z); - - this->gc_history_.push_back(item); - this->incr_gc_pending_ = false; this->gc_statistics_.include_gc(generation::nursery, N0_before_gc, N_before_gc, N_after_gc, promote_z); @@ -1129,6 +1119,23 @@ namespace xo { // still want to update tenured stats for current alloc size this->gc_statistics_.update_snapshot(generation::tenured, T_after_gc); } + GcStatisticsHistoryItem item(gc_statistics_.n_gc(), + upto, + new_alloc_z, + survive_z, + promote_z, + persist_z, + effort_z, + garbage0_z, + garbage1_z, + garbageN_z, + dt); + + log && log(xtag("gcseq_after_gc", gc_statistics_.n_gc()), + xtag("item", item)); + + this->gc_history_.push_back(item); + } /*cleanup_phase*/ void @@ -1136,6 +1143,8 @@ namespace xo { { scope log(XO_DEBUG(config_.stats_flag_)); + auto t0 = std::chrono::steady_clock::now(); + bool full_move = (upto == generation::tenured); // TODO: RAII version in case of exceptions @@ -1146,9 +1155,7 @@ namespace xo { /* new allocation since last GC */ std::size_t new_alloc = this->after_checkpoint(); - ++(gc_statistics_.gen_v_[static_cast(upto)].n_gc_); - gc_statistics_.total_allocated_ += new_alloc; - gc_statistics_.total_promoted_sab_ = gc_statistics_.total_promoted_; + gc_statistics_.begin_gc(upto, new_alloc); log && log(xtag("new_alloc", new_alloc)); @@ -1176,10 +1183,13 @@ namespace xo { log && log("step 6 : cleanup"); - this->cleanup_phase(upto); - this->capture_object_statistics(upto, capture_phase::sae); + auto t1 = std::chrono::steady_clock::now(); + auto dt = std::chrono::duration_cast(t1 - t0); + + this->cleanup_phase(upto, xo::qty::qty::nanoseconds(dt.count())); + log && log("object statistics [nursery]:"); log && log(refrtag("stats", object_statistics_sab_[gen2int(generation::nursery)])); log && log("object statistics [tenured]:"); @@ -1233,6 +1243,13 @@ namespace xo { this->request_gc(full_gc_pending_ ? generation::tenured : generation::nursery); } } + + void + GC::enable_gc_once() { + this->enable_gc(); + this->disable_gc(); + } + } /*namespace gc*/ } /*namespace xo*/ diff --git a/src/alloc/GcStatistics.cpp b/src/alloc/GcStatistics.cpp index cb7ebebf..72624403 100644 --- a/src/alloc/GcStatistics.cpp +++ b/src/alloc/GcStatistics.cpp @@ -16,6 +16,7 @@ namespace xo { { this->update_snapshot(after_z); + //++n_gc_; new_alloc_z_ += alloc_z; scanned_z_ += before_z; survive_z_ += after_z; @@ -41,6 +42,15 @@ namespace xo { << ">"; } + void + GcStatistics::begin_gc(generation upto, + std::size_t new_alloc) + { + ++(this->gen_v_[static_cast(upto)].n_gc_); + this->total_allocated_ += new_alloc; + this->total_promoted_sab_ = total_promoted_; + } + void GcStatistics::include_gc(generation upto, std::size_t alloc_z, @@ -105,6 +115,7 @@ namespace xo { << xrtag("garbage0_z", garbage0_z_) << xrtag("garbage1_z", garbage1_z_) << xrtag("garbageN_z", garbageN_z_) + << xrtag("dt", dt_) << ">"; } @@ -177,7 +188,8 @@ namespace xo { refrtag("effort_z", x.effort_z_), refrtag("garbage0_z", x.garbage0_z_), refrtag("garbage1_z", x.garbage1_z_), - refrtag("garbageN_z", x.garbageN_z_)); + refrtag("garbageN_z", x.garbageN_z_), + refrtag("dt", x.dt_)); } } /*namespace print*/ } /*namespace xo*/ From d751093a87021e99ec655d0e29dd46d1801229d9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 23 Aug 2025 10:47:52 -0400 Subject: [PATCH 018/342] xo-imgui: ex2: animate GC copy step --- include/xo/alloc/GC.hpp | 12 +++++++++--- include/xo/alloc/generation.hpp | 10 ++++++++++ src/alloc/GC.cpp | 13 +++++++++---- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 7c4f42c6..8ddb3e23 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -154,6 +154,8 @@ namespace xo { /** true iff GC permitted in current state **/ bool is_gc_enabled() const { return gc_enabled_ == 0; } + /** true iff GC has been requested **/ + bool is_gc_pending() const { return incr_gc_pending_ || full_gc_pending_; } /** true during (and only during) a GC cycle **/ bool gc_in_progress() const { return runstate_.in_progress(); } /** @return reserved size of Nursery to-space **/ @@ -223,10 +225,14 @@ namespace xo { * * GC is enabled when number of calls to @ref enable_gc is at least as large * as number of calls to @ref disable_gc. + * + * @return true iff GC performed **/ - void enable_gc(); - /** same as @c this->enable_gc() followed by @c this->disable_gc() **/ - void enable_gc_once(); + bool enable_gc(); + /** same as @c this->enable_gc() followed by @c this->disable_gc() + * @return true iff GC performed + **/ + bool enable_gc_once(); // inherited from IAlloc.. diff --git a/include/xo/alloc/generation.hpp b/include/xo/alloc/generation.hpp index 2ed89276..0acd943a 100644 --- a/include/xo/alloc/generation.hpp +++ b/include/xo/alloc/generation.hpp @@ -7,6 +7,7 @@ #include #include +#include namespace xo { namespace gc { @@ -31,6 +32,15 @@ namespace xo { not_found }; + inline generation valid_genresult2gen(generation_result x) { + assert(x != generation_result::not_found); + + if (x == generation_result::nursery) + return generation::nursery; + else + return generation::tenured; + } + } /*namespace gc*/ } /*namespace xo*/ diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index e6fb188f..200ac218 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -1233,21 +1233,26 @@ namespace xo { --gc_enabled_; } - void + bool GC::enable_gc() { ++gc_enabled_; if (gc_enabled_ == 0) { /* unblock gc */ - if (incr_gc_pending_) + if (incr_gc_pending_) { this->request_gc(full_gc_pending_ ? generation::tenured : generation::nursery); + return true; + } } + + return false; } - void + bool GC::enable_gc_once() { - this->enable_gc(); + bool retval = this->enable_gc(); this->disable_gc(); + return retval; } } /*namespace gc*/ From 0a19c8b043a07a435f33a4d7b3c0bf904f354fe1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 23 Aug 2025 13:09:59 -0400 Subject: [PATCH 019/342] xo-alloc: track GC efficiency --- include/xo/alloc/GcStatistics.hpp | 11 +++++++++++ src/alloc/GcStatistics.cpp | 17 +++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/xo/alloc/GcStatistics.hpp b/include/xo/alloc/GcStatistics.hpp index d0f54084..c0058b5f 100644 --- a/include/xo/alloc/GcStatistics.hpp +++ b/include/xo/alloc/GcStatistics.hpp @@ -176,6 +176,17 @@ namespace xo { dt_{dt} {} constexpr GcStatisticsHistoryItem(const GcStatisticsHistoryItem &) = default; + std::size_t garbage_z() const { return garbage0_z_ + garbage1_z_ + garbageN_z_; } + + float efficiency() const { + std::size_t gz = this->garbage_z(); + + return gz / static_cast(effort_z_ + gz); + } + + /** collection rate, in bytes/sec **/ + float collection_rate() const; + GcStatisticsHistoryItem & operator=(const GcStatisticsHistoryItem & x) { gc_seq_ = x.gc_seq_; upto_ = x.upto_; diff --git a/src/alloc/GcStatistics.cpp b/src/alloc/GcStatistics.cpp index 72624403..deb30685 100644 --- a/src/alloc/GcStatistics.cpp +++ b/src/alloc/GcStatistics.cpp @@ -103,6 +103,23 @@ namespace xo { << ">"; } + float + GcStatisticsHistoryItem::collection_rate() const { + using namespace xo::qty::qty; + + float gz = this->garbage_z(); + + auto dt_nanos = this->dt_.with_repr(); + auto dt_sec = dt_nanos.rescale_ext(); + auto rate = gz / dt_sec; + float retval = rate.scale(); + + //scope log(XO_DEBUG(true)); + //log && log(xtag("gz", gz), xtag("dt_sec", dt_sec), xtag("rate", rate), xtag("rate/sec", retval)); + + return retval; + } + void GcStatisticsHistoryItem::display(std::ostream & os) const { From 4c824edbe46ed29678a5f5c63b1fc95036b98042 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 24 Aug 2025 17:03:04 -0400 Subject: [PATCH 020/342] xo-imgui: ex2: + average efficiency + plot --- include/xo/alloc/GcStatistics.hpp | 44 +++++++++++++++++++++++-------- src/alloc/GC.cpp | 13 ++++++++- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/include/xo/alloc/GcStatistics.hpp b/include/xo/alloc/GcStatistics.hpp index c0058b5f..b591bf22 100644 --- a/include/xo/alloc/GcStatistics.hpp +++ b/include/xo/alloc/GcStatistics.hpp @@ -163,17 +163,23 @@ namespace xo { std::size_t garbage0_z, std::size_t garbage1_z, std::size_t garbageN_z, - nanos dt) : gc_seq_{gc_seq}, - upto_{upto}, - new_alloc_z_{new_alloc_z}, - survive_z_{survive_z}, - promote_z_{promote_z}, - persist_z_{persist_z}, - effort_z_{effort_z}, - garbage0_z_{garbage0_z}, - garbage1_z_{garbage1_z}, - garbageN_z_{garbageN_z}, - dt_{dt} {} + nanos dt, + std::size_t sum_effort_z, + std::size_t sum_garbage_z) + : gc_seq_{gc_seq}, + upto_{upto}, + new_alloc_z_{new_alloc_z}, + survive_z_{survive_z}, + promote_z_{promote_z}, + persist_z_{persist_z}, + effort_z_{effort_z}, + garbage0_z_{garbage0_z}, + garbage1_z_{garbage1_z}, + garbageN_z_{garbageN_z}, + dt_{dt}, + sum_effort_z_{sum_effort_z}, + sum_garbage_z_{sum_garbage_z} + {} constexpr GcStatisticsHistoryItem(const GcStatisticsHistoryItem &) = default; std::size_t garbage_z() const { return garbage0_z_ + garbage1_z_ + garbageN_z_; } @@ -184,6 +190,11 @@ namespace xo { return gz / static_cast(effort_z_ + gz); } + /** lifetime byte-weighted average collection efficiency. Always in [0.0, 1.0] **/ + float average_efficiency() const { + return sum_garbage_z_ / static_cast(sum_effort_z_ + sum_garbage_z_); + } + /** collection rate, in bytes/sec **/ float collection_rate() const; @@ -199,6 +210,10 @@ namespace xo { garbage1_z_ = x.garbage1_z_; garbageN_z_ = x.garbageN_z_; this->dt_.scale_ = x.dt_.scale_; + + sum_effort_z_ = x.sum_effort_z_; + sum_garbage_z_ = x.sum_garbage_z_; + return *this; } @@ -229,6 +244,13 @@ namespace xo { std::size_t garbageN_z_ = 0; /** elapsed time for this GC (see @ref GC::execute_gc) **/ nanos dt_; + + // ----- cumulative statistics ----- + + /** sum (in bytes) copied by collections since inception **/ + std::size_t sum_effort_z_ = 0; + /** sum (in bytes) of garbage collected since inception **/ + std::size_t sum_garbage_z_ = 0; }; inline std::ostream & operator<< (std::ostream & os, const GcStatisticsHistoryItem & x) { diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 200ac218..1b5481cb 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -1119,6 +1119,15 @@ namespace xo { // still want to update tenured stats for current alloc size this->gc_statistics_.update_snapshot(generation::tenured, T_after_gc); } + + std::size_t sum_effort_z = effort_z; + std::size_t sum_garbage_z = garbage0_z + garbage1_z + garbageN_z; + + if (gc_history_.size() > 0) { + sum_effort_z += gc_history_.back().sum_effort_z_; + sum_garbage_z += gc_history_.back().sum_garbage_z_; + } + GcStatisticsHistoryItem item(gc_statistics_.n_gc(), upto, new_alloc_z, @@ -1129,7 +1138,9 @@ namespace xo { garbage0_z, garbage1_z, garbageN_z, - dt); + dt, + sum_effort_z, + sum_garbage_z); log && log(xtag("gcseq_after_gc", gc_statistics_.n_gc()), xtag("item", item)); From a9563204706635cc7fe3dee9014c1991899a2e03 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 25 Aug 2025 16:09:18 -0400 Subject: [PATCH 021/342] xo-imgui: ex: display both from+to spaces + refactor&streamline --- include/xo/alloc/GC.hpp | 9 +++++++++ src/alloc/GC.cpp | 2 ++ 2 files changed, 11 insertions(+) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 8ddb3e23..1e55c497 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -147,6 +147,8 @@ namespace xo { static up make(const Config & config); const Config & config() const { return config_; } + std::uint8_t nursery_polarity() const { return nursery_polarity_; } + std::uint8_t tenured_polarity() const { return tenured_polarity_; } const GCRunstate & runstate() const { return runstate_; } const GcStatistics & native_gc_statistics() const { return gc_statistics_; } GcStatisticsExt get_gc_statistics() const; @@ -345,6 +347,13 @@ namespace xo { /** garbage collector configuration **/ Config config_; + /** keep track of the identity of from-space and to-space. + * assist for animation (see xo-imgui/example/ex2). + * polarity alternates between 0 and 1 on each GC + **/ + std::uint8_t nursery_polarity_ = 0; + std::uint8_t tenured_polarity_ = 0; + /** contains allocated objects, along with unreachable garbage to be collected. * roles reverse after each incremental, or full, collection. **/ diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 1b5481cb..5f75c2a0 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -501,6 +501,7 @@ namespace xo { up tmp = std::move(nursery_[role2int(role::to_space)]); nursery_[role2int(role::to_space)] = std::move(nursery_[role2int(role::from_space)]); nursery_[role2int(role::from_space)] = std::move(tmp); + nursery_polarity_ = 1 - nursery_polarity_; } void @@ -509,6 +510,7 @@ namespace xo { up tmp = std::move(tenured_[role2int(role::to_space)]); tenured_[role2int(role::to_space)] = std::move(tenured_[role2int(role::from_space)]); tenured_[role2int(role::from_space)] = std::move(tmp); + tenured_polarity_ = 1 - tenured_polarity_; } void From 6c7b13e44327c668e6aa9000f551d03315576a66 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 26 Aug 2025 13:36:18 -0400 Subject: [PATCH 022/342] xo-alloc: try to make commit happen at start of GC cycle --- include/xo/alloc/ArenaAlloc.hpp | 8 +-- include/xo/alloc/GC.hpp | 27 +++++++--- src/alloc/ArenaAlloc.cpp | 6 +++ src/alloc/GC.cpp | 88 ++++++++++++++++++--------------- 4 files changed, 79 insertions(+), 50 deletions(-) diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 66dd6a70..11fcdb72 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -54,13 +54,15 @@ namespace xo { return std::make_pair(lo_, free_ptr_); } - /** Reset to empty state **/ - void reset(std::size_t /*z_ignored*/) { this->clear(); } + /** Reset to empty state; provision at least @p need_z bytes of (committed) space **/ + void reset(std::size_t need_z); void capture_object_statistics(capture_phase phase, ObjectStatistics * p_dest) const; - /** expand available (i.e. committed) space to size @p z **/ + /** expand available (i.e. committed) space to size at least @p z + * In practice will round up to a multiple of @ref page_z_ + **/ bool expand(std::size_t z); // inherited from IAlloc... diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 1e55c497..d145e2c7 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -33,12 +33,16 @@ namespace xo { struct Config { /** initial size in bytes for youngest (Nursery) generation. * GC allocates two nursery spaces of this size. - * Will allocate more space as needed + * This number represents reserved address space. + * pages are committed on demand. + * Initial committment will be up to @ref incr_gc_threshold_ **/ std::size_t initial_nursery_z_ = 0; /** initial size in bytes for oldest (Tenured) generation. - * GC allocates two tenured spaces of this size - * Will allocate more space as needed + * GC allocates two tenured spaces of this size. + * This number represents reserved address space. + * pages are committed on demand. + * Initial committment will be up to @ref full_gc_threshold_ **/ std::size_t initial_tenured_z_ = 0; /** trigger incremental GC after this many bytes allocated in nursery **/ @@ -158,6 +162,8 @@ namespace xo { bool is_gc_enabled() const { return gc_enabled_ == 0; } /** true iff GC has been requested **/ bool is_gc_pending() const { return incr_gc_pending_ || full_gc_pending_; } + /** true iff full GC pending **/ + bool is_full_gc_pending() const { return full_gc_pending_; } /** true during (and only during) a GC cycle **/ bool gc_in_progress() const { return runstate_.in_progress(); } /** @return reserved size of Nursery to-space **/ @@ -170,6 +176,10 @@ namespace xo { std::size_t nursery_after_checkpoint() const; /** @return allocated memory range for nursery **/ std::pair nursery_span(role role) const; + /** @return nursery bytes used in from-space + * (only interesting during GC copy phase, e.g. during scope of a GcCopyCallback call) + **/ + std::size_t nursery_from_allocated() const; /** @return reserved size of Tenured to-space **/ std::size_t tenured_to_reserved() const; /** @return committed size of Tenured to-space **/ @@ -186,19 +196,19 @@ namespace xo { * and allocated size of that generation * @p role chooses between to-space and from-space **/ - std::tuple location_of(role role, const void * x) const; + std::tuple location_of(role role, const void * x) const; /** @return generation to which object at @p x belongs, * location relative to base address for @p x, * and allocated size of generation **/ - std::tuple tospace_location_of(const void * x) const; + std::tuple tospace_location_of(const void * x) const; /** @return generation that contains @p x, given it's in from-space **/ generation_result fromspace_generation_of(const void * x) const; /** @return generation to which object at @p x belongs, * location relative to base address for @p x, * and allocated size of generation **/ - std::tuple fromspace_location_of(const void * x) const; + std::tuple fromspace_location_of(const void * x) const; /** true iff from-space contains @p x **/ bool fromspace_contains(const void * x) const; /** @return free pointer for generation @p gen, i.e. nursery or tenured space **/ @@ -215,7 +225,10 @@ namespace xo { * Intended for GC visualization. **/ CallbackId add_gc_copy_callback(up fn); - /** request garbage collection. **/ + /** request garbage collection. + * If GC currently disabled, collection will be deferred until the next time GC + * is in an enabled state. See @ref disable_gc and @ref enable_gc + **/ void request_gc(generation g); /** disable garbage collection until matching call to @ref enable_gc. * diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index f3145bb2..9703d103 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -144,6 +144,12 @@ namespace xo { } } + void + ArenaAlloc::reset(std::size_t need_z) { + this->clear(); + this->expand(need_z); + } + void ArenaAlloc::capture_object_statistics(capture_phase phase, ObjectStatistics * p_dest) const diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 5f75c2a0..7d18da57 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -68,16 +68,23 @@ namespace xo { nursery_[role2int(role::from_space)] = ArenaAlloc::make("NA", nursery_size, config.debug_flag_); + nursery_[role2int(role::to_space) ] = ArenaAlloc::make("NB", nursery_size, config.debug_flag_); tenured_[role2int(role::from_space)] = ArenaAlloc::make("TA", tenured_size, config.debug_flag_); + tenured_[role2int(role::to_space) ] = ArenaAlloc::make("TB", tenured_size, config.debug_flag_); + nursery_[role2int(role::from_space)]->expand(config.incr_gc_threshold_); + nursery_[role2int(role::to_space) ]->expand(config.incr_gc_threshold_); + tenured_[role2int(role::from_space)]->expand(config.full_gc_threshold_); + tenured_[role2int(role::to_space) ]->expand(config.full_gc_threshold_); + mutation_log_[role2int(role::from_space)] = std::make_unique(); - mutation_log_[role2int(role::to_space)] = std::make_unique(); + mutation_log_[role2int(role::to_space )] = std::make_unique(); defer_mutation_log_ = std::make_unique(); this->gc_history_ = CircularBuffer(config.stats_history_z_); @@ -194,6 +201,12 @@ namespace xo { return retval; } + std::size_t + GC::nursery_from_allocated() const + { + return nursery_from()->allocated(); + } + std::size_t GC::nursery_to_reserved() const { @@ -259,7 +272,7 @@ namespace xo { return generation_result::not_found; } - std::tuple + std::tuple GC::location_of(role role, const void *x) const { { @@ -267,7 +280,7 @@ namespace xo { auto [is_tenured, offset] = space->location_of(x); if (is_tenured) - return std::make_tuple(generation_result::tenured, offset, space->allocated()); + return std::make_tuple(generation_result::tenured, offset, space->allocated(), space->committed()); } { @@ -275,19 +288,19 @@ namespace xo { auto [is_nursery, offset] = nursery(role)->location_of(x); if (is_nursery) - return std::make_tuple(generation_result::nursery, offset, space->allocated()); + return std::make_tuple(generation_result::nursery, offset, space->allocated(), space->committed()); } - return std::make_tuple(generation_result::not_found, 0, 0); + return std::make_tuple(generation_result::not_found, 0, 0, 0); } - std::tuple + std::tuple GC::tospace_location_of(const void * x) const { return location_of(role::to_space, x); } - std::tuple + std::tuple GC::fromspace_location_of(const void * x) const { return location_of(role::from_space, x); @@ -533,29 +546,26 @@ namespace xo { */ std::size_t max_promote_z = nursery_[role2int(role::to_space)]->before_checkpoint(); - log && log(xtag("max_promote_z", max_promote_z)); + ArenaAlloc * tenured_to = this->tenured_to(); + + /* tenured generation may need this much space */ + std::size_t need_tenured_z = (tenured_to->allocated() + + max_promote_z + + config_.full_gc_threshold_); + + log && log(xtag("alloc_tenured_z", tenured_to->allocated()), + xtag("max_promote_z", max_promote_z), + xtag("full_gc_threshold", config_.full_gc_threshold_), + xtag("need_tenured_z", need_tenured_z)); + + tenured_to->expand(tenured_to->allocated() + + max_promote_z + + config_.full_gc_threshold_); if (target == generation::tenured) { - /* gc on tenured generation may need this much space */ - std::size_t need_tenured_z = (tenured_[role2int(role::to_space)]->allocated() - + max_promote_z - + config_.full_gc_threshold_); - - log && log("need_tenured_z", need_tenured_z); - - tenured_from()->reset(need_tenured_z); + tenured_from()->clear(); this->swap_tenured(); - } else { - std::size_t avail_tenured_z = tenured_[role2int(role::to_space)]->available(); - - log && log(xtag("avail_tenured_z", avail_tenured_z)); - - if (avail_tenured_z < max_promote_z) { - ArenaAlloc * tenured_to = this->tenured_to(); - - tenured_to->expand(max_promote_z); - } } /* subtracting max_promote_z is correct here, since anything not promoted is garbage */ @@ -1220,24 +1230,22 @@ namespace xo { void GC::request_gc(generation target) { + /** full collection when >= @ref full_gc_threshold_ bytes added to tenured + * generation, since last full collection + **/ + bool need_full_gc + = ((target == generation::tenured) + || (this->tenured_to()->after_checkpoint() > config_.full_gc_threshold_) + || !config_.allow_incremental_gc_); + + if (need_full_gc) + target = generation::tenured; + if (!runstate_.in_progress() && (gc_enabled_ == 0)) { - if (!config_.allow_incremental_gc_) - target = generation::tenured; - - if ((target == generation::nursery) - && (this->tenured_to()->after_checkpoint() > config_.full_gc_threshold_)) - { - /** full collection when >= @ref full_gc_threshold_ bytes added to tenured - * generation, since last full collection - **/ - target = generation::tenured; - } - this->execute_gc(target); } else { this->incr_gc_pending_ = true; - if (target == generation::tenured) - this->full_gc_pending_ = true; + this->full_gc_pending_ |= need_full_gc; } } From f46c1d613e0a2984479efea252bf41b36cb88e5b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 29 Aug 2025 19:33:09 -0400 Subject: [PATCH 023/342] xo-imgui: clang compiler nits --- include/xo/alloc/GC.hpp | 2 ++ include/xo/alloc/ObjectStatistics.hpp | 3 ++- src/alloc/ArenaAlloc.cpp | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index d145e2c7..313306bc 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -119,6 +119,8 @@ namespace xo { **/ class GcCopyCallback { public: + virtual ~GcCopyCallback() = default; + virtual void notify_gc_copy(std::size_t z, const void * src_addr, const void * dest_addr, generation src_gen, generation dest_gen) = 0; /** invoked when added to callback set (i.e. @ref GC::GcCopyCallbackSet) **/ diff --git a/include/xo/alloc/ObjectStatistics.hpp b/include/xo/alloc/ObjectStatistics.hpp index ced3b463..43ddd70e 100644 --- a/include/xo/alloc/ObjectStatistics.hpp +++ b/include/xo/alloc/ObjectStatistics.hpp @@ -56,7 +56,8 @@ namespace xo { * * Passed to @ref Object::deep_move for example **/ - struct ObjectStatistics { + class ObjectStatistics { + public: void display(std::ostream & os) const; /** per-object-type statistics, indexed by TypeId **/ diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index 9703d103..4fdcefe8 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -9,6 +9,7 @@ #include "xo/indentlog/scope.hpp" #include "xo/indentlog/print/tag.hpp" #include +#include // for getpagesize() on OSX #include namespace xo { From 954921c641a5c31714bbdec9e33774a67f8a775e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 15 Nov 2025 12:25:03 -0500 Subject: [PATCH 024/342] xo-alloc: doc improvements --- docs/install.rst | 2 +- include/xo/alloc/ArenaAlloc.hpp | 44 ++++++++++++++++++++++++++------ include/xo/alloc/Forwarding.hpp | 28 -------------------- include/xo/alloc/Forwarding1.hpp | 16 +++++++++--- include/xo/alloc/Object.hpp | 4 +-- 5 files changed, 52 insertions(+), 42 deletions(-) delete mode 100644 include/xo/alloc/Forwarding.hpp diff --git a/docs/install.rst b/docs/install.rst index ab356be5..a61d9eea 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -24,7 +24,7 @@ Install One-step Install ---------------- -Install along with the reset of *XO* from `xo-umbrella2 source`_ +Install along with the rest of *XO* from `xo-umbrella2 source`_ .. _xo-umbrella2 source: https://github.com/rconybea/xo-umbrella2 diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 11fcdb72..da67f8f2 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -11,16 +11,41 @@ namespace xo { namespace gc { /** @class ArenaAlloc - * @brief Bump allocator with fixed capacity + * @brief Bump allocator with fixed capacity with dynamic virtual memory commitment. * * @text * - * <-----allocated----> <--------free-------> - * XXXXXXXXXXXXXXXXXXXX______________________ - * ^ ^ ^ - * lo free hi - * limit + * allocation order: + * -----------------------> + * + * <----------------- .size() ------------------> + * <----------------- .committed() ---------------> + * + * <-------allocated------><--------free--------> <---uncommitted----> + * XXXXXXXXXXXXXXXXXXXXXXXX______________________ .................... + * ^ ^ ^ ^ ^ + * lo checkpoint free limit hi + * + * +- .alloc() -> + * +-- .expand() --> + * > < .before_checkpoint() + * > < .after_checkpoint() + * * @endtext + * + * Design Notes: + * - non-copyable, non-moveable + * - always heap-allocated + * - @ref lo_ <= @ref checkpoint_ <= @ref free_ <= @ref limit_ <= @ref hi_ + * - memory obtained from mmap(), not heap + * - memory addresses are stable. Expand storage by committing VM pages. + * - @ref lo_ is aligned on VM page size (guaranteed by mmap()) + * - @ref lo_ + @ref committed_z_ <= @ref hi_ + * - @ref limit_ <= @ref lO_ + @ref committed_z_ + * - @ref committed_z_ is always a multiple of VM page size + * - @ref limit_ is not guaranteed to be aligned with VM page size. + * - @ref expand increases @ref limit_ and @ref committed_z_ as needed. + * **/ class ArenaAlloc : public IAlloc { public: @@ -57,11 +82,14 @@ namespace xo { /** Reset to empty state; provision at least @p need_z bytes of (committed) space **/ void reset(std::size_t need_z); + /** gc support: If used for storing xo::Object instances, scan allocated memory + * to populate @p *p_dest. + **/ void capture_object_statistics(capture_phase phase, ObjectStatistics * p_dest) const; /** expand available (i.e. committed) space to size at least @p z - * In practice will round up to a multiple of @ref page_z_ + * In practice will round up to a multiple of @ref page_z_. **/ bool expand(std::size_t z); @@ -98,7 +126,7 @@ namespace xo { /** optional instance name, for diagnostics **/ std::string name_; - /** size of a VM page **/ + /** size of a VM page (from getpagesize()) **/ std::size_t page_z_; /** allocator owns memory in range [@ref lo_, @ref hi_) **/ diff --git a/include/xo/alloc/Forwarding.hpp b/include/xo/alloc/Forwarding.hpp deleted file mode 100644 index 47a555da..00000000 --- a/include/xo/alloc/Forwarding.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/* Forwarding.hpp - * - * author: Roland Conybeare, Jul 2025 - */ - -#pragma once - -#include "Object.hpp" - -namespace xo { - namespace gc { - class Forwarding : public Object { - public: - Forwarding() = default; - - // inherited from Object.. -#ifdef NOT_USING - virtual bool _is_forwarded() const override final { return true; } -#endif - virtual Object * _destination() override final { return destination_.ptr(); } - - private: - gp destination_; - }; - } /*namespace gc*/ -} /*namespace xo*/ - -/* end Forwarding.hpp */ diff --git a/include/xo/alloc/Forwarding1.hpp b/include/xo/alloc/Forwarding1.hpp index cf54597d..6276c1ad 100644 --- a/include/xo/alloc/Forwarding1.hpp +++ b/include/xo/alloc/Forwarding1.hpp @@ -7,6 +7,16 @@ namespace xo { namespace obj { + /** @class Forwarding1 + * @brief forwarding pointer for garbage collector. + * + * Used internally by garbage collector (see @ref GC). + * During evacuate phase overwrite from-space objects in-place + * with an instance of this class. + * + * This class suitable only for singly-inheriting objects, + * i.e. those that have exactly one vtable. + **/ class Forwarding1 : public Object { public: explicit Forwarding1(gp dest); @@ -17,11 +27,11 @@ namespace xo { virtual bool _is_forwarded() const final override { return true; } virtual Object * _offset_destination(Object * src) const final override; virtual Object * _destination() final override; - /** never called on Forwarding1 **/ + /** required by Object i/face, but never called on Forwarding1 **/ virtual std::size_t _shallow_size() const final override; - /** never called on Forwarding1 **/ + /** required by Object i/face, but never called on Forwarding1 **/ virtual Object * _shallow_copy() const final override; - /** never called on Forwarding1 **/ + /** required by Object i/face, but never called on Forwarding1 **/ virtual std::size_t _forward_children() final override; private: diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 0f50bfed..8d74f5af 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -75,8 +75,8 @@ namespace xo { * for a type appear directly in that type's vtable, and at specific locations. * This implies one level of indirection when GC traverses an instance. * - * Would be feasible to relax the must-inherit-from-Object constraint, - * but cost would be an extra layer of indirection + * Would be feasible to relax the must-inherit-from-Object constraint + * by having GC use its own wrapper, at cost of an extra layer of indirection **/ class Object { public: From 1c97e2aa9300688ac111457ff280c5a331ff4cef Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 15 Nov 2025 16:38:18 -0500 Subject: [PATCH 025/342] xo-alloc: utest: fix broken alloc utests --- include/xo/alloc/GC.hpp | 6 ++++ src/alloc/CMakeLists.txt | 2 ++ src/alloc/GC.cpp | 12 +++++++ utest/CMakeLists.txt | 13 ++++--- utest/GC.test.cpp | 75 ++++++++++++++++++++++++---------------- 5 files changed, 75 insertions(+), 33 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 313306bc..1e73362e 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -168,6 +168,12 @@ namespace xo { bool is_full_gc_pending() const { return full_gc_pending_; } /** true during (and only during) a GC cycle **/ bool gc_in_progress() const { return runstate_.in_progress(); } + + /** @return pagesize (will be the same for {nursery, tenured} spaces) **/ + std::size_t pagesize() const; + + /** @return allocation portion of Nursery to-space **/ + std::size_t nursery_to_allocated() const; /** @return reserved size of Nursery to-space **/ std::size_t nursery_to_reserved() const; /** @return committed size of Nursery to-space **/ diff --git a/src/alloc/CMakeLists.txt b/src/alloc/CMakeLists.txt index b83e2618..5645b717 100644 --- a/src/alloc/CMakeLists.txt +++ b/src/alloc/CMakeLists.txt @@ -14,7 +14,9 @@ set(SELF_SRCS ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) +# xo-unit used for time measurement xo_dependency(${SELF_LIB} xo_unit) +xo_dependency(${SELF_LIB} indentlog) xo_dependency(${SELF_LIB} reflect) xo_dependency(${SELF_LIB} callback) diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 7d18da57..051a68b3 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -201,12 +201,24 @@ namespace xo { return retval; } + std::size_t + GC::pagesize() const + { + return nursery_to()->page_size(); + } + std::size_t GC::nursery_from_allocated() const { return nursery_from()->allocated(); } + std::size_t + GC::nursery_to_allocated() const + { + return nursery_to()->allocated(); + } + std::size_t GC::nursery_to_reserved() const { diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 379ed925..366cf664 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -1,4 +1,4 @@ -# build unittest alloc/utest +# xo-alloc/utest/CMakeLists.txt # # NOTE: more GC tests in xo-object/utest @@ -16,6 +16,11 @@ set(UTEST_SRCS generation.test.cpp ) -xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) -xo_self_dependency(${UTEST_EXE} xo_alloc) -xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2) +if (ENABLE_TESTING) + xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) + xo_self_dependency(${UTEST_EXE} xo_alloc) + xo_dependency(${UTEST_EXE} reflect) + xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2) +endif() + +# end CmakeLists.txt diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp index d961e3dd..67a0fdc0 100644 --- a/utest/GC.test.cpp +++ b/utest/GC.test.cpp @@ -15,55 +15,72 @@ namespace xo { namespace { struct testcase_gc { - testcase_gc(std::size_t nz, std::size_t tz) : nursery_z_{nz}, tenured_z_{tz} {} + testcase_gc(std::size_t nz, std::size_t tz, std::size_t n_gct, std::size_t t_gct) + : nursery_z_{nz}, tenured_z_{tz}, incr_gc_threshold_{n_gct}, full_gc_threshold_{t_gct} {} std::size_t nursery_z_; std::size_t tenured_z_; + std::size_t incr_gc_threshold_; + std::size_t full_gc_threshold_; }; std::vector s_testcase_v = { - testcase_gc(1024, 4096) + // nz tz n_gct t_gct + testcase_gc(1024, 4096, 1024, 4096) }; } TEST_CASE("gc", "[alloc][gc]") { for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { - const testcase_gc & tc = s_testcase_v[i_tc]; + try { + const testcase_gc & tc = s_testcase_v[i_tc]; - up gc = GC::make( - {.initial_nursery_z_ = tc.nursery_z_, - .initial_tenured_z_ = tc.tenured_z_}); + up gc = GC::make( + {.initial_nursery_z_ = tc.nursery_z_, + .initial_tenured_z_ = tc.tenured_z_, + .incr_gc_threshold_ = tc.incr_gc_threshold_, + .full_gc_threshold_ = tc.full_gc_threshold_, + }); - REQUIRE(gc.get()); - REQUIRE(gc->name() == "GC"); - REQUIRE(gc->size() == tc.nursery_z_ + tc.tenured_z_); - REQUIRE(gc->allocated() == 0); - REQUIRE(gc->available() == tc.nursery_z_); - REQUIRE(gc->before_checkpoint() == 0); - // ListAlloc model is that nothing is before checkpoint - // until it's first established - REQUIRE(gc->after_checkpoint() == 0); + REQUIRE(gc.get()); + REQUIRE(gc->name() == "GC"); + REQUIRE(gc->nursery_to_allocated() == 0); + REQUIRE(gc->nursery_to_committed() >= tc.nursery_z_); + REQUIRE(gc->nursery_to_reserved() >= tc.nursery_z_); + REQUIRE(gc->nursery_to_reserved() < tc.nursery_z_ + gc->pagesize()); + REQUIRE(gc->size() >= tc.nursery_z_ + tc.tenured_z_); + REQUIRE(gc->size() < tc.nursery_z_ + gc->pagesize() + tc.tenured_z_ + gc->pagesize()); + REQUIRE(gc->allocated() == 0); + REQUIRE(gc->available() == gc->nursery_to_reserved()); + REQUIRE(gc->before_checkpoint() == 0); + // ListAlloc model is that nothing is before checkpoint + // until it's first established + REQUIRE(gc->after_checkpoint() == 0); - REQUIRE(gc->gc_in_progress() == false); - REQUIRE(gc->is_gc_enabled() == true); - REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 0); - REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0); + REQUIRE(gc->gc_in_progress() == false); + REQUIRE(gc->is_gc_enabled() == true); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 0); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0); - /* gc with empty state */ - gc->request_gc(generation::nursery); + /* gc with empty state */ + gc->request_gc(generation::nursery); - REQUIRE(gc->gc_in_progress() == false); - REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); - REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0); + REQUIRE(gc->gc_in_progress() == false); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0); - /* still empty state */ - gc->request_gc(generation::tenured); + /* still empty state */ + gc->request_gc(generation::tenured); - REQUIRE(gc->gc_in_progress() == false); - REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); - REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 1); + REQUIRE(gc->gc_in_progress() == false); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); + REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 1); + } catch (std::exception &ex) { + std::cerr << "caught exception: " << ex.what() << std::endl; + REQUIRE(false); + } } } From b4c89d8624e4a1050d86b7eaade93202aa46738e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 16 Nov 2025 20:10:23 -0500 Subject: [PATCH 026/342] xo-interpreter adds + explict mm arg to ctors (retiring Object::mm) --- include/xo/alloc/GC.hpp | 2 + include/xo/alloc/Object.hpp | 3 +- src/alloc/ArenaAlloc.cpp | 71 +++++++++++++++++++++++------------ src/alloc/CMakeLists.txt | 4 +- src/alloc/GC.cpp | 74 ++++++++++++++++++++++++------------- src/alloc/Object.cpp | 2 +- utest/Forwarding1.test.cpp | 2 +- 7 files changed, 105 insertions(+), 53 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 1e73362e..abbb9657 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -54,6 +54,8 @@ namespace xo { bool allow_incremental_gc_ = true; /** true to report statistics **/ bool stats_flag_ = false; + /** true to capture per-type object statistics **/ + bool object_stats_flag_ = false; /** remember basic gc statistics for this many GC's; separately for incremental + full GCs **/ std::size_t stats_history_z_ = 256; /** true to enable debug logging **/ diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 8d74f5af..5a981998 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -258,8 +258,9 @@ namespace xo { **/ class Cpof { public: - explicit Cpof(const Object * src) : src_{src} {} + explicit Cpof(gc::IAlloc * mm, const Object * src) : mm_{mm}, src_{src} {} + gc::IAlloc * mm_ = nullptr; const void * src_ = nullptr; }; } /*namespace xo*/ diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index 4fdcefe8..febbcb61 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -26,6 +26,11 @@ namespace xo { void * base = mmap(nullptr, z, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + log && log("acquired memory [lo,hi) using mmap", + xtag("lo", base), + xtag("z", z), + xtag("hi", reinterpret_cast(base) + z)); + // could use this as fallback.. //base = (new std::byte [z]); @@ -39,7 +44,7 @@ namespace xo { this->checkpoint_ = lo_; this->free_ptr_ = lo_; this->limit_ = lo_ + z; - this->hi_ = limit_; + this->hi_ = lo_ + z; this->debug_flag_ = debug_flag; if (!lo_) { @@ -52,22 +57,25 @@ namespace xo { ArenaAlloc::~ArenaAlloc() { + scope log(XO_DEBUG(debug_flag_)); // hygiene.. if (lo_) { + log && log("unmap [lo,hi)", xtag("lo", lo_), xtag("z", hi_ - lo_), xtag("hi", hi_)); + munmap(lo_, hi_ - lo_); } - // could use this as fallback if not using uncommitted technique + // could use this as fallback if we dropped the uncommitted technique //delete [] this->lo_; - this->lo_ = nullptr; + this->lo_ = nullptr; this->committed_z_ = 0; - this->checkpoint_ = nullptr; - this->free_ptr_ = nullptr; - this->limit_ = nullptr; - this->hi_ = nullptr; - this->debug_flag_ = false; + this->checkpoint_ = nullptr; + this->free_ptr_ = nullptr; + this->limit_ = nullptr; + this->hi_ = nullptr; + this->debug_flag_ = false; } up @@ -94,26 +102,41 @@ namespace xo { } bool - ArenaAlloc::expand(size_t offset_z) { + ArenaAlloc::expand(size_t offset_z) + { scope log(XO_DEBUG(debug_flag_), xtag("offset_z", offset_z), xtag("committed_z", committed_z_)); - if (offset_z <= committed_z_) + if (offset_z <= committed_z_) { + log && log("trivial success, offset within committed range", + xtag("offset_z", offset_z), + xtag("committed_z", committed_z_)); return true; - - std::size_t align_offset_z = align_lub(offset_z, page_z_); - std::byte * commit_start = lo_ + committed_z_; - std::size_t new_commit_z = align_offset_z - committed_z_; - - log && log(xtag("align_offset_z", align_offset_z), - xtag("new_commit_z", new_commit_z)); - - if (mprotect(commit_start, new_commit_z, PROT_READ | PROT_WRITE) != 0) { - throw std::runtime_error(tostr("ArenaAlloc::expand: commit failure", - xtag("committed_z", committed_z_), - xtag("new_commit_z", new_commit_z))); } - this->committed_z_ = align_offset_z; + if (lo_ + offset_z > limit_) { + throw std::runtime_error(tostr("ArenaAlloc::expand: requested size exceeds reserved size", + xtag("requested", offset_z), xtag("reserved", reserved()))); + } + + std::size_t aligned_offset_z = align_lub(offset_z, page_z_); + std::byte * commit_start = lo_ + committed_z_; + std::size_t add_commit_z = aligned_offset_z - committed_z_; + + log && log(xtag("aligned_offset_z", aligned_offset_z), + xtag("add_commit_z", add_commit_z)); + + log && log("expand committed range", + xtag("commit_start", commit_start), + xtag("add_commit_z", add_commit_z), + xtag("commit_end", commit_start + add_commit_z)); + + if (mprotect(commit_start, add_commit_z, PROT_READ | PROT_WRITE) != 0) { + throw std::runtime_error(tostr("ArenaAlloc::expand: commit failure", + xtag("committed_z", committed_z_), + xtag("add_commit_z", add_commit_z))); + } + + this->committed_z_ = aligned_offset_z; this->limit_ = this->lo_ + committed_z_; return true; @@ -167,6 +190,8 @@ namespace xo { std::byte * p = lo_; while (p < free_ptr_) { + log && log(xtag("p", (void *)p)); + Object * obj = reinterpret_cast(p); TaggedPtr tp = obj->self_tp(); std::size_t z = obj->_shallow_size(); diff --git a/src/alloc/CMakeLists.txt b/src/alloc/CMakeLists.txt index 5645b717..6bbc2f32 100644 --- a/src/alloc/CMakeLists.txt +++ b/src/alloc/CMakeLists.txt @@ -15,9 +15,9 @@ set(SELF_SRCS xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) # xo-unit used for time measurement -xo_dependency(${SELF_LIB} xo_unit) +xo_headeronly_dependency(${SELF_LIB} xo_unit) xo_dependency(${SELF_LIB} indentlog) xo_dependency(${SELF_LIB} reflect) -xo_dependency(${SELF_LIB} callback) +xo_headeronly_dependency(${SELF_LIB} callback) #end CMakeLists.txt diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 051a68b3..8181cbb1 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -66,16 +66,36 @@ namespace xo { std::size_t nursery_size = config.initial_nursery_z_; std::size_t tenured_size = config.initial_tenured_z_; - nursery_[role2int(role::from_space)] + if (config_.incr_gc_threshold_ > nursery_size) { + throw std::runtime_error(tostr("GC::ctor: expected nursery gc threshold < nursery size", + xtag("nursery-gc-threshold", config_.incr_gc_threshold_), + xtag("nursery-size", nursery_size))); + } + + if (nursery_size + config_.full_gc_threshold_ > tenured_size) { + throw std::runtime_error(tostr("GC::ctor: expected nursery size + tennured gc threshold < tenured size", + xtag("nursery-size", nursery_size), + xtag("tenured-size", tenured_size), + xtag("full-gc-threshold", config_.full_gc_threshold_) + )); + } + + if (config_.incr_gc_threshold_ > nursery_size) + this->config_.incr_gc_threshold_ = nursery_size; + + if (config_.full_gc_threshold_ > tenured_size) + this->config_.full_gc_threshold_ = tenured_size; + + this->nursery_[role2int(role::from_space)] = ArenaAlloc::make("NA", nursery_size, config.debug_flag_); - nursery_[role2int(role::to_space) ] + this->nursery_[role2int(role::to_space) ] = ArenaAlloc::make("NB", nursery_size, config.debug_flag_); - tenured_[role2int(role::from_space)] + this->tenured_[role2int(role::from_space)] = ArenaAlloc::make("TA", tenured_size, config.debug_flag_); - tenured_[role2int(role::to_space) ] + this->tenured_[role2int(role::to_space) ] = ArenaAlloc::make("TB", tenured_size, config.debug_flag_); nursery_[role2int(role::from_space)]->expand(config.incr_gc_threshold_); @@ -83,9 +103,9 @@ namespace xo { tenured_[role2int(role::from_space)]->expand(config.full_gc_threshold_); tenured_[role2int(role::to_space) ]->expand(config.full_gc_threshold_); - mutation_log_[role2int(role::from_space)] = std::make_unique(); - mutation_log_[role2int(role::to_space )] = std::make_unique(); - defer_mutation_log_ = std::make_unique(); + this->mutation_log_[role2int(role::from_space)] = std::make_unique(); + this->mutation_log_[role2int(role::to_space )] = std::make_unique(); + this->defer_mutation_log_ = std::make_unique(); this->gc_history_ = CircularBuffer(config.stats_history_z_); @@ -96,23 +116,25 @@ namespace xo { /* hygiene */ this->clear(); - nursery_[role2int(role::from_space)].reset(); - nursery_[role2int(role::to_space) ].reset(); + this->nursery_[role2int(role::from_space)].reset(); + this->nursery_[role2int(role::to_space) ].reset(); - tenured_[role2int(role::from_space)].reset(); - tenured_[role2int(role::to_space) ].reset(); + this->tenured_[role2int(role::from_space)].reset(); + this->tenured_[role2int(role::to_space) ].reset(); - mutation_log_[role2int(role::from_space)].reset(); - mutation_log_[role2int(role::to_space) ].reset(); - defer_mutation_log_.reset(); + this->gc_root_v_.clear(); + + this->mutation_log_[role2int(role::from_space)].reset(); + this->mutation_log_[role2int(role::to_space) ].reset(); + this->defer_mutation_log_.reset(); } up GC::make(const Config & config) { - GC * gc = new GC(config); + //GC * gc = new GC(config); - return up{gc}; + return std::make_unique(config); } const std::string & @@ -608,16 +630,18 @@ namespace xo { void GC::capture_object_statistics(generation upto, capture_phase phase) { - /* scan nursery */ - this->nursery_[role2int(role::to_space)]->capture_object_statistics - (phase, - &object_statistics_sab_[gen2int(generation::nursery)]); - - if (upto == generation::tenured) { - /* scan tenured */ - this->tenured_[role2int(role::to_space)]->capture_object_statistics + if (config_.object_stats_flag_) { + /* scan nursery */ + this->nursery_[role2int(role::to_space)]->capture_object_statistics (phase, - &object_statistics_sab_[gen2int(generation::tenured)]); + &object_statistics_sab_[gen2int(generation::nursery)]); + + if (upto == generation::tenured) { + /* scan tenured */ + this->tenured_[role2int(role::to_space)]->capture_object_statistics + (phase, + &object_statistics_sab_[gen2int(generation::tenured)]); + } } } diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index b3db11ca..475d84ad 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -14,7 +14,7 @@ operator new (std::size_t z, const xo::Cpof & cpof) { using xo::gc::GC; - GC * gc = reinterpret_cast(xo::Object::mm); + GC * gc = reinterpret_cast(cpof.mm_); return gc->alloc_gc_copy(z, cpof.src_); } diff --git a/utest/Forwarding1.test.cpp b/utest/Forwarding1.test.cpp index e5dfb1fe..b39c35a1 100644 --- a/utest/Forwarding1.test.cpp +++ b/utest/Forwarding1.test.cpp @@ -33,7 +33,7 @@ namespace xo { void display(std::ostream & os) const final override { os << data_; } virtual std::size_t _shallow_size() const final override { return sizeof(*this); } - virtual Object * _shallow_copy() const final override { return new (Cpof(this)) DummyObject(*this); } + virtual Object * _shallow_copy() const final override { return new (Cpof(Object::mm, this)) DummyObject(*this); } virtual std::size_t _forward_children() final override { return _shallow_size(); } private: From 78c6c5cde98e4bf42b03a790c9036aec1b419a0a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 17 Nov 2025 10:41:35 -0500 Subject: [PATCH 027/342] xo-interpreter CVector for StackFrame reflection + OSX imgui edits --- include/xo/alloc/Object.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 5a981998..81f0611c 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -61,7 +61,9 @@ namespace xo { void assign_ptr(T * x) { ptr_ = x; } gc_ptr & operator=(const gc_ptr & x) { ptr_ = x.ptr(); return *this; } + T * operator->() const { return ptr_; } + T & operator*() const { return *ptr_; } private: T * ptr_ = nullptr; From 7b82ace806fd05912ae6e9847714c33567c2268d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 17 Nov 2025 22:31:10 -0500 Subject: [PATCH 028/342] xo-interpreter: prep for xo-symboltable --- README.md | 17 +++++++++++++++-- include/xo/alloc/Object.hpp | 2 -- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index eeef6ca5..5a42f922 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ -# xo-alloc -- arena allocator with rudimentary GC support +# xo-alloc -- arena allocator and incremental garbage collector -Xo-alloc is a lightweight arena allocator +# Rules for writing garbage-collected classes. + +Topics +* allocation - allocate Objects (inheriting xo::Object) before owned scratch space. + Can relax this if/when abandon the bad-for-locality use of two pointers + into to-space to keep track of grey objects. Want to use stack anyway + so we can do depth-first search. +* destructors - can omit except for finalization +* assignment - MUST USE Object::assign_member() to assign pointers to gc-owned memory. + Only necessary for old->new pointers, so don't need to worry about this + for initialization. +* finalization - not supported (yet) + +- padding - use IAlloc::with_padding(z) for hand-allocated objects. diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 81f0611c..a29b8de5 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -191,8 +191,6 @@ namespace xo { **/ virtual std::size_t _shallow_size() const = 0; - // TODO: _shallow_move() also overwrite *this with gc-only forwarding object point to C - /** if subject is allocated by GC: * - create copy C in to-space * - destination C will be nursery|tenured depending on location of this. From f3887debcaefe4ae2a7aecc7a65815452c16d2f6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 19 Nov 2025 12:38:54 -0500 Subject: [PATCH 029/342] xo-alloc / xo-refcnt: feature flags for easy tests. --- include/xo/alloc/Object.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index a29b8de5..5727331e 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -39,6 +39,11 @@ namespace xo { template gc_ptr(const gc_ptr & x) : ptr_{x.ptr()} {} + /** convenience for static asserts **/ + static constexpr bool is_gc_ptr = true; + /** see also: xo/refcnt/Refcounted.hpp **/ + static constexpr bool is_rc_ptr = false; + static bool is_eq(gc_ptr x1, gc_ptr x2) { std::uintptr_t u1 = reinterpret_cast(x1.ptr()); std::uintptr_t u2 = reinterpret_cast(x2.ptr()); From 2c21eede1fcd1082463a877740d60c383c542fff Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 20 Nov 2025 21:26:18 -0500 Subject: [PATCH 030/342] xo-interpreter: setting up for gc in interactive interpreter --- include/xo/alloc/GC.hpp | 4 ++-- src/alloc/GC.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index abbb9657..ce7b0f85 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -37,14 +37,14 @@ namespace xo { * pages are committed on demand. * Initial committment will be up to @ref incr_gc_threshold_ **/ - std::size_t initial_nursery_z_ = 0; + std::size_t initial_nursery_z_ = 64*1024*1024; /** initial size in bytes for oldest (Tenured) generation. * GC allocates two tenured spaces of this size. * This number represents reserved address space. * pages are committed on demand. * Initial committment will be up to @ref full_gc_threshold_ **/ - std::size_t initial_tenured_z_ = 0; + std::size_t initial_tenured_z_ = 128*1024*1024; /** trigger incremental GC after this many bytes allocated in nursery **/ std::size_t incr_gc_threshold_ = 64*1024; /** trigger full GC after this many bytes promoted to tenured **/ diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 8181cbb1..22654700 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -73,7 +73,7 @@ namespace xo { } if (nursery_size + config_.full_gc_threshold_ > tenured_size) { - throw std::runtime_error(tostr("GC::ctor: expected nursery size + tennured gc threshold < tenured size", + throw std::runtime_error(tostr("GC::ctor: expected nursery size + tenured gc threshold < tenured size", xtag("nursery-size", nursery_size), xtag("tenured-size", tenured_size), xtag("full-gc-threshold", config_.full_gc_threshold_) From dd41635a5652d267f0878bb04b03eb85572be97f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 22 Nov 2025 20:13:33 -0500 Subject: [PATCH 031/342] xo-tokenizer: refactor to correct accounting for line/consume/errpos --- include/xo/alloc/ArenaAlloc.hpp | 86 ++++++++++++++++++++++--- src/alloc/ArenaAlloc.cpp | 107 +++++++++++++++++++++++--------- 2 files changed, 157 insertions(+), 36 deletions(-) diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index da67f8f2..e0bfed2f 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -18,11 +18,11 @@ namespace xo { * allocation order: * -----------------------> * - * <----------------- .size() ------------------> - * <----------------- .committed() ---------------> + * <----------------- .size(), .reserved() ---------------------------> + * <----------------- .committed() -------------> * - * <-------allocated------><--------free--------> <---uncommitted----> - * XXXXXXXXXXXXXXXXXXXXXXXX______________________ .................... + * <-------allocated------><--------free--------><-----uncommitted----> + * XXXXXXXXXXXXXXXXXXXXXXXX______________________...................... * ^ ^ ^ ^ ^ * lo checkpoint free limit hi * @@ -31,12 +31,77 @@ namespace xo { * > < .before_checkpoint() * > < .after_checkpoint() * + * lifetime: + * + * 1. initial state after ctor + * + * >< committed()=0 + * <---------------------------uncommitted----------------------------> + * .................................................................... + * ^ ^ + * lo hi + * checkpoint + * free + * limit + * + * 1a. one call to ::mmap() + * 1b. vm address space [lo,hi) is reserved + * 1c. address space [lo,hi) is inaccessible. no read|write|execute permission + * + * 2. after first allocation of n bytes + * + * <--committed---> + * <--free--><--------------------uncommitted--------------------> + * > <- allocated + * XXXXXX__________..................................................... + * ^ ^ ^ ^ + * lo lo+n limit hi + * ^ free + * checkpoint + * + * 2a. committed just enough hugepages (2mb each) to accomodate n, + * i.e. expand-on-demand: + * - one call to ::mprotect() + * - .limit = .lo + (k+1) * .hugepage_z for some integer k>=0 + * - k * .page_z <= n < (k+1) * .hugepage_z + * 2b. expect immediate cost 1-5us, includes: + * - TLB flush + * invalidate TLB entries for committed range on all cores that this + * process' threads have run on since process inception. + * Also, if a kernel thread has run on one of said cores, it may + * have borrowed our TLB entries + * - page table update + * write to entry for each vm page + * - kernel overhead 100-1000 cycles (< 1us) + * 2c. expect deferred cost 1us-2us per hugepage: + * - committed pages aren't backed by physical memory until + * first touched; minor page fault on first access for each page. + * - so about 256-512us for 1MB + * 3. after .expand(z) + * + * <-------------committed------------> + * <------------free------------><----------uncomitted-----------> + * > <- allocated + * XXXXXX______________________________................................. + * ^ ^ ^ ^ + * lo lo+n limit hi + * ^ free + * checkpoint + * + * 3a. same as case 2. but without advancing .free pointer. + * + * 4. after dtor + * + * 4a. all memory returned to o/s, no longer reserved. + * - one call to ::munmap() + * * @endtext * * Design Notes: * - non-copyable, non-moveable - * - always heap-allocated * - @ref lo_ <= @ref checkpoint_ <= @ref free_ <= @ref limit_ <= @ref hi_ + * - memory for ArenaAlloc itself (not the memory it allocates), ~100 bytes + * always heap allocated. Use ArenaAlloc::make() * - memory obtained from mmap(), not heap * - memory addresses are stable. Expand storage by committing VM pages. * - @ref lo_ is aligned on VM page size (guaranteed by mmap()) @@ -55,7 +120,7 @@ namespace xo { /** Create allocator with capacity @p z, * Reserve memory addresses for @p z bytes, - * but don't commit them until needed + * (but don't commit them until needed) **/ static up make(const std::string & name, std::size_t z, @@ -127,7 +192,12 @@ namespace xo { std::string name_; /** size of a VM page (from getpagesize()) **/ - std::size_t page_z_; + std::size_t page_z_ = 0; + + /** size of a huge VM page. hardwiring this in ctor (to 2MB). + * larger pages relieve pressure on TLB, but suboptimal if use << 2MB + **/ + std::size_t hugepage_z_ = 0; /** allocator owns memory in range [@ref lo_, @ref hi_) **/ std::byte * lo_ = nullptr; @@ -139,7 +209,7 @@ namespace xo { * older (addresses below checkpoint) * and younger (addresses above checkpoint) **/ - std::byte * checkpoint_; + std::byte * checkpoint_ = nullptr; /** free pointer. memory in range [@ref free_, @ref limit_) available **/ std::byte * free_ptr_ = nullptr; /** soft limit: end of committed virtual memory **/ diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index febbcb61..0a0365e2 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -13,37 +13,101 @@ #include namespace xo { + using std::byte; + namespace gc { + namespace { + /* alignment better be a power of 2 */ + std::size_t + align_lub(std::size_t x, std::size_t align) + { + /* e.g: + * align = 4096, x%align = 100 -> dx = 3996 + * align = 4096, x%align = 0 -> dx = 0 + */ + std::size_t dx = (align - (x % align)) % align; + + return x + dx; + } + } + ArenaAlloc::ArenaAlloc(const std::string & name, - std::size_t z, bool debug_flag) + std::size_t z, + bool debug_flag) { scope log(XO_DEBUG(debug_flag), xtag("name", name)); + constexpr size_t c_hugepage_z = 2 * 1024 * 1024; + this->name_ = name; this->page_z_ = getpagesize(); + this->hugepage_z_ = c_hugepage_z; - // reserve virtual memory + // 1. need k pagetable entries where k is lub {k | k * .page_z >= z} + // 2. base will be aligned with .page_z but likely not with .hugepage_z + // 3. bad to have misalignment, because misaligned {prefix, suffix} of [base, base+z) + // will use 4k pages instead of 2mb pages + // + // strategy: + // 4. round up z to multiple of c_hugepage_z + // 5. over-request so reserved range contains an aligned subrange of size z + // 6. unmap misaligned prefix + // 7. unmap misaligned suffix. + // 8. enable huge pages for now-aligned remainder of reserved range + // + // Z. note: rejecting inferior MAP_HUGETLB|MAP_HUGE_2MB flags on ::mmap here: + // Za. requires previously-reserved memory in /proc/sys/vm/nr_hugepages + // Zb. reserved pages permenently resident in RAM, never swapped + // Zc. memory cost incurred even if no application is using said pages - void * base = mmap(nullptr, z, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + z = align_lub(z, c_hugepage_z); // 4. + + // 5. + byte * base = reinterpret_cast(::mmap(nullptr, + z + c_hugepage_z, + PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0)); log && log("acquired memory [lo,hi) using mmap", xtag("lo", base), xtag("z", z), - xtag("hi", reinterpret_cast(base) + z)); - - // could use this as fallback.. - //base = (new std::byte [z]); + xtag("hi", reinterpret_cast(base) + z)); if (base == MAP_FAILED) { throw std::runtime_error(tostr("ArenaAlloc: uncommitted allocation failed", xtag("size", z))); } - this->lo_ = reinterpret_cast(base); + byte * aligned_base = reinterpret_cast(align_lub(reinterpret_cast(base), + c_hugepage_z)); + + assert(reinterpret_cast(aligned_base) % c_hugepage_z == 0); + assert(aligned_base >= base); + assert(aligned_base < base + c_hugepage_z); + + if (base < aligned_base) { + size_t prefix = aligned_base - base; + + ::munmap(base, prefix); // 6. + } + + byte * aligned_hi = aligned_base + z; + byte * hi = base + z + c_hugepage_z; + + if (aligned_hi < hi) { + size_t suffix = hi - aligned_hi; + + ::munmap(aligned_hi, suffix); // 7. + } + + ::madvise(aligned_base, z, MADV_HUGEPAGE); // 8. + + this->lo_ = aligned_base; this->committed_z_ = 0; this->checkpoint_ = lo_; this->free_ptr_ = lo_; - this->limit_ = lo_ + z; + this->limit_ = lo_; this->hi_ = lo_ + z; this->debug_flag_ = debug_flag; @@ -52,7 +116,9 @@ namespace xo { xtag("size", z))); } - log && log(xtag("lo", (void*)lo_), xtag("page_z", page_z_)); + log && log(xtag("lo", (void*)lo_), + xtag("page_z", page_z_), + xtag("hugepage_z", hugepage_z_)); } ArenaAlloc::~ArenaAlloc() @@ -64,7 +130,7 @@ namespace xo { if (lo_) { log && log("unmap [lo,hi)", xtag("lo", lo_), xtag("z", hi_ - lo_), xtag("hi", hi_)); - munmap(lo_, hi_ - lo_); + ::munmap(lo_, hi_ - lo_); } // could use this as fallback if we dropped the uncommitted technique //delete [] this->lo_; @@ -86,21 +152,6 @@ namespace xo { z, debug_flag)); } - namespace { - /* alignment better be a power of 2 */ - std::size_t - align_lub(std::size_t x, std::size_t align) - { - /* e.g: - * align = 4096, x%align = 100 -> dx = 3996 - * align = 4096, x%align = 0 -> dx = 0 - */ - std::size_t dx = (align - (x % align)) % align; - - return x + dx; - } - } - bool ArenaAlloc::expand(size_t offset_z) { @@ -118,7 +169,7 @@ namespace xo { xtag("requested", offset_z), xtag("reserved", reserved()))); } - std::size_t aligned_offset_z = align_lub(offset_z, page_z_); + std::size_t aligned_offset_z = align_lub(offset_z, hugepage_z_); std::byte * commit_start = lo_ + committed_z_; std::size_t add_commit_z = aligned_offset_z - committed_z_; @@ -130,7 +181,7 @@ namespace xo { xtag("add_commit_z", add_commit_z), xtag("commit_end", commit_start + add_commit_z)); - if (mprotect(commit_start, add_commit_z, PROT_READ | PROT_WRITE) != 0) { + if (::mprotect(commit_start, add_commit_z, PROT_READ | PROT_WRITE) != 0) { throw std::runtime_error(tostr("ArenaAlloc::expand: commit failure", xtag("committed_z", committed_z_), xtag("add_commit_z", add_commit_z))); From 54dbbf69440e7dd32b4402104d12741031049779 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 22 Nov 2025 23:06:51 -0500 Subject: [PATCH 032/342] xo-tokenizer: streamline error path during tokenization --- src/alloc/ArenaAlloc.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index 0a0365e2..e5609297 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -64,10 +64,10 @@ namespace xo { // 5. byte * base = reinterpret_cast(::mmap(nullptr, - z + c_hugepage_z, - PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0)); + z + c_hugepage_z, + PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0)); log && log("acquired memory [lo,hi) using mmap", xtag("lo", base), @@ -101,7 +101,13 @@ namespace xo { ::munmap(aligned_hi, suffix); // 7. } +#ifdef __linux__ ::madvise(aligned_base, z, MADV_HUGEPAGE); // 8. +#endif + // TODO: for OSX -> need something else here. + // MAP_ALIGNED_SUPER with mmap() and/or + // use mach_vm_allocate() + // this->lo_ = aligned_base; this->committed_z_ = 0; From 40128c423c44d42994744f6e8b2f27a474a611a6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 23 Nov 2025 11:35:05 -0500 Subject: [PATCH 033/342] xo-alloc: bugfix expand: limit_ is soft, hi_ is hard. + docs --- include/xo/alloc/ArenaAlloc.hpp | 6 ++++-- src/alloc/ArenaAlloc.cpp | 27 ++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index e0bfed2f..302d9c0a 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -127,7 +127,7 @@ namespace xo { bool debug_flag); /** size of virtual address range reserved for this allocator **/ - std::size_t reserved() const { return this->size(); } + std::size_t reserved() const { return hi_ - lo_; }; std::size_t page_size() const { return page_z_; } std::byte * free_ptr() const { return free_ptr_; } @@ -212,7 +212,9 @@ namespace xo { std::byte * checkpoint_ = nullptr; /** free pointer. memory in range [@ref free_, @ref limit_) available **/ std::byte * free_ptr_ = nullptr; - /** soft limit: end of committed virtual memory **/ + /** soft limit: end of committed virtual memory + * invariant: @ref limit_ = @ref lo_ + @ref committed_z_ + **/ std::byte * limit_ = nullptr; /** hard limit: end of reserved virtual memory **/ std::byte * hi_ = nullptr; diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index e5609297..c06b9518 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -170,15 +170,37 @@ namespace xo { return true; } - if (lo_ + offset_z > limit_) { + if (lo_ + offset_z > hi_) { throw std::runtime_error(tostr("ArenaAlloc::expand: requested size exceeds reserved size", xtag("requested", offset_z), xtag("reserved", reserved()))); } + /* + * pre: + * + * _______________................................... + * ^ ^ ^ + * lo limit hi + * + * < committed_z > + * <----------offset_z-----------> + * > <- z: 0 <= z < hugepage_z + * <---------aligned_offset_z---------> + * <--- add_commit_z --> + * + * post: + * ____________________________________.............. + * ^ ^ ^ + * lo limit hi + * + */ + std::size_t aligned_offset_z = align_lub(offset_z, hugepage_z_); std::byte * commit_start = lo_ + committed_z_; std::size_t add_commit_z = aligned_offset_z - committed_z_; + assert(limit_ == lo_ + committed_z_); + log && log(xtag("aligned_offset_z", aligned_offset_z), xtag("add_commit_z", add_commit_z)); @@ -196,6 +218,9 @@ namespace xo { this->committed_z_ = aligned_offset_z; this->limit_ = this->lo_ + committed_z_; + assert(committed_z_ % hugepage_z_ == 0); + assert(reinterpret_cast(limit_) % hugepage_z_ == 0); + return true; } From eec5bc098186f9bea236d0d0be438cc763897283 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 23 Nov 2025 21:41:14 -0500 Subject: [PATCH 034/342] xo-interpreter: + toplevel env in VSM --- include/xo/alloc/GC.hpp | 13 +++++++++++++ src/alloc/GC.cpp | 21 +++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index ce7b0f85..8e12990e 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -7,6 +7,7 @@ #include "ArenaAlloc.hpp" #include "GcStatistics.hpp" +#include "Object.hpp" #include "xo/callback/UpCallbackSet.hpp" #include "xo/indentlog/print/array.hpp" #include @@ -154,6 +155,9 @@ namespace xo { **/ static up make(const Config & config); + /** runtime downcast **/ + static GC * from(IAlloc * mm); + const Config & config() const { return config_; } std::uint8_t nursery_polarity() const { return nursery_polarity_; } std::uint8_t tenured_polarity() const { return tenured_polarity_; } @@ -230,6 +234,15 @@ namespace xo { * from @c *addr **/ void add_gc_root(Object ** addr); + /** reverse the effect of previous call to @ref add_gc_root **/ + void remove_gc_root(Object ** addr); + + /** convenience wrapper **/ + template + void add_gc_root_dwim(gp * p) { this->add_gc_root(reinterpret_cast(p->ptr_address())); } + template + void remove_gc_root_dwim(gp * p) { this->remove_gc_root(reinterpret_cast(p->ptr_address())); } + /** may optionally use this to observe GC copy phase. * Will be invoked once _per surviving object_, so not cheap. * Intended for GC visualization. diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 22654700..c78768fb 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -132,11 +132,15 @@ namespace xo { up GC::make(const Config & config) { - //GC * gc = new GC(config); - return std::make_unique(config); } + GC * + GC::from(IAlloc * mm) + { + return dynamic_cast(mm); + } + const std::string & GC::name() const { @@ -390,6 +394,19 @@ namespace xo { gc_root_v_.push_back(addr); } + void + GC::remove_gc_root(Object ** addr) + { + /* Multithreaded GC not supported */ + + assert(!this->gc_in_progress()); + + auto new_end_ix = std::remove(gc_root_v_.begin(), gc_root_v_.end(), addr); + + /* erase now-unused slots */ + gc_root_v_.erase(new_end_ix, gc_root_v_.end()); + } + auto GC::add_gc_copy_callback(up fn) -> CallbackId { From 760bb556b24fa86124d1c61c882a94d927f839f7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 23 Nov 2025 22:57:52 -0500 Subject: [PATCH 035/342] xo-interpreter/xo-alloc: GlobalEnv + mm -> shallow_copy() --- include/xo/alloc/Forwarding1.hpp | 2 +- include/xo/alloc/Object.hpp | 5 ++++- src/alloc/Forwarding1.cpp | 2 +- src/alloc/Object.cpp | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/xo/alloc/Forwarding1.hpp b/include/xo/alloc/Forwarding1.hpp index 6276c1ad..77e081f9 100644 --- a/include/xo/alloc/Forwarding1.hpp +++ b/include/xo/alloc/Forwarding1.hpp @@ -30,7 +30,7 @@ namespace xo { /** required by Object i/face, but never called on Forwarding1 **/ virtual std::size_t _shallow_size() const final override; /** required by Object i/face, but never called on Forwarding1 **/ - virtual Object * _shallow_copy() const final override; + virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; /** required by Object i/face, but never called on Forwarding1 **/ virtual std::size_t _forward_children() final override; diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 5727331e..849cf9bb 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -57,6 +57,9 @@ namespace xo { return (u2 <= u1 + sizeof(std::uintptr_t)); } + /** (for consistency's sake) **/ + T * get() const { return ptr_; } + T * ptr() const { return ptr_; } T ** ptr_address() { return &ptr_; } @@ -204,7 +207,7 @@ namespace xo { * * Require: @ref mm is an instance of @ref gc::GC **/ - virtual Object * _shallow_copy() const = 0; + virtual Object * _shallow_copy(gc::IAlloc * mm) const = 0; /** update child pointers that refer to forwarding pointers, * replacing them with the correct destination. diff --git a/src/alloc/Forwarding1.cpp b/src/alloc/Forwarding1.cpp index 4b47e4f2..b4a44ff6 100644 --- a/src/alloc/Forwarding1.cpp +++ b/src/alloc/Forwarding1.cpp @@ -52,7 +52,7 @@ namespace xo { // LCOV_EXCL_START Object * - Forwarding1::_shallow_copy() const { + Forwarding1::_shallow_copy(gc::IAlloc *) const { assert(false); return nullptr; } diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index 475d84ad..309e0886 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -170,7 +170,7 @@ namespace xo { */ if (gc->fromspace_contains(src)) { - Object * dest = src->_shallow_copy(); + Object * dest = src->_shallow_copy(gc); if (dest != src) src->_forward_to(dest); From 2f2cb735f3a413f854dee8d84947430ed0b1a8b5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 24 Nov 2025 09:55:43 -0500 Subject: [PATCH 036/342] xo-interpreter: refactor for explicit gc::GC* dep --- include/xo/alloc/ArenaAlloc.hpp | 2 ++ include/xo/alloc/Forwarding1.hpp | 2 +- include/xo/alloc/GC.hpp | 9 +++++++++ include/xo/alloc/IAlloc.hpp | 27 ++++++++++++++++++++++----- include/xo/alloc/Object.hpp | 16 ++++++++-------- src/alloc/ArenaAlloc.cpp | 8 ++++++++ src/alloc/Forwarding1.cpp | 2 +- src/alloc/GC.cpp | 13 +++++++++++++ src/alloc/IAlloc.cpp | 12 ++++++++++++ src/alloc/Object.cpp | 30 +++++++++++++----------------- 10 files changed, 89 insertions(+), 32 deletions(-) diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 302d9c0a..ed3fd59c 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -175,6 +175,8 @@ namespace xo { virtual void checkpoint() final override; virtual std::byte * alloc(std::size_t z) final override; + virtual bool check_owned(Object * src) const final override; + ArenaAlloc & operator=(const ArenaAlloc &) = delete; ArenaAlloc & operator=(ArenaAlloc &&) = delete; diff --git a/include/xo/alloc/Forwarding1.hpp b/include/xo/alloc/Forwarding1.hpp index 77e081f9..88ca849a 100644 --- a/include/xo/alloc/Forwarding1.hpp +++ b/include/xo/alloc/Forwarding1.hpp @@ -32,7 +32,7 @@ namespace xo { /** required by Object i/face, but never called on Forwarding1 **/ virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; /** required by Object i/face, but never called on Forwarding1 **/ - virtual std::size_t _forward_children() final override; + virtual std::size_t _forward_children(gc::GC * mm) final override; private: /** the object that used to be located at this address (i.e. @c this) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 8e12990e..423dd2f8 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -308,6 +308,15 @@ namespace xo { **/ virtual void assign_member(Object * parent, Object ** lhs, Object* rhs) final override; + /** during GC check for source objects owned by GC. + * See Object::_shallow_move. + **/ + virtual bool check_owned(Object * src) const final override; + /** queries during GC to determine if object at address @p src should move: + * - full GC -> always + * - incr GC -> if not tenured + **/ + virtual bool check_move(Object * src) const final override; virtual std::byte * alloc(std::size_t z) final override; virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; diff --git a/include/xo/alloc/IAlloc.hpp b/include/xo/alloc/IAlloc.hpp index 0b6791f0..fceaca94 100644 --- a/include/xo/alloc/IAlloc.hpp +++ b/include/xo/alloc/IAlloc.hpp @@ -16,7 +16,12 @@ namespace xo { namespace gc { /** @class IAllocator - * @brief memory allocation interface with limited garbaga collector support + * @brief memory allocation interface with limited garbage collector support + * + * Garbage collector support methods: + * - checkpoint() + * - assign_member() + * - alloc_gc_copy() **/ class IAlloc { public: @@ -56,14 +61,28 @@ namespace xo { /** @return true iff debug logging enabled **/ virtual bool debug_flag() const = 0; - /** reset allocator to empty state. **/ - virtual void clear() = 0; /** remember allocator state. All currently-allocated addresses xo * will satisfy is_before_checkpoint(x). Subsequent allocations x * will fail is_before_checkpoint(x), until checkpoint superseded * by @ref clear or another call to @ref checkpoint **/ virtual void checkpoint() = 0; + + /** allocate @p z bytes of memory. returns pointer to first address **/ + virtual std::byte * alloc(std::size_t z) = 0; + /** reset allocator to empty state. **/ + virtual void clear() = 0; + + // ----- GC-specific methods ----- + + /** true iff this allocator owns object at address @p src. + * Use to assist Object::_shallow_move + **/ + virtual bool check_owned(Object * src) const; + /** true iff object at address @p src must move as part of + * in-progress collection phase + **/ + virtual bool check_move(Object * src) const; /** perform assignment * @code * *lhs = rhs @@ -72,8 +91,6 @@ namespace xo { * Default implementation just does the assignment. **/ virtual void assign_member(Object * parent, Object ** lhs, Object * rhs); - /** allocate @p z bytes of memory. returns pointer to first address **/ - virtual std::byte * alloc(std::size_t z) = 0; /** allocate @p z bytes for copy of object at @p src. * Only used in @ref GC. Default implementation asserts and returns nullptr **/ diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 849cf9bb..f1d03225 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -122,15 +122,15 @@ namespace xo { static Object * _forward(Object * src, gc::GC * gc); template - static void _forward_inplace(T ** src_addr) { - Object * fwd = _forward(*src_addr, _gc()); + static void _forward_inplace(T ** src_addr, gc::GC * gc) { + Object * fwd = _forward(*src_addr, gc); *src_addr = reinterpret_cast(fwd); } template - static void _forward_inplace(gp & src) { - _forward_inplace(src.ptr_address()); + static void _forward_inplace(gp & src, gc::GC * gc) { + _forward_inplace(src.ptr_address(), gc); } /** primary workhorse for garbage collection. @@ -156,10 +156,10 @@ namespace xo { **/ static Object * _deep_move(Object * src, gc::GC * gc, gc::ObjectStatistics * stats); - /** copy @p src to to-space, and replace original with forwarding pointer to new location. + /** copy @p src to to-space. Overwrite original with forwarding pointer to new location. * return the new location **/ - static Object * _shallow_move(Object * src, gc::GC * gc); + static Object * _shallow_move(Object * src, gc::IAlloc * gc); // Reflection support @@ -207,7 +207,7 @@ namespace xo { * * Require: @ref mm is an instance of @ref gc::GC **/ - virtual Object * _shallow_copy(gc::IAlloc * mm) const = 0; + virtual Object * _shallow_copy(gc::IAlloc * gc) const = 0; /** update child pointers that refer to forwarding pointers, * replacing them with the correct destination. @@ -243,7 +243,7 @@ namespace xo { * allocated by @ref _shallow_move * **/ - virtual std::size_t _forward_children() = 0; + virtual std::size_t _forward_children(gc::GC * gc) = 0; }; template diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index c06b9518..15078a0e 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -356,6 +356,14 @@ namespace xo { return free_ptr_ - checkpoint_; } + bool + ArenaAlloc::check_owned(Object * src) const + { + byte * addr = reinterpret_cast(src); + + return (lo_ <= addr) && (addr < hi_); + } + bool ArenaAlloc::debug_flag() const { diff --git a/src/alloc/Forwarding1.cpp b/src/alloc/Forwarding1.cpp index b4a44ff6..2cc183d5 100644 --- a/src/alloc/Forwarding1.cpp +++ b/src/alloc/Forwarding1.cpp @@ -60,7 +60,7 @@ namespace xo { // LCOV_EXCL_START std::size_t - Forwarding1::_forward_children() { + Forwarding1::_forward_children(gc::GC *) { assert(false); return 0; } diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index c78768fb..bb556620 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -559,6 +559,19 @@ namespace xo { } } + bool + GC::check_owned(Object * src) const + { + return this->fromspace_contains(src); + } + + bool + GC::check_move(Object * src) const + { + return (this->runstate().full_move() + || (this->tospace_generation_of(src) != gc::generation_result::tenured)); + } + void GC::swap_nursery() { diff --git a/src/alloc/IAlloc.cpp b/src/alloc/IAlloc.cpp index 8fe4789a..9754fb47 100644 --- a/src/alloc/IAlloc.cpp +++ b/src/alloc/IAlloc.cpp @@ -47,6 +47,18 @@ namespace xo { *lhs = rhs; } + bool + IAlloc::check_owned(Object * /*obj*/) const + { + return false; + } + + bool + IAlloc::check_move(Object * /*obj*/) const + { + return false; + } + // LCOV_EXCL_START std::byte * IAlloc::alloc_gc_copy(std::size_t /*z*/, const void * /*src*/) diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index 309e0886..560f941b 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -14,9 +14,9 @@ operator new (std::size_t z, const xo::Cpof & cpof) { using xo::gc::GC; - GC * gc = reinterpret_cast(cpof.mm_); + //GC * gc = reinterpret_cast(cpof.mm_); - return gc->alloc_gc_copy(z, cpof.src_); + return cpof.mm_->alloc_gc_copy(z, cpof.src_); } namespace xo { @@ -32,18 +32,15 @@ namespace xo { if (src->_is_forwarded()) return src->_offset_destination(src); - bool full_move = gc->runstate().full_move(); + if (gc->check_move(src)) { + Object::_shallow_move(src, gc); - if (!full_move && (gc->tospace_generation_of(src) == gc::generation_result::tenured)) { + /* *src is now a forwarding pointer to a copy in to-space */ + return src->_offset_destination(src); + } else { /* don't move tenured objects during incremental collection */ return src; } - - Object::_shallow_move(src, gc); - - /* *src is now a forwarding pointer to copy in to-space */ - - return src->_offset_destination(src); } Object * @@ -59,9 +56,7 @@ namespace xo { if (retval) return retval; - bool full_move = gc->runstate().full_move(); - - if (!full_move && gc->tospace_generation_of(from_src) == gc::generation_result::tenured) { + if (!gc->check_move(from_src)) { /** incremental collection does not move already-tenured objects **/ return from_src; } @@ -70,7 +65,8 @@ namespace xo { * To-space: * * to_lo = start of to-space - * w,W = white objects. An object x is white if x + all immediate children of x are in to-space + * w,W = white objects. An object x is white if x + * + all immediate children of x are in to-space * (also implies this GC cycle put it there) * g,G = grey objects. An object x is gray if it's in to-space, * but possibly has >0 black children @@ -141,7 +137,7 @@ namespace xo { // update per-class stats here - std::size_t xz = x->_forward_children(); + std::size_t xz = x->_forward_children(gc); // must pad xz to multiple of word size, // to match behavior of LinearAlloc::alloc() @@ -163,12 +159,12 @@ namespace xo { } /*deep_move*/ Object * - Object::_shallow_move(Object * src, gc::GC * gc) + Object::_shallow_move(Object * src, gc::IAlloc * gc) { /* filter for source objects that are owned by GC. * Care required though -- during GC from/to spaces have been swapped already */ - if (gc->fromspace_contains(src)) + if (gc->check_owned(src)) { Object * dest = src->_shallow_copy(gc); From e10380a792470dcddcd87dcfa370f6688deaa43f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 24 Nov 2025 12:47:44 -0500 Subject: [PATCH 037/342] xo-alloc: utest: fix forwading unit test after upstream refactor --- utest/Forwarding1.test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utest/Forwarding1.test.cpp b/utest/Forwarding1.test.cpp index b39c35a1..2dcb5efe 100644 --- a/utest/Forwarding1.test.cpp +++ b/utest/Forwarding1.test.cpp @@ -33,8 +33,8 @@ namespace xo { void display(std::ostream & os) const final override { os << data_; } virtual std::size_t _shallow_size() const final override { return sizeof(*this); } - virtual Object * _shallow_copy() const final override { return new (Cpof(Object::mm, this)) DummyObject(*this); } - virtual std::size_t _forward_children() final override { return _shallow_size(); } + virtual Object * _shallow_copy(gc::IAlloc * mm) const final override { return new (Cpof(mm, this)) DummyObject(*this); } + virtual std::size_t _forward_children(gc::GC * gc) final override { return _shallow_size(); } private: std::array data_; From 66235079a86c7ddf0964ae9ee7758f64a8dfd48f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 24 Nov 2025 12:58:54 -0500 Subject: [PATCH 038/342] xo-alloc: IAlloc* i/face sufficient for Object._forward_children --- include/xo/alloc/Forwarding1.hpp | 2 +- include/xo/alloc/Object.hpp | 8 ++++---- src/alloc/Forwarding1.cpp | 2 +- src/alloc/Object.cpp | 2 +- utest/Forwarding1.test.cpp | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/xo/alloc/Forwarding1.hpp b/include/xo/alloc/Forwarding1.hpp index 88ca849a..8999849a 100644 --- a/include/xo/alloc/Forwarding1.hpp +++ b/include/xo/alloc/Forwarding1.hpp @@ -32,7 +32,7 @@ namespace xo { /** required by Object i/face, but never called on Forwarding1 **/ virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; /** required by Object i/face, but never called on Forwarding1 **/ - virtual std::size_t _forward_children(gc::GC * mm) final override; + virtual std::size_t _forward_children(gc::IAlloc * mm) final override; private: /** the object that used to be located at this address (i.e. @c this) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index f1d03225..f16dd6ac 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -119,17 +119,17 @@ namespace xo { * @p src. source object to be forwarded * @p gc. garbage collector */ - static Object * _forward(Object * src, gc::GC * gc); + static Object * _forward(Object * src, gc::IAlloc * gc); template - static void _forward_inplace(T ** src_addr, gc::GC * gc) { + static void _forward_inplace(T ** src_addr, gc::IAlloc * gc) { Object * fwd = _forward(*src_addr, gc); *src_addr = reinterpret_cast(fwd); } template - static void _forward_inplace(gp & src, gc::GC * gc) { + static void _forward_inplace(gp & src, gc::IAlloc * gc) { _forward_inplace(src.ptr_address(), gc); } @@ -243,7 +243,7 @@ namespace xo { * allocated by @ref _shallow_move * **/ - virtual std::size_t _forward_children(gc::GC * gc) = 0; + virtual std::size_t _forward_children(gc::IAlloc * gc) = 0; }; template diff --git a/src/alloc/Forwarding1.cpp b/src/alloc/Forwarding1.cpp index 2cc183d5..f94bf4f1 100644 --- a/src/alloc/Forwarding1.cpp +++ b/src/alloc/Forwarding1.cpp @@ -60,7 +60,7 @@ namespace xo { // LCOV_EXCL_START std::size_t - Forwarding1::_forward_children(gc::GC *) { + Forwarding1::_forward_children(gc::IAlloc *) { assert(false); return 0; } diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index 560f941b..dbb86ae2 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -24,7 +24,7 @@ namespace xo { Object::mm = nullptr; Object * - Object::_forward(Object * src, gc::GC * gc) + Object::_forward(Object * src, gc::IAlloc * gc) { if (!src) return src; diff --git a/utest/Forwarding1.test.cpp b/utest/Forwarding1.test.cpp index 2dcb5efe..19d9bf1e 100644 --- a/utest/Forwarding1.test.cpp +++ b/utest/Forwarding1.test.cpp @@ -34,7 +34,7 @@ namespace xo { virtual std::size_t _shallow_size() const final override { return sizeof(*this); } virtual Object * _shallow_copy(gc::IAlloc * mm) const final override { return new (Cpof(mm, this)) DummyObject(*this); } - virtual std::size_t _forward_children(gc::GC * gc) final override { return _shallow_size(); } + virtual std::size_t _forward_children(gc::IAlloc * gc) final override { return _shallow_size(); } private: std::array data_; From 5c032834c6afc0db3a89f0962af373293eb00c21 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 24 Nov 2025 18:01:24 -0500 Subject: [PATCH 039/342] xo-interpreter: handle define-expressions. --- include/xo/alloc/Object.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index f16dd6ac..73a60edd 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -97,6 +97,8 @@ namespace xo { /** memory allocator for objects. Likely this will be a GC instance, * but simple arena also supported. + * + * Load-bearing for .assign_member() **/ static gc::IAlloc * mm; From e5a72bce36601aa9c088f3d4b4ed433c42aa03c8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 25 Nov 2025 12:43:57 -0500 Subject: [PATCH 040/342] xo-interpreter: implement variable lookup --- include/xo/alloc/Object.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 73a60edd..c8772db9 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -39,6 +39,10 @@ namespace xo { template gc_ptr(const gc_ptr & x) : ptr_{x.ptr()} {} + /** runtime downcast. shorthand for dynamic_cast **/ + template + static gc_ptr from(const gc_ptr & x) { return gc_ptr{dynamic_cast(x.ptr())}; } + /** convenience for static asserts **/ static constexpr bool is_gc_ptr = true; /** see also: xo/refcnt/Refcounted.hpp **/ From daf729292e6ba9ac23d4f8d78f40b210bc498a38 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 26 Nov 2025 20:15:03 -0500 Subject: [PATCH 041/342] xo-interpreter: Object->TaggedPtr conversion (prep for primitives) --- include/xo/alloc/Blob.hpp | 40 +++++++++++++++++++++++++++ src/alloc/Blob.cpp | 57 +++++++++++++++++++++++++++++++++++++++ src/alloc/CMakeLists.txt | 1 + 3 files changed, 98 insertions(+) create mode 100644 include/xo/alloc/Blob.hpp create mode 100644 src/alloc/Blob.cpp diff --git a/include/xo/alloc/Blob.hpp b/include/xo/alloc/Blob.hpp new file mode 100644 index 00000000..9e3ae44a --- /dev/null +++ b/include/xo/alloc/Blob.hpp @@ -0,0 +1,40 @@ +/** @file Blob.hpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#pragma once + +#include "Object.hpp" +#include "IAlloc.hpp" + +namespace xo { + /** Use to allocate opaque binary data, + * with object header. + * + * Not sure if we want to bother implementing reflection for this... + **/ + class Blob : public Object { + public: + Blob(std::size_t z) : z_{z} {}; + + static gp make(gc::IAlloc * mm, std::size_t z); + + std::size_t size() const { return z_; } + std::byte * data() { return data_; } + + virtual TaggedPtr self_tp() const final override; + virtual void display(std::ostream & os) const final override; + + virtual std::size_t _shallow_size() const final override; + virtual Object * _shallow_copy(gc::IAlloc * gc) const final override; + virtual std::size_t _forward_children(gc::IAlloc * gc) final override; + + private: + std::size_t z_ = 0; + /** flexible array, with @ref z_ bytes **/ + std::byte data_[]; + }; +} + +/* end Blob.hpp */ diff --git a/src/alloc/Blob.cpp b/src/alloc/Blob.cpp new file mode 100644 index 00000000..97932844 --- /dev/null +++ b/src/alloc/Blob.cpp @@ -0,0 +1,57 @@ +/** @file Blob.cpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#include "Blob.hpp" +#include "xo/reflect/Reflect.hpp" +#include "xo/alloc/IAlloc.hpp" + +namespace xo { + using xo::reflect::Reflect; + using xo::reflect::TaggedPtr; + + gp + Blob::make(gc::IAlloc * mm, std::size_t z) { + std::byte * mem = mm->alloc(sizeof(Blob) + z); + + return new (mem) Blob(z); + } + + TaggedPtr + Blob::self_tp() const + { + return Reflect::make_tp(const_cast(this)); + } + + void + Blob::display(std::ostream & os) const + { + os << ""; + } + + std::size_t + Blob::_shallow_size() const { + return sizeof(Blob) + z_; + } + + Object * + Blob::_shallow_copy(gc::IAlloc * mm) const { + Cpof cpof(mm, this); + std::byte * cp_mem = mm->alloc_gc_copy(sizeof(Blob) + z_, this); + + gp copy = new (cp_mem) Blob(z_); + + ::memcpy(copy->data(), data_, z_); + + return copy.get(); + } + + std::size_t + Blob::_forward_children(gc::IAlloc *) + { + return this->_shallow_size(); + } +} + +/* end Blob.cpp */ diff --git a/src/alloc/CMakeLists.txt b/src/alloc/CMakeLists.txt index 6bbc2f32..4a9d1db4 100644 --- a/src/alloc/CMakeLists.txt +++ b/src/alloc/CMakeLists.txt @@ -9,6 +9,7 @@ set(SELF_SRCS GcStatistics.cpp ObjectStatistics.cpp Object.cpp + Blob.cpp Forwarding1.cpp generation.cpp ) From 2febec3c8ca16896078fb5d42c81b7451edef03a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 29 Nov 2025 16:58:44 -0500 Subject: [PATCH 042/342] xo-alloc, xo-object: fix alloc,gc unit tests after gc improvements --- include/xo/alloc/ArenaAlloc.hpp | 1 + include/xo/alloc/GC.hpp | 2 ++ include/xo/alloc/IAlloc.hpp | 5 ++++- include/xo/alloc/ListAlloc.hpp | 3 +++ src/alloc/GC.cpp | 6 ++++++ src/alloc/ListAlloc.cpp | 6 ++++++ utest/ArenaAlloc.test.cpp | 24 ++++++++++++------------ utest/GC.test.cpp | 9 ++++++--- utest/ListAlloc.test.cpp | 5 ++++- 9 files changed, 44 insertions(+), 17 deletions(-) diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index ed3fd59c..d9731761 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -130,6 +130,7 @@ namespace xo { std::size_t reserved() const { return hi_ - lo_; }; std::size_t page_size() const { return page_z_; } + std::size_t hugepage_z() const { return hugepage_z_; } std::byte * free_ptr() const { return free_ptr_; } void set_free_ptr(std::byte * x); diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 423dd2f8..6146cba9 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -177,6 +177,8 @@ namespace xo { /** @return pagesize (will be the same for {nursery, tenured} spaces) **/ std::size_t pagesize() const; + /** @return hugepage size (will be the same for {nursery, tenured} spaces) **/ + std::size_t hugepage_z() const; /** @return allocation portion of Nursery to-space **/ std::size_t nursery_to_allocated() const; diff --git a/include/xo/alloc/IAlloc.hpp b/include/xo/alloc/IAlloc.hpp index fceaca94..3b36dc98 100644 --- a/include/xo/alloc/IAlloc.hpp +++ b/include/xo/alloc/IAlloc.hpp @@ -16,12 +16,15 @@ namespace xo { namespace gc { /** @class IAllocator - * @brief memory allocation interface with limited garbage collector support + * @brief arena allocation interface with limited garbage collector support * * Garbage collector support methods: * - checkpoint() * - assign_member() * - alloc_gc_copy() + * + * See class GC for copying incremental collector. + * See class ArenaAlloc for arena allocator **/ class IAlloc { public: diff --git a/include/xo/alloc/ListAlloc.hpp b/include/xo/alloc/ListAlloc.hpp index 75b148ac..30d91cfb 100644 --- a/include/xo/alloc/ListAlloc.hpp +++ b/include/xo/alloc/ListAlloc.hpp @@ -37,6 +37,9 @@ namespace xo { /** page size used by underlying ArenaAlloc **/ std::size_t page_size() const; + /** hugepage size used by underlying ArenaAlloc **/ + std::size_t hugepage_z() const; + /** reset to have at least @p z bytes of storage **/ bool reset(std::size_t z); diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index bb556620..3e636cad 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -233,6 +233,12 @@ namespace xo { return nursery_to()->page_size(); } + std::size_t + GC::hugepage_z() const + { + return nursery_to()->hugepage_z(); + } + std::size_t GC::nursery_from_allocated() const { diff --git a/src/alloc/ListAlloc.cpp b/src/alloc/ListAlloc.cpp index 8b0a2dbb..9961d59b 100644 --- a/src/alloc/ListAlloc.cpp +++ b/src/alloc/ListAlloc.cpp @@ -75,6 +75,11 @@ namespace xo { return hd_->page_size(); } + std::size_t + ListAlloc::hugepage_z() const { + return hd_->hugepage_z(); + } + std::size_t ListAlloc::size() const { return total_z_; @@ -336,6 +341,7 @@ namespace xo { std::unique_ptr new_alloc = ArenaAlloc::make(name, cz, debug_flag_); + cz = new_alloc->size(); if (!new_alloc) return false; diff --git a/utest/ArenaAlloc.test.cpp b/utest/ArenaAlloc.test.cpp index 52f135f3..78055eed 100644 --- a/utest/ArenaAlloc.test.cpp +++ b/utest/ArenaAlloc.test.cpp @@ -13,17 +13,16 @@ namespace xo { namespace { struct testcase_alloc { - testcase_alloc(std::size_t rz, std::size_t z) + explicit testcase_alloc(std::size_t z) : arena_z_{z} {} std::size_t arena_z_; - }; std::vector s_testcase_v = { - testcase_alloc(0, 4096) + testcase_alloc(4096) }; } @@ -37,11 +36,12 @@ namespace xo { auto alloc = ArenaAlloc::make("linearalloc", tc.arena_z_, c_debug_flag); + alloc->expand(tc.arena_z_); REQUIRE(alloc.get()); REQUIRE(alloc->name() == "linearalloc"); - REQUIRE(alloc->size() == tc.arena_z_); - REQUIRE(alloc->available() == tc.arena_z_); + REQUIRE(alloc->size() == std::max(tc.arena_z_, alloc->hugepage_z())); + REQUIRE(alloc->available() == std::max(tc.arena_z_, alloc->hugepage_z())); REQUIRE(alloc->allocated() == 0); REQUIRE(alloc->is_before_checkpoint(alloc->free_ptr()) == false); REQUIRE(alloc->before_checkpoint() == 0); @@ -49,23 +49,23 @@ namespace xo { auto free0 = alloc->free_ptr(); - auto mem = alloc->alloc(tc.arena_z_); + auto mem = alloc->alloc(std::max(tc.arena_z_, alloc->hugepage_z())); REQUIRE(mem != nullptr); REQUIRE(mem == free0); - REQUIRE(alloc->size() == tc.arena_z_); + REQUIRE(alloc->size() == std::max(tc.arena_z_, alloc->hugepage_z())); REQUIRE(alloc->available() == 0); - REQUIRE(alloc->allocated() == tc.arena_z_); + REQUIRE(alloc->allocated() == std::max(tc.arena_z_, alloc->hugepage_z())); REQUIRE(alloc->is_before_checkpoint(mem) == false); REQUIRE(alloc->before_checkpoint() == 0); - REQUIRE(alloc->after_checkpoint() == tc.arena_z_); + REQUIRE(alloc->after_checkpoint() == std::max(tc.arena_z_, alloc->hugepage_z())); alloc->clear(); REQUIRE(alloc->free_ptr() == free0); - REQUIRE(alloc->available() == tc.arena_z_); + REQUIRE(alloc->available() == std::max(tc.arena_z_, alloc->hugepage_z())); REQUIRE(alloc->allocated() == 0); REQUIRE(alloc->is_before_checkpoint(free0) == false); REQUIRE(alloc->before_checkpoint() == 0); @@ -74,8 +74,8 @@ namespace xo { mem = alloc->alloc(1); auto used = sizeof(void*); - REQUIRE(alloc->size() == tc.arena_z_); - REQUIRE(alloc->available() == tc.arena_z_ - used); + REQUIRE(alloc->size() == std::max(tc.arena_z_, alloc->hugepage_z())); + REQUIRE(alloc->available() == std::max(tc.arena_z_, alloc->hugepage_z()) - used); REQUIRE(alloc->allocated() == used); REQUIRE(alloc->is_before_checkpoint(free0) == false); REQUIRE(alloc->before_checkpoint() == 0); diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp index 67a0fdc0..9e6c17e3 100644 --- a/utest/GC.test.cpp +++ b/utest/GC.test.cpp @@ -26,8 +26,11 @@ namespace xo { std::vector s_testcase_v = { + // n_gct: nursery gc threshold + // t_gct: tenured gc threshold + // // nz tz n_gct t_gct - testcase_gc(1024, 4096, 1024, 4096) + testcase_gc(1024, 4096, 1024, 1024) }; } @@ -49,9 +52,9 @@ namespace xo { REQUIRE(gc->nursery_to_allocated() == 0); REQUIRE(gc->nursery_to_committed() >= tc.nursery_z_); REQUIRE(gc->nursery_to_reserved() >= tc.nursery_z_); - REQUIRE(gc->nursery_to_reserved() < tc.nursery_z_ + gc->pagesize()); + REQUIRE(gc->nursery_to_reserved() < tc.nursery_z_ + gc->hugepage_z()); REQUIRE(gc->size() >= tc.nursery_z_ + tc.tenured_z_); - REQUIRE(gc->size() < tc.nursery_z_ + gc->pagesize() + tc.tenured_z_ + gc->pagesize()); + REQUIRE(gc->size() < tc.nursery_z_ + gc->hugepage_z() + tc.tenured_z_ + gc->hugepage_z()); REQUIRE(gc->allocated() == 0); REQUIRE(gc->available() == gc->nursery_to_reserved()); REQUIRE(gc->before_checkpoint() == 0); diff --git a/utest/ListAlloc.test.cpp b/utest/ListAlloc.test.cpp index 0a62fd0b..5f425568 100644 --- a/utest/ListAlloc.test.cpp +++ b/utest/ListAlloc.test.cpp @@ -10,6 +10,8 @@ namespace xo { using xo::gc::ListAlloc; namespace ut { +#ifdef NOT_USING // ListAlloc probably permanently retired. Not maintaining + TEST_CASE("ListAlloc", "[alloc][gc]") { /** teeny weeny allocator. @@ -27,7 +29,7 @@ namespace xo { std::byte * mem1 = alloc->alloc(20); REQUIRE(mem1); - REQUIRE(alloc->size() == alloc->page_size()); + REQUIRE(alloc->size() == std::max(alloc->page_size(), alloc->hugepage_z())); /* round up to multiple of 8 */ REQUIRE(alloc->before_checkpoint() == 24); REQUIRE(alloc->after_checkpoint() == 0); @@ -54,6 +56,7 @@ namespace xo { REQUIRE(alloc->is_before_checkpoint(mem2) == false); REQUIRE(alloc->is_before_checkpoint(mem3) == false); } +#endif } /*namespace ut*/ } /*namespace xo*/ From 50b0f7698c7ac6357b49e2a5efcae19f79c492e4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 29 Nov 2025 16:59:36 -0500 Subject: [PATCH 043/342] xo-alloc: + ArenaAllocT for use with std::map() etc. --- include/xo/alloc/ArenaAllocT.hpp | 74 ++++++++++++++++++++++++++++++++ utest/ArenaAllocT.test.cpp | 65 ++++++++++++++++++++++++++++ utest/CMakeLists.txt | 1 + 3 files changed, 140 insertions(+) create mode 100644 include/xo/alloc/ArenaAllocT.hpp create mode 100644 utest/ArenaAllocT.test.cpp diff --git a/include/xo/alloc/ArenaAllocT.hpp b/include/xo/alloc/ArenaAllocT.hpp new file mode 100644 index 00000000..6c8a9b41 --- /dev/null +++ b/include/xo/alloc/ArenaAllocT.hpp @@ -0,0 +1,74 @@ +/** @file Allocator.hpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#pragma once + +#include "xo/alloc/ArenaAlloc.hpp" + +namespace xo { + namespace gc { + /** @class allocator + * @brief c++ allocator with allocator traits + * + * Can use ArenaAllocT with std::map etc. + **/ + template + class ArenaAllocT { + public: + using value_type = T; + /** copy assignment: leave lhs allocator in place **/ + using propagate_on_container_copy_assignment = std::false_type; + /** move assignment: adopt rhs allocator + * (Forced: cannot mix allocations from different allocators + * within a container) + **/ + using propagate_on_container_move_assignment = std::true_type; + /** swap: also swap allocators + * (Forced: cannot mix allocations from different allocators + * within a containers) + **/ + using propagate_on_container_swap = std::true_type; + /** An ArenaAlloc instance is unique owner of its own memory: + * no other instance can dealloc + **/ + using is_always_equal = std::false_type; + + public: + explicit ArenaAllocT(ArenaAlloc * mm) : mm_{mm} {} + ArenaAllocT(const ArenaAllocT & other) = default; + + /** rebind ctor. Allows container to use supplied allocator + * for multiple types + **/ + template + ArenaAllocT(const ArenaAllocT & other) noexcept : mm_{other.mm_} {} + + T * allocate(size_t n) { + void * mem = mm_->alloc(n * sizeof(T)); + + return reinterpret_cast(mem); + } + + void deallocate(T * p, size_t n) noexcept { + assert(mm_->contains(p)); + assert(n == 0 || mm_->contains(p + n - 1)); + + //arena_->deallocate(p, n * sizeof(T)); + } + + bool operator==(const ArenaAllocT & other) const { + return mm_ == other.mm_; + } + + bool operator!=(const ArenaAllocT & other) const { + return mm_ != other.mm_; + } + + ArenaAlloc * mm_ = nullptr; + }; + } /*namespace gc*/ +} /*namespace xo*/ + +/* end Allocator.hpp */ diff --git a/utest/ArenaAllocT.test.cpp b/utest/ArenaAllocT.test.cpp new file mode 100644 index 00000000..44b350be --- /dev/null +++ b/utest/ArenaAllocT.test.cpp @@ -0,0 +1,65 @@ +/** @file ArenaAllocT.test.cpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#include "xo/alloc/ArenaAllocT.hpp" +#include +#include + +namespace xo { + using xo::gc::ArenaAllocT; + using xo::gc::ArenaAlloc; + + namespace ut { + + namespace { + struct testcase_ArenaAllocT { + testcase_ArenaAllocT(std::size_t z) : arena_z_{z} {} + + std::size_t arena_z_; + std::vector> kv_pairs_; + }; + + std::vector + s_testcase_v = { + testcase_ArenaAllocT(4096) + }; + } + + TEST_CASE("ArenaAllocT", "[alloc][traits]") + { + for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + const testcase_ArenaAllocT & tc = s_testcase_v[i_tc]; + + constexpr bool c_debug_flag = true; + + auto arena = ArenaAlloc::make("arena", tc.arena_z_, c_debug_flag); + auto alloc = ArenaAllocT>(arena.get()); + + using TestMapType = std::map, + ArenaAllocT>>; + + TestMapType test_map(alloc); + + size_t n = 0; + for (const auto & kv_ix : tc.kv_pairs_) { + test_map[kv_ix.first] = kv_ix.second; + ++n; + + REQUIRE(test_map.size() == n); + + for (const auto & map_ix : test_map) { + map_ix.first; + map_ix.second; + } + } + + } + } + } +} /*namespace xo*/ + +/* end ArenaAllocT.test.cpp */ diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 366cf664..6c644f51 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -7,6 +7,7 @@ set(UTEST_SRCS alloc_utest_main.cpp IAlloc.test.cpp ArenaAlloc.test.cpp + ArenaAllocT.test.cpp ListAlloc.test.cpp GC.test.cpp GcStatistics.test.cpp From 5e3df1c7837746c02acbd845040cde42a1d728a1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 29 Nov 2025 17:11:53 -0500 Subject: [PATCH 044/342] xo-alloc: + ArenaAllocT unit test --- utest/ArenaAllocT.test.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/utest/ArenaAllocT.test.cpp b/utest/ArenaAllocT.test.cpp index 44b350be..a9257173 100644 --- a/utest/ArenaAllocT.test.cpp +++ b/utest/ArenaAllocT.test.cpp @@ -15,15 +15,16 @@ namespace xo { namespace { struct testcase_ArenaAllocT { - testcase_ArenaAllocT(std::size_t z) : arena_z_{z} {} - std::size_t arena_z_; std::vector> kv_pairs_; }; std::vector s_testcase_v = { - testcase_ArenaAllocT(4096) + { 4096, {} }, + { 4096, {{"a", "apple"}} }, + { 4096, {{"a", "apple"}, {"b", "banana"}, {"c", "carrot"}} }, + { 4096, {{"a", "apple"}, {"b", "banana"}, {"c", "carrot"}, {"e", "eggplant"}} }, }; } @@ -32,7 +33,7 @@ namespace xo { for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { const testcase_ArenaAllocT & tc = s_testcase_v[i_tc]; - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; auto arena = ArenaAlloc::make("arena", tc.arena_z_, c_debug_flag); auto alloc = ArenaAllocT>(arena.get()); @@ -52,8 +53,9 @@ namespace xo { REQUIRE(test_map.size() == n); for (const auto & map_ix : test_map) { - map_ix.first; - map_ix.second; + // verify alloc was used for both Key + Value. + REQUIRE(arena->contains(&map_ix.first)); + REQUIRE(arena->contains(&map_ix.second)); } } From 30a00be2620dc0ad40a71b1258454db269a6c428 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 1 Dec 2025 01:20:49 -0500 Subject: [PATCH 045/342] xo-alloc + xo-allocutil: refactor to shrink dep surface area --- include/xo/alloc/ArenaAlloc.hpp | 4 +- include/xo/alloc/Forwarding1.hpp | 10 +- include/xo/alloc/GC.hpp | 37 +++---- include/xo/alloc/IAlloc.hpp | 129 ----------------------- include/xo/alloc/Object.hpp | 171 +++++-------------------------- src/alloc/ArenaAlloc.cpp | 2 +- src/alloc/Blob.cpp | 2 +- src/alloc/CMakeLists.txt | 2 +- src/alloc/Forwarding1.cpp | 21 ++-- src/alloc/GC.cpp | 41 ++++---- src/alloc/IAlloc.cpp | 74 ------------- src/alloc/Object.cpp | 20 ++-- 12 files changed, 100 insertions(+), 413 deletions(-) delete mode 100644 include/xo/alloc/IAlloc.hpp delete mode 100644 src/alloc/IAlloc.cpp diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index d9731761..1f48121b 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -5,7 +5,7 @@ #pragma once -#include "IAlloc.hpp" +#include "xo/allocutil/IAlloc.hpp" #include "ObjectStatistics.hpp" namespace xo { @@ -175,8 +175,8 @@ namespace xo { virtual void clear() final override; virtual void checkpoint() final override; virtual std::byte * alloc(std::size_t z) final override; + virtual bool check_owned(IObject * src) const final override; - virtual bool check_owned(Object * src) const final override; ArenaAlloc & operator=(const ArenaAlloc &) = delete; ArenaAlloc & operator=(ArenaAlloc &&) = delete; diff --git a/include/xo/alloc/Forwarding1.hpp b/include/xo/alloc/Forwarding1.hpp index 8999849a..90ff0198 100644 --- a/include/xo/alloc/Forwarding1.hpp +++ b/include/xo/alloc/Forwarding1.hpp @@ -19,18 +19,18 @@ namespace xo { **/ class Forwarding1 : public Object { public: - explicit Forwarding1(gp dest); + explicit Forwarding1(gp dest); // inherited from Object.. virtual TaggedPtr self_tp() const final override; virtual void display(std::ostream & os) const final override; virtual bool _is_forwarded() const final override { return true; } - virtual Object * _offset_destination(Object * src) const final override; - virtual Object * _destination() final override; + virtual IObject * _offset_destination(IObject * src) const final override; + virtual IObject * _destination() final override; /** required by Object i/face, but never called on Forwarding1 **/ virtual std::size_t _shallow_size() const final override; /** required by Object i/face, but never called on Forwarding1 **/ - virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; + virtual IObject * _shallow_copy(gc::IAlloc * mm) const final override; /** required by Object i/face, but never called on Forwarding1 **/ virtual std::size_t _forward_children(gc::IAlloc * mm) final override; @@ -47,7 +47,7 @@ namespace xo { * UB revealed when GC traverses a pointer that relies on the 2nd * vtable to index virtual methods. **/ - gp dest_; + gp dest_; }; } /*namespace obj*/ diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 6146cba9..aeb918c9 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -88,29 +88,30 @@ namespace xo { class MutationLogEntry { public: - MutationLogEntry(Object * parent, Object ** lhs) : parent_{parent}, lhs_{lhs} {} + MutationLogEntry(IObject * parent, IObject ** lhs) + : parent_{parent}, lhs_{lhs} {} - Object * parent() const { return parent_; } - Object ** lhs() const { return lhs_; } + IObject * parent() const { return parent_; } + IObject ** lhs() const { return lhs_; } - Object * child() const { return *lhs_; } + IObject * child() const { return *lhs_; } bool is_child_forwarded() const; bool is_parent_forwarded() const; - Object * parent_destination() const; + IObject * parent_destination() const; /** Flag obsolete mutation. * Future proofing, never happens for regular objects **/ bool is_dead() const { return false; } - MutationLogEntry update_parent_moved(Object * parent_to) const; - void fixup_parent_child_moved(Object * child_to) { *lhs_ = child_to; } + MutationLogEntry update_parent_moved(IObject * parent_to) const; + void fixup_parent_child_moved(IObject * child_to) { *lhs_ = child_to; } private: - Object * parent_; - Object ** lhs_; + IObject * parent_ = nullptr; + IObject ** lhs_ = nullptr; }; using MutationLog = std::vector; @@ -235,15 +236,15 @@ namespace xo { /** add gc root at address @p addr . Gc will keep alive anything reachable * from @c *addr **/ - void add_gc_root(Object ** addr); + void add_gc_root(IObject ** addr); /** reverse the effect of previous call to @ref add_gc_root **/ - void remove_gc_root(Object ** addr); + void remove_gc_root(IObject ** addr); /** convenience wrapper **/ template - void add_gc_root_dwim(gp * p) { this->add_gc_root(reinterpret_cast(p->ptr_address())); } + void add_gc_root_dwim(gp * p) { this->add_gc_root(reinterpret_cast(p->ptr_address())); } template - void remove_gc_root_dwim(gp * p) { this->remove_gc_root(reinterpret_cast(p->ptr_address())); } + void remove_gc_root_dwim(gp * p) { this->remove_gc_root(reinterpret_cast(p->ptr_address())); } /** may optionally use this to observe GC copy phase. * Will be invoked once _per surviving object_, so not cheap. @@ -308,17 +309,17 @@ namespace xo { * @param lhs. address of a member variable within the allocation of @p parent. * @param rhs. new target for @p *lhs **/ - virtual void assign_member(Object * parent, Object ** lhs, Object* rhs) final override; + virtual void assign_member(IObject * parent, IObject ** lhs, IObject* rhs) final override; /** during GC check for source objects owned by GC. * See Object::_shallow_move. **/ - virtual bool check_owned(Object * src) const final override; + virtual bool check_owned(IObject * src) const final override; /** queries during GC to determine if object at address @p src should move: * - full GC -> always * - incr GC -> if not tenured **/ - virtual bool check_move(Object * src) const final override; + virtual bool check_move(IObject * src) const final override; virtual std::byte * alloc(std::size_t z) final override; virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; @@ -349,7 +350,7 @@ namespace xo { /** scan to-space for object statistics before GC */ void capture_object_statistics(generation upto, capture_phase phase); /** copy object **/ - void copy_object(Object ** addr, generation upto, ObjectStatistics * object_stats); + void copy_object(IObject ** addr, generation upto, ObjectStatistics * object_stats); /** copy everything reachable from global gc roots **/ void copy_globals(generation g); /** review mutation log; may discover+rescue reachable objects. @@ -426,7 +427,7 @@ namespace xo { * Application can introduce new root object pointers at any time provided GC not running, * but cannot withdraw them. **/ - std::vector gc_root_v_; + std::vector gc_root_v_; /** log cross-generational and cross-checkpoint mutations. * These need to be adjusted on next incremental collection diff --git a/include/xo/alloc/IAlloc.hpp b/include/xo/alloc/IAlloc.hpp deleted file mode 100644 index 3b36dc98..00000000 --- a/include/xo/alloc/IAlloc.hpp +++ /dev/null @@ -1,129 +0,0 @@ -/* file IAlloc.hpp - * - * author: Roland Conybeare, Jul 2025 - */ - -#pragma once - -#include -#include - -namespace xo { - template - using up = std::unique_ptr; - - class Object; - - namespace gc { - /** @class IAllocator - * @brief arena allocation interface with limited garbage collector support - * - * Garbage collector support methods: - * - checkpoint() - * - assign_member() - * - alloc_gc_copy() - * - * See class GC for copying incremental collector. - * See class ArenaAlloc for arena allocator - **/ - class IAlloc { - public: - virtual ~IAlloc() {} - - /** compute padding to add to an allocation of size z to bring it up to - * a multiple of word size (8 bytes on x86_64) - **/ - static std::uint32_t alloc_padding(std::size_t z); - /** z + alloc_padding(z) **/ - static std::size_t with_padding(std::size_t z); - - /** optional name for this allocator; labelling for diagnostics **/ - virtual const std::string & name() const = 0; - /** allocator size in bytes (up to reserved limit) - * Includes unallocated mmeory - **/ - virtual std::size_t size() const = 0; - /** committed size in bytes **/ - virtual std::size_t committed() const = 0; - /** number of unallocated bytes available (up to soft limit) - * from this allocator - **/ - virtual std::size_t available() const = 0; - /** number of bytes allocated from this allocator **/ - virtual std::size_t allocated() const = 0; - /** true iff pointer x comes from this allocator **/ - virtual bool contains(const void * x) const = 0; - /** true iff object at address @p x was allocated by this allocator, - * and before checkpoint - **/ - virtual bool is_before_checkpoint(const void * x) const = 0; - /** number of bytes allocated before @ref checkpoint **/ - virtual std::size_t before_checkpoint() const = 0; - /** number of bytes allocated since @ref checkpoint **/ - virtual std::size_t after_checkpoint() const = 0; - /** @return true iff debug logging enabled **/ - virtual bool debug_flag() const = 0; - - /** remember allocator state. All currently-allocated addresses xo - * will satisfy is_before_checkpoint(x). Subsequent allocations x - * will fail is_before_checkpoint(x), until checkpoint superseded - * by @ref clear or another call to @ref checkpoint - **/ - virtual void checkpoint() = 0; - - /** allocate @p z bytes of memory. returns pointer to first address **/ - virtual std::byte * alloc(std::size_t z) = 0; - /** reset allocator to empty state. **/ - virtual void clear() = 0; - - // ----- GC-specific methods ----- - - /** true iff this allocator owns object at address @p src. - * Use to assist Object::_shallow_move - **/ - virtual bool check_owned(Object * src) const; - /** true iff object at address @p src must move as part of - * in-progress collection phase - **/ - virtual bool check_move(Object * src) const; - /** perform assignment - * @code - * *lhs = rhs - * @endcode - * plus additional book keeping if needed (e.g. in @ref GC) - * Default implementation just does the assignment. - **/ - virtual void assign_member(Object * parent, Object ** lhs, Object * rhs); - /** allocate @p z bytes for copy of object at @p src. - * Only used in @ref GC. Default implementation asserts and returns nullptr - **/ - virtual std::byte * alloc_gc_copy(std::size_t z, const void * src); - }; - } /*namespace gc*/ - - class MMPtr { - public: - explicit MMPtr(gc::IAlloc * mm) : mm_{mm} {} - - gc::IAlloc * mm_ = nullptr; - }; -} /*namespace xo*/ - -inline void * operator new (std::size_t z, const xo::MMPtr & mmp) { - return mmp.mm_->alloc(z); -} - -//inline void operator delete (void * p, const MMPtr & mmp) { -// mmp.mm_->free(reinterpret_cast(p)); -//} - -inline void * operator new[] (std::size_t z, const xo::MMPtr & mmp) { - return mmp.mm_->alloc(z); -} - -//inline void operator delete[] (void * p, const MMPtr & mmp) { -// mmp.mm_->free(reinterpret_cast(p)); -//} - - -/* end IAlloc.hpp */ diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index c8772db9..2468c8bc 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -7,6 +7,8 @@ #include "xo/reflect/TaggedPtr.hpp" #include "IAlloc.hpp" +#include "xo/allocutil/IObject.hpp" +#include "xo/allocutil/gc_ptr.hpp" #include #include @@ -16,71 +18,6 @@ namespace xo { class ObjectStatistics; }; - template - class gc_ptr; - - template - using gp = gc_ptr; - - /** wrapper for a pointer to garbage-collector-eligible T. - * Application code will usually use the alias template gp - **/ - template - class gc_ptr { - public: - using element_type = T; - - public: - gc_ptr() = default; - gc_ptr(T * p) : ptr_{p} {} - gc_ptr(const gc_ptr & x) : ptr_{x.ptr_} {} - - /** create from gc_ptr to some related type @tparam S **/ - template - gc_ptr(const gc_ptr & x) : ptr_{x.ptr()} {} - - /** runtime downcast. shorthand for dynamic_cast **/ - template - static gc_ptr from(const gc_ptr & x) { return gc_ptr{dynamic_cast(x.ptr())}; } - - /** convenience for static asserts **/ - static constexpr bool is_gc_ptr = true; - /** see also: xo/refcnt/Refcounted.hpp **/ - static constexpr bool is_rc_ptr = false; - - static bool is_eq(gc_ptr x1, gc_ptr x2) { - std::uintptr_t u1 = reinterpret_cast(x1.ptr()); - std::uintptr_t u2 = reinterpret_cast(x2.ptr()); - - // multiple inheritance shenanigans. - // (allow interface pointers separated by one pointer) - - if (u1 >= u2) - return (u1 <= u2 + sizeof(std::uintptr_t)); - else - return (u2 <= u1 + sizeof(std::uintptr_t)); - } - - /** (for consistency's sake) **/ - T * get() const { return ptr_; } - - T * ptr() const { return ptr_; } - T ** ptr_address() { return &ptr_; } - - bool is_null() const { return ptr_ == nullptr; } - void make_null() { ptr_ = nullptr; } - - void assign_ptr(T * x) { ptr_ = x; } - - gc_ptr & operator=(const gc_ptr & x) { ptr_ = x.ptr(); return *this; } - - T * operator->() const { return ptr_; } - T & operator*() const { return *ptr_; } - - private: - T * ptr_ = nullptr; - }; - /** Root class for all xo GC-collectable objects. * * Design note: @@ -92,11 +29,15 @@ namespace xo { * Would be feasible to relax the must-inherit-from-Object constraint * by having GC use its own wrapper, at cost of an extra layer of indirection **/ - class Object { + class Object : public IObject { public: using TaggedPtr = xo::reflect::TaggedPtr; public: + static gp from(gp x) { + return dynamic_cast(x.ptr()); + } + virtual ~Object() = default; /** memory allocator for objects. Likely this will be a GC instance, @@ -111,7 +52,7 @@ namespace xo { * add mutation log entry **/ template - static void assign_member(gp parent, gp * lhs, gp rhs); + static void assign_member(gp parent, gp * lhs, gp rhs); /** use from GC aux functions **/ static gc::GC * _gc() { return reinterpret_cast(mm); } @@ -125,11 +66,11 @@ namespace xo { * @p src. source object to be forwarded * @p gc. garbage collector */ - static Object * _forward(Object * src, gc::IAlloc * gc); + static IObject * _forward(IObject * src, gc::IAlloc * gc); template static void _forward_inplace(T ** src_addr, gc::IAlloc * gc) { - Object * fwd = _forward(*src_addr, gc); + IObject * fwd = _forward(*src_addr, gc); *src_addr = reinterpret_cast(fwd); } @@ -160,12 +101,12 @@ namespace xo { * @param gc garbage collector * @param stats per-object-type GC statistics **/ - static Object * _deep_move(Object * src, gc::GC * gc, gc::ObjectStatistics * stats); + static IObject * _deep_move(IObject * src, gc::GC * gc, gc::ObjectStatistics * stats); /** copy @p src to to-space. Overwrite original with forwarding pointer to new location. * return the new location **/ - static Object * _shallow_move(Object * src, gc::IAlloc * gc); + static IObject * _shallow_move(IObject * src, gc::IAlloc * gc); // Reflection support @@ -176,89 +117,25 @@ namespace xo { /** print on stream @p os **/ virtual void display(std::ostream & os) const = 0; - // GC support + // Inherited from IObject.. - /** true iff this object represents a forwarding pointer. - * Forwarding pointers are exclusively created by the garbage collector; - * forwarding pointers (and only forwarding pointers) return true here. - **/ - virtual bool _is_forwarded() const { return false; } + //virtual bool _is_forwarded() const override { return false; } + //virtual IObject * _offset_destination(IObject * src) const override { return src; }; + virtual void _forward_to(IObject * dest) override; + //virtual IObject * _destination() override { return nullptr; } - /** offset for uncommon situation where pointer address is offset from object - * base address - **/ - virtual Object * _offset_destination(Object * src) const { return src; }; - - /** replace this object with a forwarding pointer referring to @p dest. - **/ - virtual void _forward_to(Object * dest); - - /** if this object represents a forwarding pointer, return its new location. - * forwarding pointers belong to the garbage collector implementation. - * (if you have to ask -- no, your class is not a forwarding pointer) - * all other objects return nullptr here. - **/ - virtual Object * _destination() { return nullptr; } - - /** return amount of storage (including padding) consumed by this object, - * excluding immediate Object-pointer children - **/ - virtual std::size_t _shallow_size() const = 0; - - /** if subject is allocated by GC: - * - create copy C in to-space - * - destination C will be nursery|tenured depending on location of this. - * else - * - return this to disengage from GC - * - * Require: @ref mm is an instance of @ref gc::GC - **/ - virtual Object * _shallow_copy(gc::IAlloc * gc) const = 0; - - /** update child pointers that refer to forwarding pointers, - * replacing them with the correct destination. - * See @ref Object::deep_move - * - * this gray object, located in to-space. - * fwd1 forwarding objects. - * Located in from-space. Invalid at end of GC cycle. - * p1,p2 source pointers. - * D1,D2 already-forwarded objects. located in to-space. - * - * before: - * this fwd1 - * +----+ +-+ - * | p1 ----->|x|-------> D1 - * | | +-+ - * | | - * | p2 ----------------> D2 - * +----+ - * - * after: - * this - * +----+ - * | p1 ----------------> D1 - * | | - * | | - * | p2 ----------------> D2 - * +----+ - * - * this is now white - * - * @return shallow size of *this. Must exactly match the amount of memory in to-space - * allocated by @ref _shallow_move - * - **/ - virtual std::size_t _forward_children(gc::IAlloc * gc) = 0; + virtual std::size_t _shallow_size() const override = 0; + virtual IObject * _shallow_copy(gc::IAlloc * gc) const override = 0; + virtual std::size_t _forward_children(gc::IAlloc * gc) override = 0; }; template void - Object::assign_member(gp parent, gp * lhs, gp rhs) + Object::assign_member(gp parent, gp * lhs, gp rhs) { - Object::mm->assign_member(parent.ptr(), - reinterpret_cast(lhs->ptr_address()), - rhs.ptr()); + Object::mm->assign_member(reinterpret_cast(parent.ptr()), + reinterpret_cast(lhs->ptr_address()), + reinterpret_cast(rhs.ptr())); } std::ostream & diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index 15078a0e..886b6a70 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -357,7 +357,7 @@ namespace xo { } bool - ArenaAlloc::check_owned(Object * src) const + ArenaAlloc::check_owned(IObject * src) const { byte * addr = reinterpret_cast(src); diff --git a/src/alloc/Blob.cpp b/src/alloc/Blob.cpp index 97932844..83e4121b 100644 --- a/src/alloc/Blob.cpp +++ b/src/alloc/Blob.cpp @@ -5,7 +5,7 @@ #include "Blob.hpp" #include "xo/reflect/Reflect.hpp" -#include "xo/alloc/IAlloc.hpp" +#include "xo/allocutil/IAlloc.hpp" namespace xo { using xo::reflect::Reflect; diff --git a/src/alloc/CMakeLists.txt b/src/alloc/CMakeLists.txt index 4a9d1db4..67e9759b 100644 --- a/src/alloc/CMakeLists.txt +++ b/src/alloc/CMakeLists.txt @@ -2,7 +2,6 @@ set(SELF_LIB xo_alloc) set(SELF_SRCS - IAlloc.cpp ArenaAlloc.cpp ListAlloc.cpp GC.cpp @@ -15,6 +14,7 @@ set(SELF_SRCS ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) +xo_headeronly_dependency(${SELF_LIB} xo_allocutil) # xo-unit used for time measurement xo_headeronly_dependency(${SELF_LIB} xo_unit) xo_dependency(${SELF_LIB} indentlog) diff --git a/src/alloc/Forwarding1.cpp b/src/alloc/Forwarding1.cpp index f94bf4f1..a42a3f57 100644 --- a/src/alloc/Forwarding1.cpp +++ b/src/alloc/Forwarding1.cpp @@ -13,7 +13,7 @@ namespace xo { using xo::reflect::TaggedPtr; namespace obj { - Forwarding1::Forwarding1(gp dest) + Forwarding1::Forwarding1(gp dest) : dest_{dest} {} @@ -26,18 +26,21 @@ namespace xo { void Forwarding1::display(std::ostream & os) const { - os << "self_tp().td()->short_name()) << ">"; + os << "self_tp().td()->short_name()) + << ">"; } - Object * - Forwarding1::_offset_destination(Object * src) const + IObject * + Forwarding1::_offset_destination(IObject * src) const { - intptr_t offset = src - static_cast(this); + intptr_t offset = src - static_cast(this); return dest_.ptr() + offset; } - Object * + IObject * Forwarding1::_destination() { return dest_.ptr(); } @@ -51,8 +54,10 @@ namespace xo { // LCOV_EXCL_STOP // LCOV_EXCL_START - Object * + IObject * Forwarding1::_shallow_copy(gc::IAlloc *) const { + /* forwarding objects are never copied */ + assert(false); return nullptr; } @@ -61,6 +66,8 @@ namespace xo { // LCOV_EXCL_START std::size_t Forwarding1::_forward_children(gc::IAlloc *) { + /* forwarding objects are never traced */ + assert(false); return 0; } diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 3e636cad..ca2506d9 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -27,7 +27,7 @@ namespace xo { return parent_->_is_forwarded(); } - Object * + IObject * MutationLogEntry::parent_destination() const { //const bool c_debug_flag = true; @@ -45,7 +45,7 @@ namespace xo { } MutationLogEntry - MutationLogEntry::update_parent_moved(Object * parent_to) const + MutationLogEntry::update_parent_moved(IObject * parent_to) const { std::byte * parent_from = reinterpret_cast(parent_); std::byte * lhs_from = reinterpret_cast(lhs_); @@ -55,7 +55,7 @@ namespace xo { std::byte * lhs_to = reinterpret_cast(parent_to) + offset; return MutationLogEntry(parent_to, - reinterpret_cast(lhs_to)); + reinterpret_cast(lhs_to)); } GC::GC(const Config & config) @@ -395,13 +395,13 @@ namespace xo { } void - GC::add_gc_root(Object ** addr) + GC::add_gc_root(IObject ** addr) { gc_root_v_.push_back(addr); } void - GC::remove_gc_root(Object ** addr) + GC::remove_gc_root(IObject ** addr) { /* Multithreaded GC not supported */ @@ -450,7 +450,9 @@ namespace xo { std::byte * GC::alloc_gc_copy(std::size_t z, const void * src) { - scope log(XO_DEBUG(config_.debug_flag_), xtag("z", z), xtag("+pad", IAlloc::alloc_padding(z))); + scope log(XO_DEBUG(config_.debug_flag_), + xtag("z", z), + xtag("+pad", IAlloc::alloc_padding(z))); generation_result src_gr = this->fromspace_generation_of(src); @@ -483,7 +485,8 @@ namespace xo { gc_copy_cbset_.invoke(&GcCopyCallback::notify_gc_copy, z, src, retval, generation::nursery, generation::tenured); - this->gc_statistics_.total_promoted_ += IAlloc::with_padding(z); + this->gc_statistics_.total_promoted_ + += IAlloc::with_padding(z); } else { log && log("nursery"); @@ -509,7 +512,7 @@ namespace xo { } void - GC::assign_member(Object * parent, Object ** lhs, Object * rhs) + GC::assign_member(IObject * parent, IObject ** lhs, IObject * rhs) { ++gc_statistics_.n_mutation_; @@ -566,13 +569,13 @@ namespace xo { } bool - GC::check_owned(Object * src) const + GC::check_owned(IObject * src) const { return this->fromspace_contains(src); } bool - GC::check_move(Object * src) const + GC::check_move(IObject * src) const { return (this->runstate().full_move() || (this->tospace_generation_of(src) != gc::generation_result::tenured)); @@ -682,7 +685,9 @@ namespace xo { } void - GC::copy_object(Object ** pp_object, generation upto, ObjectStatistics * object_stats) + GC::copy_object(IObject ** pp_object, + generation upto, + ObjectStatistics * object_stats) { void * object_address = *pp_object; @@ -707,7 +712,7 @@ namespace xo { scope log(XO_DEBUG(config_.debug_flag_), xtag("roots", gc_root_v_.size())); - for (Object ** pp_root : gc_root_v_) { + for (IObject ** pp_root : gc_root_v_) { this->copy_object(pp_root, upto, &object_statistics_sae_[gen2int(upto)]); } @@ -778,7 +783,7 @@ namespace xo { // obsolete mutation -- no longer belongs to parent, discard } else { // note: child obtained (as it must be) by reading from parent's memory _now_. - Object * child_from = from_entry.child(); + IObject * child_from = from_entry.child(); if (child_from) { if (!child_from->_is_forwarded()) { @@ -813,7 +818,7 @@ namespace xo { // P->C, C moved to C' // Includes cases (a),(c) from above - Object * child_to = child_from->_destination(); + IObject * child_to = child_from->_destination(); from_entry.fixup_parent_child_moved(child_to); @@ -843,7 +848,7 @@ namespace xo { // follows that loc(P') = T // already have P'->C' when parent moved separately - Object * parent_to = from_entry.parent_destination(); + IObject * parent_to = from_entry.parent_destination(); log && log(xtag("parent_to", (void*)parent_to)); @@ -851,7 +856,7 @@ namespace xo { MutationLogEntry to_entry = from_entry.update_parent_moved(parent_to); - Object * child_to = to_entry.child(); // after moving + IObject * child_to = to_entry.child(); // after moving if (tospace_generation_of(child_to) == generation_result::nursery) { if (to_entry.is_dead()) { @@ -954,7 +959,7 @@ namespace xo { log && (i_from % 10000 == 0) && log(xtag("i_from", i_from)); if (from_entry.is_parent_forwarded()) { - Object * parent_to = from_entry.parent_destination(); + IObject * parent_to = from_entry.parent_destination(); log && log(xtag("parent_to", (void*)parent_to)); @@ -964,7 +969,7 @@ namespace xo { // note: child obtained (as it must be) by reading from prarent's memory _now_. // Since parent has moved, child has too - Object * child_to = to_entry.child(); // after moveing + IObject * child_to = to_entry.child(); // after moveing if (tospace_generation_of(parent_to) == generation_result::tenured) { diff --git a/src/alloc/IAlloc.cpp b/src/alloc/IAlloc.cpp deleted file mode 100644 index 9754fb47..00000000 --- a/src/alloc/IAlloc.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* @file IAlloc.cpp - * - * author: Roland Conybeare, Aug 2025 - */ - -#include "IAlloc.hpp" -#include -#include - -namespace xo { - namespace gc { - - std::uint32_t - IAlloc::alloc_padding(std::size_t z) - { - /* word size for alignment */ - constexpr uint32_t c_bpw = sizeof(std::uintptr_t); - - /* round up to multiple of c_bpw, but map 0 -> 0 - * (table assuming c_bpw==8) - * - * z%c_bpw dz - * ------------ - * 0 0 - * 1 7 - * 2 6 - * .. .. - * 7 1 - */ - std::uint32_t dz = (c_bpw - (z % c_bpw)) % c_bpw; - z += dz; - - assert(z % c_bpw == 0ul); - - return dz; - } - - std::size_t - IAlloc::with_padding(std::size_t z) - { - return z + alloc_padding(z); - } - - void - IAlloc::assign_member(Object * /*parent*/, Object ** lhs, Object * rhs) - { - *lhs = rhs; - } - - bool - IAlloc::check_owned(Object * /*obj*/) const - { - return false; - } - - bool - IAlloc::check_move(Object * /*obj*/) const - { - return false; - } - - // LCOV_EXCL_START - std::byte * - IAlloc::alloc_gc_copy(std::size_t /*z*/, const void * /*src*/) - { - assert(false); - return nullptr; - } - // LCOV_EXCL_STOP - - } /*namespace gc*/ -} /*namespace xo*/ - -/* end IAlloc.cpp */ diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index dbb86ae2..82583a0a 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -23,8 +23,8 @@ namespace xo { gc::IAlloc * Object::mm = nullptr; - Object * - Object::_forward(Object * src, gc::IAlloc * gc) + IObject * + Object::_forward(IObject * src, gc::IAlloc * gc) { if (!src) return src; @@ -43,15 +43,15 @@ namespace xo { } } - Object * - Object::_deep_move(Object * from_src, gc::GC * gc, gc::ObjectStatistics * /*stats*/) + IObject * + Object::_deep_move(IObject * from_src, gc::GC * gc, gc::ObjectStatistics * /*stats*/) { using gc::generation; if (!from_src) return nullptr; - Object * retval = from_src->_destination(); + IObject * retval = from_src->_destination(); if (retval) return retval; @@ -124,7 +124,7 @@ namespace xo { std::array gray_lo_v = { gc->free_ptr(generation::nursery), gc->free_ptr(generation::tenured) }; - Object * to_src = Object::_shallow_move(from_src, gc); + IObject * to_src = Object::_shallow_move(from_src, gc); std::size_t fixup_work = 0; do { @@ -158,15 +158,15 @@ namespace xo { return to_src; } /*deep_move*/ - Object * - Object::_shallow_move(Object * src, gc::IAlloc * gc) + IObject * + Object::_shallow_move(IObject * src, gc::IAlloc * gc) { /* filter for source objects that are owned by GC. * Care required though -- during GC from/to spaces have been swapped already */ if (gc->check_owned(src)) { - Object * dest = src->_shallow_copy(gc); + IObject * dest = src->_shallow_copy(gc); if (dest != src) src->_forward_to(dest); @@ -178,7 +178,7 @@ namespace xo { } void - Object::_forward_to(Object * dest) + Object::_forward_to(IObject * dest) { char * mem = reinterpret_cast(this); From b32b9151dad7dda47b6fe13ae0d4309ce51ee016 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 1 Dec 2025 14:22:41 -0500 Subject: [PATCH 046/342] xo-alloc xo-ordinaltree: GC option work in progress --- include/xo/alloc/Object.hpp | 2 +- utest/Forwarding1.test.cpp | 4 ++-- utest/IAlloc.test.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 2468c8bc..2c11ea9e 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -64,7 +64,7 @@ namespace xo { * 3. return the location of the copy make in step 1. * * @p src. source object to be forwarded - * @p gc. garbage collector + * @p gc. allocator (poassibly garbage collector) */ static IObject * _forward(IObject * src, gc::IAlloc * gc); diff --git a/utest/Forwarding1.test.cpp b/utest/Forwarding1.test.cpp index 19d9bf1e..f0a81c14 100644 --- a/utest/Forwarding1.test.cpp +++ b/utest/Forwarding1.test.cpp @@ -23,7 +23,7 @@ namespace xo { gp member() const { return member_; } void assign_member(Object * x) { - Object::mm->assign_member(this, member_.ptr_address(), x); + Object::mm->assign_member(this, reinterpret_cast(member_.ptr_address()), x); } TaggedPtr self_tp() const final override { @@ -33,7 +33,7 @@ namespace xo { void display(std::ostream & os) const final override { os << data_; } virtual std::size_t _shallow_size() const final override { return sizeof(*this); } - virtual Object * _shallow_copy(gc::IAlloc * mm) const final override { return new (Cpof(mm, this)) DummyObject(*this); } + virtual IObject * _shallow_copy(gc::IAlloc * mm) const final override { return new (Cpof(mm, this)) DummyObject(*this); } virtual std::size_t _forward_children(gc::IAlloc * gc) final override { return _shallow_size(); } private: diff --git a/utest/IAlloc.test.cpp b/utest/IAlloc.test.cpp index b0214749..823791ab 100644 --- a/utest/IAlloc.test.cpp +++ b/utest/IAlloc.test.cpp @@ -3,7 +3,7 @@ * author: Roland Conybeare, Aug 2025 */ -#include "xo/alloc/IAlloc.hpp" +#include "xo/allocutil/IAlloc.hpp" #include namespace xo { From fd6bdd93c37e1dec26f139308baa336a68140bb6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 1 Dec 2025 22:25:41 -0500 Subject: [PATCH 047/342] xo-ordinaltree: GC test [wip] --- include/xo/alloc/GC.hpp | 8 ++++++++ include/xo/alloc/Object.hpp | 13 ------------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index aeb918c9..092f2f36 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -144,9 +144,17 @@ namespace xo { using GcCopyCallbackSet = xo::fn::UpCallbackSet; using nanos = decltype(xo::qty::qty::nanosecond); + /** rebind is for typed allocators. since IAlloc is untyped, + * we want degenerate version + **/ + template + struct rebind { using other = GC; }; + public: /** create new GC instance with configuration @p config **/ explicit GC(const Config & config); + /** noncopyable **/ + GC(const GC & other) = delete; virtual ~GC(); /** create GC allocator. diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 2c11ea9e..9681afab 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -141,19 +141,6 @@ namespace xo { std::ostream & operator<< (std::ostream & os, gp x); - /** @class Cpof - * @brief argument to operator new used for garbage collector evacuation phase - * - * Tag overloaded operator new to activate allocation policy based on location - * in memory of source object. - **/ - class Cpof { - public: - explicit Cpof(gc::IAlloc * mm, const Object * src) : mm_{mm}, src_{src} {} - - gc::IAlloc * mm_ = nullptr; - const void * src_ = nullptr; - }; } /*namespace xo*/ void * operator new (std::size_t z, const xo::Cpof & copy); From 77f84cabbbc94cb362c68e65f22446bec8792148 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 2 Dec 2025 10:37:07 -0500 Subject: [PATCH 048/342] xo-alloc / xo-ordinaltree: work on dual-alloc-policy trees --- include/xo/alloc/GC.hpp | 3 ++- src/alloc/GC.cpp | 6 ++++++ src/alloc/Object.cpp | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 092f2f36..be2ff071 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -318,7 +318,8 @@ namespace xo { * @param rhs. new target for @p *lhs **/ virtual void assign_member(IObject * parent, IObject ** lhs, IObject* rhs) final override; - + /** evacuate @p *lhs and replace with forwarding pointer **/ + virtual void forward_inplace(IObject ** lhs) final override; /** during GC check for source objects owned by GC. * See Object::_shallow_move. **/ diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index ca2506d9..40234bf3 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -568,6 +568,12 @@ namespace xo { } } + void + GC::forward_inplace(IObject ** lhs) + { + Object::_forward_inplace(lhs, this); + } + bool GC::check_owned(IObject * src) const { diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index 82583a0a..75abec14 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -24,7 +24,8 @@ namespace xo { Object::mm = nullptr; IObject * - Object::_forward(IObject * src, gc::IAlloc * gc) + Object::_forward(IObject * src, + gc::IAlloc * gc) { if (!src) return src; From 764e98e12e10c644b7347dd82d4d4e7f35eb1a0b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 2 Dec 2025 17:07:19 -0500 Subject: [PATCH 049/342] xo-alloc: UT for allocator interation + misc improvements --- include/xo/alloc/ArenaAllocT.hpp | 74 ------------- utest/ArenaAllocT.test.cpp | 67 ------------ utest/CMakeLists.txt | 1 - utest/Forwarding1.test.cpp | 10 +- utest/GC.test.cpp | 179 ++++++++++++++++++++++++++++++- utest/IAlloc.test.cpp | 118 ++++++++++++++++++-- 6 files changed, 295 insertions(+), 154 deletions(-) delete mode 100644 include/xo/alloc/ArenaAllocT.hpp delete mode 100644 utest/ArenaAllocT.test.cpp diff --git a/include/xo/alloc/ArenaAllocT.hpp b/include/xo/alloc/ArenaAllocT.hpp deleted file mode 100644 index 6c8a9b41..00000000 --- a/include/xo/alloc/ArenaAllocT.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/** @file Allocator.hpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#pragma once - -#include "xo/alloc/ArenaAlloc.hpp" - -namespace xo { - namespace gc { - /** @class allocator - * @brief c++ allocator with allocator traits - * - * Can use ArenaAllocT with std::map etc. - **/ - template - class ArenaAllocT { - public: - using value_type = T; - /** copy assignment: leave lhs allocator in place **/ - using propagate_on_container_copy_assignment = std::false_type; - /** move assignment: adopt rhs allocator - * (Forced: cannot mix allocations from different allocators - * within a container) - **/ - using propagate_on_container_move_assignment = std::true_type; - /** swap: also swap allocators - * (Forced: cannot mix allocations from different allocators - * within a containers) - **/ - using propagate_on_container_swap = std::true_type; - /** An ArenaAlloc instance is unique owner of its own memory: - * no other instance can dealloc - **/ - using is_always_equal = std::false_type; - - public: - explicit ArenaAllocT(ArenaAlloc * mm) : mm_{mm} {} - ArenaAllocT(const ArenaAllocT & other) = default; - - /** rebind ctor. Allows container to use supplied allocator - * for multiple types - **/ - template - ArenaAllocT(const ArenaAllocT & other) noexcept : mm_{other.mm_} {} - - T * allocate(size_t n) { - void * mem = mm_->alloc(n * sizeof(T)); - - return reinterpret_cast(mem); - } - - void deallocate(T * p, size_t n) noexcept { - assert(mm_->contains(p)); - assert(n == 0 || mm_->contains(p + n - 1)); - - //arena_->deallocate(p, n * sizeof(T)); - } - - bool operator==(const ArenaAllocT & other) const { - return mm_ == other.mm_; - } - - bool operator!=(const ArenaAllocT & other) const { - return mm_ != other.mm_; - } - - ArenaAlloc * mm_ = nullptr; - }; - } /*namespace gc*/ -} /*namespace xo*/ - -/* end Allocator.hpp */ diff --git a/utest/ArenaAllocT.test.cpp b/utest/ArenaAllocT.test.cpp deleted file mode 100644 index a9257173..00000000 --- a/utest/ArenaAllocT.test.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/** @file ArenaAllocT.test.cpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#include "xo/alloc/ArenaAllocT.hpp" -#include -#include - -namespace xo { - using xo::gc::ArenaAllocT; - using xo::gc::ArenaAlloc; - - namespace ut { - - namespace { - struct testcase_ArenaAllocT { - std::size_t arena_z_; - std::vector> kv_pairs_; - }; - - std::vector - s_testcase_v = { - { 4096, {} }, - { 4096, {{"a", "apple"}} }, - { 4096, {{"a", "apple"}, {"b", "banana"}, {"c", "carrot"}} }, - { 4096, {{"a", "apple"}, {"b", "banana"}, {"c", "carrot"}, {"e", "eggplant"}} }, - }; - } - - TEST_CASE("ArenaAllocT", "[alloc][traits]") - { - for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { - const testcase_ArenaAllocT & tc = s_testcase_v[i_tc]; - - constexpr bool c_debug_flag = false; - - auto arena = ArenaAlloc::make("arena", tc.arena_z_, c_debug_flag); - auto alloc = ArenaAllocT>(arena.get()); - - using TestMapType = std::map, - ArenaAllocT>>; - - TestMapType test_map(alloc); - - size_t n = 0; - for (const auto & kv_ix : tc.kv_pairs_) { - test_map[kv_ix.first] = kv_ix.second; - ++n; - - REQUIRE(test_map.size() == n); - - for (const auto & map_ix : test_map) { - // verify alloc was used for both Key + Value. - REQUIRE(arena->contains(&map_ix.first)); - REQUIRE(arena->contains(&map_ix.second)); - } - } - - } - } - } -} /*namespace xo*/ - -/* end ArenaAllocT.test.cpp */ diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 6c644f51..366cf664 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -7,7 +7,6 @@ set(UTEST_SRCS alloc_utest_main.cpp IAlloc.test.cpp ArenaAlloc.test.cpp - ArenaAllocT.test.cpp ListAlloc.test.cpp GC.test.cpp GcStatistics.test.cpp diff --git a/utest/Forwarding1.test.cpp b/utest/Forwarding1.test.cpp index f0a81c14..64c9f3f8 100644 --- a/utest/Forwarding1.test.cpp +++ b/utest/Forwarding1.test.cpp @@ -7,6 +7,7 @@ #include "ArenaAlloc.hpp" #include "xo/reflect/Reflect.hpp" #include +#include #include namespace xo { @@ -58,7 +59,14 @@ namespace xo { std::stringstream ss; ss << fwd; - REQUIRE(ss.str() == ""); + // forwarding printer looks like + // "" + // + + std::regex pattern(R"()"); + REQUIRE(std::regex_match(ss.str(), pattern)); + + //REQUIRE(ss.str() == ""); tag_config::tag_color_enabled = saved; } diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp index 9e6c17e3..c5245243 100644 --- a/utest/GC.test.cpp +++ b/utest/GC.test.cpp @@ -4,12 +4,16 @@ */ #include "xo/alloc/GC.hpp" +#include "xo/allocutil/gc_allocator_traits.hpp" #include namespace xo { + using xo::gc::IAlloc; using xo::gc::GC; + using xo::gc::gc_allocator_traits; using xo::gc::generation; using xo::gc::Config; + using xo::reflect::TaggedPtr; namespace ut { @@ -80,13 +84,186 @@ namespace xo { REQUIRE(gc->gc_in_progress() == false); REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 1); - } catch (std::exception &ex) { + } catch (std::exception & ex) { std::cerr << "caught exception: " << ex.what() << std::endl; REQUIRE(false); } } } + /** gc-enabled allocator **/ + namespace { + /** Setup test with custom allocator + * + **/ + template + struct TestClass : public GcObjectInterface { + TestClass() = default; + explicit TestClass(const Nested & member1) : member1_{member1} {} + + // using allocator_type = Allocator; + // using allocator_traits = xo::gc::gc_allocator_traits; + + /** stage1 - just allocates some memory using allocator **/ + template + static TestClass * make_0(Allocator & alloc) { + TestClass * mem = alloc.allocate(sizeof(TestClass)); + + /* but ctor will not have run, so ub to visit object */ + + return mem; + } + + /** stage2 - use allocator_traits construct **/ + template + static TestClass * make_1(Allocator & alloc) { + using traits = gc_allocator_traits; + + TestClass * mem = traits::allocate(alloc, 1); + + /* ctor will not have run here either */ + return mem; + } + + /** stage3 - invoke construct **/ + template + static TestClass * make_2(Allocator & alloc) { + using traits = gc_allocator_traits; + + TestClass * obj = traits::allocate(alloc, 1); + try { + // placement new + traits::construct(alloc, obj); + + return obj; + } catch(...) { + traits::deallocate(alloc, obj, 1); + throw; + } + } + + /** stage4 - init nested type **/ + template + static TestClass * make_3(Allocator & alloc) { + using traits = gc_allocator_traits; + + TestClass * obj = traits::allocate(alloc, 1); + try { + Nested nested; + + // placemenet new + traits::construct(alloc, obj); + + return obj; + } catch(...) { + traits::deallocate(alloc, obj, 1); + throw; + } + } + + // ----- inherited from Object ----- + + virtual TaggedPtr self_tp() const final override { + assert(false); return TaggedPtr::universal_null(); + } + virtual void display(std::ostream & os) const final override { + os << ""; + } + virtual std::size_t _shallow_size() const final override { + assert(false); return sizeof(*this); + } + virtual IObject * _shallow_copy(IAlloc * gc) const final override { + assert(false); return nullptr; + } + virtual std::size_t _forward_children(IAlloc * gc) final override { + assert(false); return _shallow_size(); + } + + Nested member1_; + }; + + struct MemberType { + MemberType() : ctor_ran_{true} {} + explicit MemberType(const std::vector> & mem2) : member2_{mem2} {} + + std::vector> member2_; + std::size_t ctor_ran_ = false; + }; + } + + TEST_CASE("gc_allocator_traits", "[alloc][gc]") + { + for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + try { + const testcase_gc & tc = s_testcase_v[i_tc]; + + up gc = GC::make( + {.initial_nursery_z_ = tc.nursery_z_, + .initial_tenured_z_ = tc.tenured_z_, + .incr_gc_threshold_ = tc.incr_gc_threshold_, + .full_gc_threshold_ = tc.full_gc_threshold_, + }); + + REQUIRE(gc.get()); + REQUIRE(gc->name() == "GC"); + + using ex_allocator = xo::gc::allocator; + using MyObjectInterface = gc_allocator_traits::template object_interface; + using NestedElementAllocator = xo::gc::allocator>; + using NestedType = MemberType; + using MyType = TestClass; + using MyAllocator = xo::gc::allocator; + + MyAllocator alloc(gc.get()); + + { + /* verify that MyType is constructible */ + MyType obj0; + + REQUIRE(obj0.member1_.ctor_ran_ == true); + } + + { + MyType * mem0 = MyType::make_0(alloc); + + REQUIRE(mem0 != nullptr); + REQUIRE(mem0->member1_.ctor_ran_ == false); + } + + { + MyType * mem1 = MyType::make_1(alloc); + + REQUIRE(mem1 != nullptr); + REQUIRE(mem1->member1_.ctor_ran_ == false); + } + + { + MyType * mem2 = MyType::make_2(alloc); + + REQUIRE(mem2 != nullptr); + REQUIRE(mem2->member1_.ctor_ran_ == true); + } + + { + MyType * mem3 = MyType::make_3(alloc); + + REQUIRE(mem3 != nullptr); + REQUIRE(mem3->member1_.ctor_ran_ == true); + } + + gp ptr; + { + REQUIRE(ptr.is_null()); + //ptr = MyType::make_0(); + } + } catch (std::exception & ex) { + std::cerr << "caught exception: " << ex.what() << std::endl; + REQUIRE(false); + } + } + + } + } /*namespace ut*/ } /*namespace xo*/ diff --git a/utest/IAlloc.test.cpp b/utest/IAlloc.test.cpp index 823791ab..7c1fdc56 100644 --- a/utest/IAlloc.test.cpp +++ b/utest/IAlloc.test.cpp @@ -3,26 +3,124 @@ * author: Roland Conybeare, Aug 2025 */ -#include "xo/allocutil/IAlloc.hpp" +//#include "xo/allocutil/IAlloc.hpp" +#include "xo/alloc/ArenaAlloc.hpp" +#include "xo/indentlog/print/tag.hpp" #include namespace xo { using xo::gc::IAlloc; + using xo::gc::ArenaAlloc; namespace ut { TEST_CASE("ialloc", "[alloc]") { + static_assert((sizeof(std::uintptr_t) == 8) && "possibly fine if this fails, but would want to know"); + REQUIRE(IAlloc::alloc_padding(0) == 0); - REQUIRE(IAlloc::alloc_padding(1) == 7); - REQUIRE(IAlloc::alloc_padding(2) == 6); - REQUIRE(IAlloc::alloc_padding(3) == 5); - REQUIRE(IAlloc::alloc_padding(4) == 4); - REQUIRE(IAlloc::alloc_padding(5) == 3); - REQUIRE(IAlloc::alloc_padding(6) == 2); - REQUIRE(IAlloc::alloc_padding(7) == 1); - REQUIRE(IAlloc::alloc_padding(8) == 0); - REQUIRE(IAlloc::alloc_padding(9) == 7); + + for (std::size_t i = 1; i < sizeof(std::uintptr_t); ++i) { + REQUIRE(IAlloc::alloc_padding(i) + i == IAlloc::c_alloc_alignment); + } + + REQUIRE(IAlloc::alloc_padding(IAlloc::c_alloc_alignment) == 0); + + for (std::size_t i = 1; i < sizeof(std::uintptr_t); ++i) { + REQUIRE(IAlloc::alloc_padding(IAlloc::c_alloc_alignment + i) + i == IAlloc::c_alloc_alignment); + } } + + /* although xo::gc::allocator is intended for + * IAlloc derivatives (so T is ArenaAlloc | GC), + * + * it only relies on allocate() and deallocate() methods + */ + + namespace { + struct TestCase { + explicit TestCase(size_t arena_z, size_t n, size_t n2) : arena_z_{arena_z}, n_{n}, n2_{n2} {} + + size_t arena_z_ = 0; + size_t n_ = 0; + size_t n2_ = 0; + }; + + std::vector s_testcase_v = { TestCase{1024*1024, 9, 13} }; + } + + TEST_CASE("gc.allocator", "[alloc]") + { + using xo::gc::allocator; + + constexpr bool c_debug_flag = false; + + for (size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + INFO(xtag("i_tc", i_tc)); + + const TestCase & tc = s_testcase_v[i_tc]; + + up mm1 = ArenaAlloc::make("arena1", + tc.arena_z_, + c_debug_flag); + up mm2 = ArenaAlloc::make("arena2", + tc.arena_z_, + c_debug_flag); + + REQUIRE(mm1.get()); + REQUIRE(mm1->allocated() == 0); + + allocator alloc1(mm1.get()); + allocator alloc1a(mm1.get()); + + REQUIRE(mm2.get()); + REQUIRE(mm2->allocated() == 0); + + allocator alloc2(mm2.get()); + + SECTION("IAlloc identity determines allocator equality") { + REQUIRE(alloc1 == alloc1a); + REQUIRE(alloc1 != alloc2); + } + + int * p1 = nullptr; + size_t z1 = 0; + + SECTION("alloc space for ints") { + p1 = alloc1.allocate(tc.n_); + + REQUIRE(p1 != nullptr); + + // note: allowing for alignment + REQUIRE(mm1->allocated() >= sizeof(int32_t) * tc.n_); + REQUIRE(mm1->allocated() < sizeof(int32_t) * tc.n_ + IAlloc::c_alloc_alignment); + z1 = mm1->allocated(); + + // deallocate exists.. + alloc1.deallocate(p1, tc.n_); + + // ..but is a no-op + REQUIRE(mm1->allocated() == z1); + } + + int * p2 = nullptr; + + SECTION("allocator independence") { + REQUIRE(mm2->allocated() == 0); + + p2 = alloc2.allocate(tc.n2_); + + REQUIRE(p2 != nullptr); + REQUIRE(p1 != p2); + + REQUIRE(mm2->allocated() >= sizeof(int32_t) * tc.n2_); + REQUIRE(mm2->allocated() < sizeof(int32_t) * tc.n2_ + IAlloc::c_alloc_alignment); + + // mm1 unaffected by mm2 allocation + REQUIRE(mm1->allocated() == z1); + } + } + } + } /*namespace ut*/ } /*namespace xo*/ From 43d79d78096284051edd076526d46e7916b28c91 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 2 Dec 2025 21:47:34 -0500 Subject: [PATCH 050/342] Gc.test.cpp expansion. Not working yet --- utest/GC.test.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp index c5245243..3912e8e4 100644 --- a/utest/GC.test.cpp +++ b/utest/GC.test.cpp @@ -182,11 +182,23 @@ namespace xo { Nested member1_; }; + template struct MemberType { - MemberType() : ctor_ran_{true} {} - explicit MemberType(const std::vector> & mem2) : member2_{mem2} {} + public: + using allocator_type = Allocator; + using vector_allocator_type = typename std::allocator_traits::template rebind_alloc>; + using vector_type = std::vector, vector_allocator_type>; - std::vector> member2_; + public: + MemberType() : ctor_ran_{true} {} + explicit MemberType(const Allocator & alloc) + : member2_{vector_allocator_type(alloc)}, ctor_ran_{true} {} + + explicit MemberType(const vector_type & mem2) : member2_{mem2}, ctor_ran_{true} {} + MemberType(const vector_type & mem2, const Allocator & alloc) + : member2_{mem2, vector_allocator_type(alloc)}, ctor_ran_{true} {} + + vector_type member2_; std::size_t ctor_ran_ = false; }; } From 146b730447e9b9fadbb86a699b20be0989774505 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 3 Dec 2025 00:14:09 -0500 Subject: [PATCH 051/342] fix unit tests to build on osx / clang16 --- utest/generation.test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/utest/generation.test.cpp b/utest/generation.test.cpp index 415d6258..edbebffa 100644 --- a/utest/generation.test.cpp +++ b/utest/generation.test.cpp @@ -4,6 +4,7 @@ */ #include "xo/alloc/generation.hpp" +#include #include #include From eee54530ff9676c419148b9e6b9746ee5cf8d515 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 3 Dec 2025 00:14:09 -0500 Subject: [PATCH 052/342] fix unit tests to build on osx / clang16 --- include/xo/reflectutil/reflect_struct_info.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/xo/reflectutil/reflect_struct_info.hpp b/include/xo/reflectutil/reflect_struct_info.hpp index 98313088..60c52392 100644 --- a/include/xo/reflectutil/reflect_struct_info.hpp +++ b/include/xo/reflectutil/reflect_struct_info.hpp @@ -6,6 +6,7 @@ #pragma once #include +#include namespace xo { namespace reflect { From 67cf4cc625e573cc7e85cb4d020a510babb54dc8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 3 Dec 2025 00:14:38 -0500 Subject: [PATCH 053/342] xo-alloc: utest: revert allocator changes in nested type --- utest/GC.test.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp index 3912e8e4..398336a8 100644 --- a/utest/GC.test.cpp +++ b/utest/GC.test.cpp @@ -94,13 +94,13 @@ namespace xo { /** gc-enabled allocator **/ namespace { /** Setup test with custom allocator - * + * **/ template struct TestClass : public GcObjectInterface { TestClass() = default; explicit TestClass(const Nested & member1) : member1_{member1} {} - + // using allocator_type = Allocator; // using allocator_traits = xo::gc::gc_allocator_traits; @@ -182,21 +182,22 @@ namespace xo { Nested member1_; }; - template + //template struct MemberType { public: - using allocator_type = Allocator; - using vector_allocator_type = typename std::allocator_traits::template rebind_alloc>; - using vector_type = std::vector, vector_allocator_type>; + //using allocator_type = Allocator; + //using vector_allocator_type = typename std::allocator_traits::template rebind_alloc>; + using vector_type = std::vector>; + //using vector_type = std::vector, vector_allocator_type>; public: MemberType() : ctor_ran_{true} {} - explicit MemberType(const Allocator & alloc) - : member2_{vector_allocator_type(alloc)}, ctor_ran_{true} {} + //explicit MemberType(const Allocator & alloc) + //: member2_{vector_allocator_type(alloc)}, ctor_ran_{true} {} explicit MemberType(const vector_type & mem2) : member2_{mem2}, ctor_ran_{true} {} - MemberType(const vector_type & mem2, const Allocator & alloc) - : member2_{mem2, vector_allocator_type(alloc)}, ctor_ran_{true} {} + //MemberType(const vector_type & mem2, const Allocator & alloc) + //: member2_{mem2, vector_allocator_type(alloc)}, ctor_ran_{true} {} vector_type member2_; std::size_t ctor_ran_ = false; @@ -223,6 +224,7 @@ namespace xo { using MyObjectInterface = gc_allocator_traits::template object_interface; using NestedElementAllocator = xo::gc::allocator>; using NestedType = MemberType; + //using NestedType = MemberType; using MyType = TestClass; using MyAllocator = xo::gc::allocator; @@ -273,7 +275,7 @@ namespace xo { REQUIRE(false); } } - + } } /*namespace ut*/ From 1a8771dc5d00f0453172d5a342b268e1500deb4a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 3 Dec 2025 10:22:52 -0500 Subject: [PATCH 054/342] xo-alloc: + utest vector w/ custom allocator --- utest/GC.test.cpp | 88 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp index 398336a8..03b5c50a 100644 --- a/utest/GC.test.cpp +++ b/utest/GC.test.cpp @@ -204,6 +204,94 @@ namespace xo { }; } + TEST_CASE("vector_custom_allocator", "[alloc][vector]") + { + for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + try { + const testcase_gc & tc = s_testcase_v[i_tc]; + + up gc = GC::make( + {.initial_nursery_z_ = tc.nursery_z_, + .initial_tenured_z_ = tc.tenured_z_, + .incr_gc_threshold_ = tc.incr_gc_threshold_, + .full_gc_threshold_ = tc.full_gc_threshold_, + }); + + REQUIRE(gc.get()); + REQUIRE(gc->name() == "GC"); + + using NestedElementAllocator = xo::gc::allocator>; + + NestedElementAllocator alloc(gc.get()); + + /** testv will use GC to allocaate element storage + * Attempt to gc will fail, because memory iteration + * won't work. + **/ + std::vector, + NestedElementAllocator> testv(alloc); + + testv.push_back(gp()); + +#ifdef NOPE + using ex_allocator = xo::gc::allocator; + using MyObjectInterface = gc_allocator_traits::template object_interface; + using NestedType = MemberType; + //using NestedType = MemberType; + using MyType = TestClass; + using MyAllocator = xo::gc::allocator; + + MyAllocator alloc(gc.get()); + + { + /* verify that MyType is constructible */ + MyType obj0; + + REQUIRE(obj0.member1_.ctor_ran_ == true); + } + + { + MyType * mem0 = MyType::make_0(alloc); + + REQUIRE(mem0 != nullptr); + REQUIRE(mem0->member1_.ctor_ran_ == false); + } + + { + MyType * mem1 = MyType::make_1(alloc); + + REQUIRE(mem1 != nullptr); + REQUIRE(mem1->member1_.ctor_ran_ == false); + } + + { + MyType * mem2 = MyType::make_2(alloc); + + REQUIRE(mem2 != nullptr); + REQUIRE(mem2->member1_.ctor_ran_ == true); + } + + { + MyType * mem3 = MyType::make_3(alloc); + + REQUIRE(mem3 != nullptr); + REQUIRE(mem3->member1_.ctor_ran_ == true); + } + + gp ptr; + { + REQUIRE(ptr.is_null()); + //ptr = MyType::make_0(); + } +#endif + } catch (std::exception & ex) { + std::cerr << "caught exception: " << ex.what() << std::endl; + REQUIRE(false); + } + } + + } + TEST_CASE("gc_allocator_traits", "[alloc][gc]") { for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { From 3c3709ba15a98e34a81d3d797436465bbb0a798b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 3 Dec 2025 15:36:59 -0500 Subject: [PATCH 055/342] xo-alloc / xo-ordinaltree: + concepts + allocator-aware --- include/xo/alloc/Object.hpp | 5 ++++- utest/GC.test.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 9681afab..d2e742a0 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -38,7 +38,7 @@ namespace xo { return dynamic_cast(x.ptr()); } - virtual ~Object() = default; + virtual ~Object() noexcept = default; /** memory allocator for objects. Likely this will be a GC instance, * but simple arena also supported. @@ -129,6 +129,9 @@ namespace xo { virtual std::size_t _forward_children(gc::IAlloc * gc) override = 0; }; + static_assert(std::is_destructible_v, "Object must be destructible"); + static_assert(std::is_nothrow_destructible_v, "Object must be noexcept destructible"); + template void Object::assign_member(gp parent, gp * lhs, gp rhs) diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp index 03b5c50a..90e22dfa 100644 --- a/utest/GC.test.cpp +++ b/utest/GC.test.cpp @@ -200,7 +200,7 @@ namespace xo { //: member2_{mem2, vector_allocator_type(alloc)}, ctor_ran_{true} {} vector_type member2_; - std::size_t ctor_ran_ = false; + bool ctor_ran_ = false; }; } From e4a4e0dc872bee27d6833ad299533531dc2b3fb3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 4 Dec 2025 17:28:59 -0500 Subject: [PATCH 056/342] xo-alloc: + static_asserts in GC root helpers --- include/xo/alloc/GC.hpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index be2ff071..214027b7 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -249,10 +249,18 @@ namespace xo { void remove_gc_root(IObject ** addr); /** convenience wrapper **/ + template - void add_gc_root_dwim(gp * p) { this->add_gc_root(reinterpret_cast(p->ptr_address())); } + void add_gc_root_dwim(gp * p) { + static_assert(std::is_convertible_v); + this->add_gc_root(reinterpret_cast(p->ptr_address())); + } + template - void remove_gc_root_dwim(gp * p) { this->remove_gc_root(reinterpret_cast(p->ptr_address())); } + void remove_gc_root_dwim(gp * p) { + static_assert(std::is_convertible_v); + this->remove_gc_root(reinterpret_cast(p->ptr_address())); + } /** may optionally use this to observe GC copy phase. * Will be invoked once _per surviving object_, so not cheap. From 676a9d0d62e7fde60aa0af22ce9e054be229eee9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 4 Dec 2025 17:29:27 -0500 Subject: [PATCH 057/342] xo-alloc: + comments on design --- include/xo/alloc/Object.hpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index d2e742a0..c1217418 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -20,14 +20,18 @@ namespace xo { /** Root class for all xo GC-collectable objects. * - * Design note: - * - * relying on inheritance means we insist that GC traits - * for a type appear directly in that type's vtable, and at specific locations. - * This implies one level of indirection when GC traverses an instance. - * - * Would be feasible to relax the must-inherit-from-Object constraint - * by having GC use its own wrapper, at cost of an extra layer of indirection + * Design notes: + * 1. xo::IObject -> xo-allocutil header-only library + * xo::Object -> xo-alloc ordinary library + * 2. relying on inheritance means we insist that GC traits + * for a type appear directly in that type's vtable, and at specific locations. + * This implies one level of indirection when GC traverses an instance. + * 3. Could adapt a gc-aware XO library (such as xo-ordinaltree) + * to a non-xo garbage collector. + * Would still need to use xo::IObject and xo::gc::gc_allocator_traits, + * but not necessarily xo::Object + * 4. Would be feasible to relax the must-inherit-from-Object constraint + * by having GC use its own wrapper, at cost of an extra layer of indirection **/ class Object : public IObject { public: @@ -49,7 +53,9 @@ namespace xo { /** assign value @p rhs to member @p *lhs of @p parent. * if assignment creates a cross-generational or cross-checkpoint pointer, - * add mutation log entry + * add mutation log entry. + * + * DEPRECATED. prefer IObject::_gc_assign_member, for explicit alloc **/ template static void assign_member(gp parent, gp * lhs, gp rhs); From bd0b1b1f719706974abce1a9706b11625df9a4d0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 4 Dec 2025 21:31:55 -0500 Subject: [PATCH 058/342] xo-alloc/xo-ordinaltree: refactor rbtree Node alloc progress toward careful gc-aware assignment --- include/xo/alloc/Object.hpp | 2 +- src/alloc/Object.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index c1217418..742fba4c 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -118,7 +118,7 @@ namespace xo { /** tagged pointer with runtime type information **/ - virtual TaggedPtr self_tp() const = 0; + virtual TaggedPtr self_tp() const; /** print on stream @p os **/ virtual void display(std::ostream & os) const = 0; diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index 75abec14..ab23b76a 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -20,9 +20,18 @@ operator new (std::size_t z, const xo::Cpof & cpof) } namespace xo { + using xo::reflect::TaggedPtr; + gc::IAlloc * Object::mm = nullptr; + TaggedPtr + Object::self_tp() const + { + assert(false); + return TaggedPtr::universal_null(); + } + IObject * Object::_forward(IObject * src, gc::IAlloc * gc) From e8d755252a42b291ceb27509719901e09f9c503a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 4 Dec 2025 21:44:22 -0500 Subject: [PATCH 059/342] xo-alloc: provide default Object::display() method So we can remove from FallbackObjectInterface and IObject --- src/alloc/Object.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index ab23b76a..b0be501b 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -32,6 +32,12 @@ namespace xo { return TaggedPtr::universal_null(); } + void + Object::display(std::ostream & os) const + { + os << ""; + } + IObject * Object::_forward(IObject * src, gc::IAlloc * gc) From 40281c4e0ab5e95a8180cecaeb1a2880ab7b7060 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 4 Dec 2025 23:38:56 -0500 Subject: [PATCH 060/342] xo-ordinaltree: rbtree ops satisfy gc write barriers --- include/xo/alloc/Object.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 742fba4c..5f31356f 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -121,7 +121,7 @@ namespace xo { virtual TaggedPtr self_tp() const; /** print on stream @p os **/ - virtual void display(std::ostream & os) const = 0; + virtual void display(std::ostream & os) const; // Inherited from IObject.. From b6ccde3ddcf9858a1981731fec14c04de7a5acd6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 5 Dec 2025 10:00:36 -0500 Subject: [PATCH 061/342] xo-alloc: check_write_barrier to verify mutation log --- include/xo/alloc/ArenaAlloc.hpp | 1 - include/xo/alloc/GC.hpp | 16 ++++- include/xo/alloc/generation.hpp | 7 +++ src/alloc/GC.cpp | 104 +++++++++++++++++++++++++++++++- src/alloc/generation.cpp | 9 +++ 5 files changed, 133 insertions(+), 4 deletions(-) diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 1f48121b..df4d2a01 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -177,7 +177,6 @@ namespace xo { virtual std::byte * alloc(std::size_t z) final override; virtual bool check_owned(IObject * src) const final override; - ArenaAlloc & operator=(const ArenaAlloc &) = delete; ArenaAlloc & operator=(ArenaAlloc &&) = delete; diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 214027b7..e5dd6781 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -337,6 +337,12 @@ namespace xo { * - incr GC -> if not tenured **/ virtual bool check_move(IObject * src) const final override; + /** if src is cross-generational (or cross-checkpoint), verify that it + * is recorded in mutation log, + * given an object @p parent that contains object pointer @p lhs + **/ + virtual bool check_write_barrier(IObject * parent, IObject ** lhs, bool may_throw) const final; + virtual std::byte * alloc(std::size_t z) final override; virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; @@ -447,7 +453,15 @@ namespace xo { std::vector gc_root_v_; /** log cross-generational and cross-checkpoint mutations. - * These need to be adjusted on next incremental collection + * These need to be adjusted on next incremental collection. + * + * mutation_log_[tospace] accumulates {xgen,xckp} pointers until + * the next GC. + * + * See GC aux functions + * @ref incremental_gc_forward_mlog + * @ref full_gc_forward_mlog + * **/ std::array, role2int(role::N)> mutation_log_; /** temporary mutation log (for deferred entries) **/ diff --git a/include/xo/alloc/generation.hpp b/include/xo/alloc/generation.hpp index 0acd943a..9f122044 100644 --- a/include/xo/alloc/generation.hpp +++ b/include/xo/alloc/generation.hpp @@ -41,6 +41,13 @@ namespace xo { return generation::tenured; } + const char * genresult2str(generation_result x); + + inline std::ostream & operator<<(std::ostream & os, generation_result x) { + os << genresult2str(x); + return os; + } + } /*namespace gc*/ } /*namespace xo*/ diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 40234bf3..5cfdd9fc 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -587,6 +587,104 @@ namespace xo { || (this->tospace_generation_of(src) != gc::generation_result::tenured)); } + bool + GC::check_write_barrier(IObject * parent, + IObject ** lhs, + bool may_throw_flag) const + { + if (!this->contains(parent)) { + if (may_throw_flag) { + throw std::runtime_error(tostr("GC::check_write_barrier", + ": expected parent object P in GC to-space", + xtag("P", parent))); + } + return false; + } + + std::size_t parent_z = parent->_shallow_size(); + + std::byte * parent_addr = reinterpret_cast(parent); + std::byte * lhs_addr = reinterpret_cast(lhs); + + if ((lhs_addr < parent_addr) || (parent_addr + parent_z < lhs_addr)) { + if (may_throw_flag) { + throw std::runtime_error + (tostr("GC::check_write_barrier", + ": expected lhs address L within address extent z of parent P", + xtag("P", parent), xtag("z", parent_z), + xtag("P+z", parent_addr + parent_z), + xtag("L", lhs))); + } + return false; + } + + IObject * rhs = *lhs; + + auto parent_gen = tospace_generation_of(parent); + auto rhs_gen = tospace_generation_of(rhs); + + switch(parent_gen) { + case generation_result::nursery: + if (is_before_checkpoint(parent)) { + switch(rhs_gen) { + case generation_result::nursery: + if (is_before_checkpoint(rhs)) { + /* no mlog entry needed */ + return true; + } else { + /* need to check mlog */ + ; + } + break; + case generation_result::tenured: + /* no mlog entry needed */ + return true; + case generation_result::not_found: + /* possible non-gc rhs */ + return true; + } + } else { + /* no mlog entry needed */ + return true; + } + break; + case generation_result::tenured: + switch(rhs_gen) { + case generation_result::nursery: + /* need to check mlog */ + break; + case generation_result::tenured: + /* no mlog entry needed */ + return true; + case generation_result::not_found: + /* possible non-gc rhs */ + return true; + } + case generation_result::not_found: + /* already excluded -> impossible */ + assert(false && "already verified parent owned by GC"); + } + + /* control here -> expect mutation log entry. + * search mutation log + verify such entry exists + */ + for (MutationLogEntry & mlog : *(mutation_log_[role2int(role::to_space)])) { + if ((mlog.parent() == parent) && (mlog.lhs() == lhs)) { + return true; + } + mlog.lhs(); + } + + if (may_throw_flag) { + throw std::runtime_error + (tostr("GC::check_write_barrier", + ": expected mlog entry for xgen pointer L->C within parent P", + xtag("P", parent), xtag("L", lhs), xtag("C", rhs), + xtag("gen(P)", parent_gen), xtag("gen(C)", rhs_gen))); + } + return false; + } + void GC::swap_nursery() { @@ -1126,9 +1224,11 @@ namespace xo { scope log(XO_DEBUG(config_.debug_flag_)); if (upto == generation::tenured) { - this->full_gc_forward_mlog(&object_statistics_sae_[gen2int(generation::tenured)]); + this->full_gc_forward_mlog + (&object_statistics_sae_[gen2int(generation::tenured)]); } else { - this->incremental_gc_forward_mlog(&object_statistics_sae_[gen2int(generation::nursery)]); + this->incremental_gc_forward_mlog + (&object_statistics_sae_[gen2int(generation::nursery)]); } } diff --git a/src/alloc/generation.cpp b/src/alloc/generation.cpp index 54c151ac..a0ae9e65 100644 --- a/src/alloc/generation.cpp +++ b/src/alloc/generation.cpp @@ -16,6 +16,15 @@ namespace xo { return "?generation"; } + const char * genresult2str(generation_result x) { + switch (x) { + case generation_result::nursery: return "nursery"; + case generation_result::tenured: return "tenured"; + case generation_result::not_found: return "not-found"; + } + return "?generation_result"; + } + } /*namespace gc*/ } /*namespace xo*/ From bd8ca68e7c4eb1410994c6dceecff9d47077760b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 5 Dec 2025 18:38:29 -0500 Subject: [PATCH 062/342] xo-ordinaltree: expand unittest + debug logging --- include/xo/alloc/GC.hpp | 4 +-- src/alloc/GC.cpp | 79 +++++++++++++++++++++++++++++++++++------ src/alloc/Object.cpp | 14 ++++++-- utest/GC.test.cpp | 23 ++++++++++++ 4 files changed, 106 insertions(+), 14 deletions(-) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index e5dd6781..d8acc08c 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -107,7 +107,7 @@ namespace xo { bool is_dead() const { return false; } MutationLogEntry update_parent_moved(IObject * parent_to) const; - void fixup_parent_child_moved(IObject * child_to) { *lhs_ = child_to; } + void fixup_parent_child_moved(IObject * child_to); private: IObject * parent_ = nullptr; @@ -341,7 +341,7 @@ namespace xo { * is recorded in mutation log, * given an object @p parent that contains object pointer @p lhs **/ - virtual bool check_write_barrier(IObject * parent, IObject ** lhs, bool may_throw) const final; + virtual bool check_write_barrier(const void * parent, const void * const * lhs, bool may_throw) const final; virtual std::byte * alloc(std::size_t z) final override; virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index 5cfdd9fc..dd17fd3b 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -58,6 +58,12 @@ namespace xo { reinterpret_cast(lhs_to)); } + void + MutationLogEntry::fixup_parent_child_moved(IObject * child_to) + { + *(this->lhs_) = child_to; + } + GC::GC(const Config & config) : config_{config} { @@ -508,12 +514,17 @@ namespace xo { assert(retval); + log && log(xtag("retval", retval)); + return retval; } void GC::assign_member(IObject * parent, IObject ** lhs, IObject * rhs) { + scope log(XO_DEBUG(config_.debug_flag_), + xtag("parent", parent), xtag("lhs", lhs), xtag("rhs", rhs)); + ++gc_statistics_.n_mutation_; *lhs = rhs; @@ -532,23 +543,28 @@ namespace xo { { case generation_result::tenured: /* only need to log mutations that create tenured->nursery pointers */ + log && log(xtag("act", "any->T no log")); return; case generation_result::nursery: switch (tospace_generation_of(parent)) { case generation_result::nursery: if (is_before_checkpoint(parent)) { + log && log(xtag("act", "N1->N0 must mlog")); + // N1->N0, so must log this->mutation_log_[role2int(role::to_space)]->push_back(MutationLogEntry(parent, lhs)); ++(this->gc_statistics_.n_logged_mutation_); ++(this->gc_statistics_.n_xckp_mutation_); } else { // parent in N0, not an xckp mutation - return; + log && log(xtag("act", "N0->any no long")); } break; case generation_result::tenured: // T->N, so must log + log && log(xtag("act", "T->N must mlog")); + this->mutation_log_[role2int(role::to_space)]->push_back(MutationLogEntry(parent, lhs)); ++(this->gc_statistics_.n_logged_mutation_); ++(this->gc_statistics_.n_xgen_mutation_); @@ -556,11 +572,13 @@ namespace xo { case generation_result::not_found: // parent is global // This may be ok (provided lhs is a gc root) + log && log(xtag("act", "root->any no log")); break; } break; case generation_result::not_found: + log && log(xtag("act", "any->root no log")); // child is global; // logging not required @@ -571,6 +589,8 @@ namespace xo { void GC::forward_inplace(IObject ** lhs) { + scope log(XO_DEBUG(config_.debug_flag_), xtag("lhs", lhs)); + Object::_forward_inplace(lhs, this); } @@ -588,10 +608,13 @@ namespace xo { } bool - GC::check_write_barrier(IObject * parent, - IObject ** lhs, + GC::check_write_barrier(const void * parent, + const void * const * lhs, bool may_throw_flag) const { + scope log(XO_DEBUG(config_.debug_flag_), + xtag("P", parent), xtag("L", lhs)); + if (!this->contains(parent)) { if (may_throw_flag) { throw std::runtime_error(tostr("GC::check_write_barrier", @@ -601,10 +624,11 @@ namespace xo { return false; } +#ifdef NOPE // don't want to assume IObject* std::size_t parent_z = parent->_shallow_size(); - std::byte * parent_addr = reinterpret_cast(parent); - std::byte * lhs_addr = reinterpret_cast(lhs); + const std::byte * parent_addr = reinterpret_cast(parent); + const std::byte * lhs_addr = reinterpret_cast(lhs); if ((lhs_addr < parent_addr) || (parent_addr + parent_z < lhs_addr)) { if (may_throw_flag) { @@ -617,12 +641,21 @@ namespace xo { } return false; } +#endif - IObject * rhs = *lhs; + const void * rhs = *lhs; + + if (!rhs) + return true; auto parent_gen = tospace_generation_of(parent); auto rhs_gen = tospace_generation_of(rhs); + log && log(xtag("C", rhs), + xtag("gen(P)", parent_gen), xtag("gen(C)", rhs_gen), + xtag("P.before-ckp", is_before_checkpoint(parent)), + xtag("C.before-ckp", is_before_checkpoint(rhs))); + switch(parent_gen) { case generation_result::nursery: if (is_before_checkpoint(parent)) { @@ -630,21 +663,25 @@ namespace xo { case generation_result::nursery: if (is_before_checkpoint(rhs)) { /* no mlog entry needed */ + log && log(xtag("msg", "N1->N1 - trivial")); return true; } else { /* need to check mlog */ - ; + log && log(xtag("msg", "N1->N0 - xgen")); } break; case generation_result::tenured: /* no mlog entry needed */ + log && log(xtag("msg", "N1->T - trivial")); return true; case generation_result::not_found: /* possible non-gc rhs */ + log && log(xtag("msg", "non-gc rhs - trivial")); return true; } } else { /* no mlog entry needed */ + log && log(xtag("msg", "N0->any - trivial")); return true; } break; @@ -652,16 +689,21 @@ namespace xo { switch(rhs_gen) { case generation_result::nursery: /* need to check mlog */ + log && log(xtag("msg", "T->N - xgen")); break; case generation_result::tenured: /* no mlog entry needed */ + log && log(xtag("msg", "T->T - trivial")); return true; case generation_result::not_found: /* possible non-gc rhs */ + log && log(xtag("msg", "non-gc rhs - trivial")); return true; } + break; case generation_result::not_found: /* already excluded -> impossible */ + log && log(xtag("msg", "assert")); assert(false && "already verified parent owned by GC"); } @@ -669,7 +711,7 @@ namespace xo { * search mutation log + verify such entry exists */ for (MutationLogEntry & mlog : *(mutation_log_[role2int(role::to_space)])) { - if ((mlog.parent() == parent) && (mlog.lhs() == lhs)) { + if ((mlog.parent() == parent) && ((const void * const *)mlog.lhs() == lhs)) { return true; } mlog.lhs(); @@ -872,7 +914,7 @@ namespace xo { for (MutationLogEntry & from_entry : *from_mlog) { if (log) { - if (i_from % 10000 == 0) + if (i_from % 10000 == 0 || true) log(xtag("i_from", i_from)); } @@ -905,8 +947,12 @@ namespace xo { ++n_rescue; + log && log(xtag("parent", parent), xtag("act", "move child"), xtag("child.from", child_from)); + Object::_deep_move(child_from, this, per_type_stats); + log && log(xtag("child.to", child_from->_destination())); + // C forwards to C', fall thru to parent fixup below // (a) T->N1' // (c) T->T @@ -924,13 +970,24 @@ namespace xo { IObject * child_to = child_from->_destination(); + log && log(xtag("act", "fixup parent"), xtag("parent", parent), xtag("lhs", from_entry.lhs()), xtag("child.from", child_from), xtag("child.to", child_to)); + from_entry.fixup_parent_child_moved(child_to); + { + // verify fixup was effective + IObject * child_from2 = from_entry.child(); + assert(child_from2 == child_to); + } + + // P->C', loc(C') in {N1', T'} if (tospace_generation_of(child_to) == generation_result::nursery) { // (b) loc(P)=T, loc(C')=N1'; also case (a) + log && log(xtag("act", "still xgen -> keep mlog entry")); + // still have xgen pointer, so need mlog for it to_mlog->push_back(from_entry); } else { @@ -972,6 +1029,8 @@ namespace xo { } } else { + log && log("defer"); + // loc(P) = N1, loc(C) = N0, P may be garbage // Includes cases: // (e) P->C, C not moved @@ -1347,7 +1406,7 @@ namespace xo { void GC::execute_gc(generation upto) { - scope log(XO_DEBUG(config_.stats_flag_)); + scope log(XO_DEBUG(config_.stats_flag_ || config_.debug_flag_)); auto t0 = std::chrono::steady_clock::now(); diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index b0be501b..b0a52f59 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -42,18 +42,24 @@ namespace xo { Object::_forward(IObject * src, gc::IAlloc * gc) { + scope log(XO_DEBUG(gc->debug_flag()), xtag("src", src)); + if (!src) return src; - if (src->_is_forwarded()) + if (src->_is_forwarded()) { + log && log("already forwarded", xtag("dest", src->_offset_destination(src))); return src->_offset_destination(src); + } if (gc->check_move(src)) { + log && log("needs forwarding"); Object::_shallow_move(src, gc); /* *src is now a forwarding pointer to a copy in to-space */ return src->_offset_destination(src); } else { + log && log("already tenured + incr collection"); /* don't move tenured objects during incremental collection */ return src; } @@ -62,6 +68,8 @@ namespace xo { IObject * Object::_deep_move(IObject * from_src, gc::GC * gc, gc::ObjectStatistics * /*stats*/) { + scope log(XO_DEBUG(gc->config().debug_flag_)); + using gc::generation; if (!from_src) @@ -146,13 +154,15 @@ namespace xo { do { fixup_work = 0; - auto fixup_generation = [gc, &gray_lo_v](generation gen) { + auto fixup_generation = [gc, &log, &gray_lo_v](generation gen) { std::size_t work = 0; while(gray_lo_v[gen2int(gen)] < gc->free_ptr(gen)) { Object * x = reinterpret_cast(gray_lo_v[gen2int(gen)]); // update per-class stats here + log && log("fwd children", xtag("x", x)); + std::size_t xz = x->_forward_children(gc); // must pad xz to multiple of word size, diff --git a/utest/GC.test.cpp b/utest/GC.test.cpp index 90e22dfa..f178f4a8 100644 --- a/utest/GC.test.cpp +++ b/utest/GC.test.cpp @@ -202,6 +202,29 @@ namespace xo { vector_type member2_; bool ctor_ran_ = false; }; + +#ifdef NOT_YET + struct MemberType2 { + public: + MemberType2() = default; + /** GC hooks rely on copy constructor. But can't write it without allocator state. + * Therefore: need copy-like constructor that takes allocator argument + **/ + + template + explicit MemberType2(Allocator & alloc, uint64 payload) { + using traits = gc_allocator_traits; + + uint64_t * ptr = traits::allocate(alloc, 1); + + this->payload_ = payload; + this->ctor_ran_ = true; + } + + uint64_t * payload_ = nullptr; + bool ctor_ran_ = false; + } +#endif } TEST_CASE("vector_custom_allocator", "[alloc][vector]") From 1b93c9a427e6d8673a95fc2d4d738f45438d3f23 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 5 Dec 2025 19:54:00 -0500 Subject: [PATCH 063/342] xo-ordinaltree: start work on gc-aware Key,Value in rbtree --- include/xo/alloc/Object.hpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 5f31356f..dce67c11 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -5,15 +5,16 @@ #pragma once -#include "xo/reflect/TaggedPtr.hpp" -#include "IAlloc.hpp" #include "xo/allocutil/IObject.hpp" +#include "xo/reflect/TaggedPtr.hpp" +#include "xo/allocutil/ObjectVisitor.hpp" #include "xo/allocutil/gc_ptr.hpp" #include #include namespace xo { namespace gc { + class IAlloc; class GC; class ObjectStatistics; }; @@ -147,6 +148,18 @@ namespace xo { reinterpret_cast(rhs.ptr())); } + namespace gc { + template + class ObjectVisitor> { + public: + void forward_children(gp & target, + IAlloc * gc) + { + Object::_forward_inplace(target, gc); + } + }; + } + std::ostream & operator<< (std::ostream & os, gp x); From 7b5198be081699ade480dcb4d0a0b8b01f4d5473 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 6 Dec 2025 19:42:36 -0500 Subject: [PATCH 064/342] xo-ordinaltree: work on gp-key unit test --- include/xo/alloc/Object.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index dce67c11..9665e66a 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -152,8 +152,8 @@ namespace xo { template class ObjectVisitor> { public: - void forward_children(gp & target, - IAlloc * gc) + static void forward_children(gp & target, + IAlloc * gc) { Object::_forward_inplace(target, gc); } From 05ab69384af65dc9da25885d6a9e4641e8b52b96 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 11 Dec 2025 11:14:46 -0500 Subject: [PATCH 065/342] xo-alloc2: work on fomo Arena --- src/alloc/ArenaAlloc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index 886b6a70..d7f794f3 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -374,7 +374,7 @@ namespace xo { ArenaAlloc::clear() { this->set_free_ptr(lo_); - this->limit_ = hi_; + //this->limit_ = hi_; } void From 412697bbb875fcbb7d4f5bffa1d7f74a283b28cf Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 5 Jan 2026 21:49:33 -0500 Subject: [PATCH 066/342] refactor: move xo::facet::typeseq to xo-reflectutil/ prep for adding xo-arena/ --- CMakeLists.txt | 2 +- cmake/xo_reflectutilConfig.cmake.in | 7 +-- include/xo/reflectutil/typeseq.hpp | 88 +++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 include/xo/reflectutil/typeseq.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a231f5dc..4f3f6dee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets # ---------------------------------------------------------------- # dependencies -xo_headeronly_dependency(${SELF_LIB} xo_flatstring) +#xo_headeronly_dependency(${SELF_LIB} xo_flatstring) #xo_headeronly_dependency(${SELF_LIB} randomgen) # etc.. diff --git a/cmake/xo_reflectutilConfig.cmake.in b/cmake/xo_reflectutilConfig.cmake.in index b7a5a0a2..26df0fc7 100644 --- a/cmake/xo_reflectutilConfig.cmake.in +++ b/cmake/xo_reflectutilConfig.cmake.in @@ -6,12 +6,7 @@ include(CMakeFindDependencyMacro) # must coordinate with xo_dependency() calls # in xo-reactor/src/reactor/CMakeLists.txt # -find_dependency(xo_flatstring) -#find_dependency(subsys) -#find_dependency(Eigen3) -#find_dependency(webutil) -#find_dependency(printjson) -#find_dependency(callback) +#find_dependency(xo_flatstring) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") check_required_components("@PROJECT_NAME@") diff --git a/include/xo/reflectutil/typeseq.hpp b/include/xo/reflectutil/typeseq.hpp new file mode 100644 index 00000000..dd0b869a --- /dev/null +++ b/include/xo/reflectutil/typeseq.hpp @@ -0,0 +1,88 @@ +/** @file typeseq.hpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#pragma once + +#include +#include + +namespace xo { + namespace reflect { + /** + * Tag here so we can preserve header-only implementation + * and still have static variable + */ + template + struct typeseq_impl { + explicit typeseq_impl(int32_t s) : seqno_{s} {} + + /** Can't have this be constexpr. + * We need ids in shared libraries to be generated + * at load time to avoid false positives + * + * Return unique id number for each type. + * Numbers are sequentially allocated, so can use + * as vector indices + * + * Conversely note that built-in typeinfo may + * return false negatives across library boundaries + * when using clang. + **/ + template + static typeseq_impl id() { + static bool armed = true; + static int32_t id = 0; + + if (armed) { + armed = false; + id = ++s_next_id; + } + + return typeseq_impl(id); + + } + + /** 'anonymous' sentinel type. + * Niche uses for this, e.g. untyped allocator + **/ + static typeseq_impl anon() { + return typeseq_impl(-1); + } + + int32_t seqno() const { return seqno_; } + + private: + static int32_t s_next_id; + + int32_t seqno_; + }; + + template + int32_t typeseq_impl::s_next_id = 0; + + template + inline bool + operator==(const typeseq_impl & lhs, const typeseq_impl & rhs) { + return lhs.seqno() == rhs.seqno(); + } + + template + inline bool + operator!=(const typeseq_impl & lhs, const typeseq_impl & rhs) { + return lhs.seqno() != rhs.seqno(); + } + + template + inline std::ostream & + operator<<(std::ostream & s, const typeseq_impl & x) { + s << x.seqno(); + return s; + } + + using typeseq = typeseq_impl<>; + } /*namespace reflect*/ +} /*namespace xo*/ + +/* end typeseq.hpp */ From b9921d410873b5255eef1e8ac18c715b834aeeb8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 10 Jan 2026 12:39:09 -0500 Subject: [PATCH 067/342] + xo-tokenizer2 xo-reader2 xo-expression2 xo-interpreter2 2nd gen schematika interpreter using fomo --- CMakeLists.txt | 37 + README.md | 1 - cmake/xo-bootstrap-macros.cmake | 33 + cmake/xo_tokenizer2Config.cmake.in | 12 + example/CMakeLists.txt | 1 + example/tokenrepl/CMakeLists.txt | 15 + example/tokenrepl/tokenrepl.cpp | 128 ++++ include/xo/tokenizer2/.gitkeep | 0 include/xo/tokenizer2/TkInputState.hpp | 230 +++++++ include/xo/tokenizer2/Token.hpp | 226 ++++++ include/xo/tokenizer2/Tokenizer.hpp | 167 +++++ include/xo/tokenizer2/TokenizerError.hpp | 114 ++++ include/xo/tokenizer2/buffer.hpp | 328 +++++++++ include/xo/tokenizer2/scan_result.hpp | 81 +++ include/xo/tokenizer2/span.hpp | 291 ++++++++ include/xo/tokenizer2/tokentype.hpp | 192 ++++++ src/tokenizer2/CMakeLists.txt | 15 + src/tokenizer2/TkInputState.cpp | 151 ++++ src/tokenizer2/Token.cpp | 259 +++++++ src/tokenizer2/Tokenizer.cpp | 836 +++++++++++++++++++++++ src/tokenizer2/TokenizerError.cpp | 60 ++ src/tokenizer2/scan_result.cpp | 43 ++ src/tokenizer2/tokentype.cpp | 74 ++ 23 files changed, 3293 insertions(+), 1 deletion(-) create mode 100644 CMakeLists.txt delete mode 100644 README.md create mode 100644 cmake/xo-bootstrap-macros.cmake create mode 100644 cmake/xo_tokenizer2Config.cmake.in create mode 100644 example/CMakeLists.txt create mode 100644 example/tokenrepl/CMakeLists.txt create mode 100644 example/tokenrepl/tokenrepl.cpp create mode 100644 include/xo/tokenizer2/.gitkeep create mode 100644 include/xo/tokenizer2/TkInputState.hpp create mode 100644 include/xo/tokenizer2/Token.hpp create mode 100644 include/xo/tokenizer2/Tokenizer.hpp create mode 100644 include/xo/tokenizer2/TokenizerError.hpp create mode 100644 include/xo/tokenizer2/buffer.hpp create mode 100644 include/xo/tokenizer2/scan_result.hpp create mode 100644 include/xo/tokenizer2/span.hpp create mode 100644 include/xo/tokenizer2/tokentype.hpp create mode 100644 src/tokenizer2/CMakeLists.txt create mode 100644 src/tokenizer2/TkInputState.cpp create mode 100644 src/tokenizer2/Token.cpp create mode 100644 src/tokenizer2/Tokenizer.cpp create mode 100644 src/tokenizer2/TokenizerError.cpp create mode 100644 src/tokenizer2/scan_result.cpp create mode 100644 src/tokenizer2/tokentype.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..9eee1160 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,37 @@ +# xo-tokenizer2/CMakeLists.txt + +cmake_minimum_required(VERSION 3.10) + +project(xo_tokenizer2 VERSION 1.0) +enable_language(CXX) + +include(GNUInstallDirs) +include(cmake/xo-bootstrap-macros.cmake) + +xo_cxx_toplevel_options3() + +# ---------------------------------------------------------------- +# c++ settings + +# one-time project-specific c++ flags. usually empty +set(PROJECT_CXX_FLAGS "") +add_definitions(${PROJECT_CXX_FLAGS}) + +# ---------------------------------------------------------------- +# output targets + +add_subdirectory(src/tokenizer2) +add_subdirectory(example) +#add_subdirectory(utest) +xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) + +if (XO_ENABLE_EXAMPLES) + install(TARGETS xo_tokenizer2_repl DESTINATION bin/xo/example/tokenizer2) +endif() + +# ---------------------------------------------------------------- +# docs targets depends on all the other library/utest targets +# +#add_subdirectory(docs) + +# end CMakeLists.txt diff --git a/README.md b/README.md deleted file mode 100644 index d64791cf..00000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# xo-tokenizer2 diff --git a/cmake/xo-bootstrap-macros.cmake b/cmake/xo-bootstrap-macros.cmake new file mode 100644 index 00000000..2cf387e5 --- /dev/null +++ b/cmake/xo-bootstrap-macros.cmake @@ -0,0 +1,33 @@ +# ---------------------------------------------------------------- +# for example: +# $ PREFIX=/usr/local # for example +# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=$PREFIX -B .build +# +# will get +# CMAKE_MODULE_PATH +# from xo-cmake-config --cmake-module-path +# +# and expect .cmake macros in +# CMAKE_MODULE_PATH/xo_macros/xo_cxx.cmake +# ---------------------------------------------------------------- + +find_program(XO_CMAKE_CONFIG_EXECUTABLE NAMES xo-cmake-config REQUIRED) + +if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL "prefix")) + message(FATAL "could not find xo-cmake-config executable") +endif() + +if (NOT XO_SUBMODULE_BUILD) + if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix)) + # default to typical install location for xo-project-macros + execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --cmake-module-path OUTPUT_VARIABLE CMAKE_MODULE_PATH) + message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + endif() +endif() + +# needs to have been installed somewhere on CMAKE_MODULE_PATH, +# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX) +# +include(xo_macros/xo_cxx) + +xo_cxx_bootstrap_message() diff --git a/cmake/xo_tokenizer2Config.cmake.in b/cmake/xo_tokenizer2Config.cmake.in new file mode 100644 index 00000000..b5c3cd5c --- /dev/null +++ b/cmake/xo_tokenizer2Config.cmake.in @@ -0,0 +1,12 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +# note: changes to find_dependency() calls here +# must coordinate with xo_dependency() calls +# in CMakeLists.txt +# +#find_dependency(xo_flatstring) + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 00000000..e761ade5 --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(tokenrepl) diff --git a/example/tokenrepl/CMakeLists.txt b/example/tokenrepl/CMakeLists.txt new file mode 100644 index 00000000..e7a8c8f3 --- /dev/null +++ b/example/tokenrepl/CMakeLists.txt @@ -0,0 +1,15 @@ +# xo-tokenizer2/example/tokenrepl/CMakeLists.txt + +set(SELF_EXE xo_tokenizer2_repl) +set(SELF_SRCS tokenrepl.cpp) + +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_dependency(${SELF_EXE} xo_tokenizer2) + xo_external_target_dependency(${SELF_EXE} replxx replxx::replxx) + + find_package(Threads REQUIRED) # replxx needs this + target_link_libraries(${SELF_EXE} PUBLIC Threads::Threads) +endif() + +# end CMakeLists.txt diff --git a/example/tokenrepl/tokenrepl.cpp b/example/tokenrepl/tokenrepl.cpp new file mode 100644 index 00000000..f97b9cd0 --- /dev/null +++ b/example/tokenrepl/tokenrepl.cpp @@ -0,0 +1,128 @@ +/** @file tokenrepl.cpp **/ + +#include +#include +#include +#include +#include +#include +#include +#include // for isatty + +// presumeably replxx assumes input is a tty +// +bool replxx_getline(bool interactive, + std::size_t parser_stack_size, + replxx::Replxx & rx, + std::string& input) +{ + using namespace std; + + char const * prompt = ""; + + if (interactive) { + if (parser_stack_size <= 1) + prompt = "> "; + else + prompt = ". "; + } + + const char * input_cstr = rx.input(prompt); + + bool retval = (input_cstr != nullptr); + + if (retval) { + //cerr << "got reval->true" << endl; + + input = input_cstr; + + } else { + //cerr << "got retval->false" << endl; + } + + rx.history_add(input); + + // we want tokenizer to see newline, it's syntax + input.push_back('\n'); + + return retval; +} + +#ifdef OBSOLETE +bool repl_getline(bool interactive, + std::istream & in, + std::ostream & out, + std::string & input) +{ + if (interactive) { + out << "> "; + std::flush(out); + } + + return static_cast(std::getline(in, input)); +} +#endif + +int +main() { + using xo::scm::Tokenizer; + using xo::scm::span; + using xo::scm::operator<<; + using replxx::Replxx; + + using namespace std; + + using span_type = span; + + xo::log_config::min_log_level = xo::log_level::severe; + + bool interactive = isatty(STDIN_FILENO); + + Replxx rx; + rx.set_max_history_size(1000); + rx.history_load("repl_history.txt"); + + Tokenizer tkz(xo::log_config::min_log_level <= xo::log_level::info); + + string input_str; + + size_t line_no = 1; + + constexpr std::size_t c_maxlines = 25; + + while ( + //repl_getline(interactive, cin, cout, input_str) // once upon a time + replxx_getline(interactive, 0 /*parser_stack_size*/, rx, input_str)) + { + span_type input = span_type::from_string(input_str); + + //cout << "input: " << input << endl; + + // reminder: input may contain multiple tokens + while (!input.empty()) { + auto [tk, consumed, error] = tkz.scan(input, false /*!eof*/); + + if (tk.is_valid()) { + cout << tk << endl; + } else if (error.is_error()) { + cout << "tokenizer error: " << endl; + error.report(cout); + + break; + } + + input = input.after_prefix(consumed); + } + + /* here: input.empty() or error encountered */ + + ++line_no; + + if (line_no > c_maxlines) { + cout << "always exit after " << c_maxlines << " lines of input" << endl; + break; + } + } +} + +/** end tokenrepl.cpp */ diff --git a/include/xo/tokenizer2/.gitkeep b/include/xo/tokenizer2/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/include/xo/tokenizer2/TkInputState.hpp b/include/xo/tokenizer2/TkInputState.hpp new file mode 100644 index 00000000..531585a1 --- /dev/null +++ b/include/xo/tokenizer2/TkInputState.hpp @@ -0,0 +1,230 @@ +/* @file TkInputState.hpp + * + * author: Roland Conybeare, Jun 2025 + */ + +#pragma once + +#include "span.hpp" + +namespace xo { + namespace scm { + /** enum to report outcome of @ref capture_current_line **/ + enum class input_error { + /** normal return, input line successfully identified and captured **/ + ok = 0, + /** incomplete input; should not have been submitted + * to @ref capture_current_line. + * note: submit last line of input with eof_flag=true + **/ + incomplete, + N + }; + + /** @class input_state + * @brief Track detailed input position for use in error messages + * + * input characters fall into two categories: + * - consumed: memory can be reclaimed/recycled + * - buffered: memory will be retained unaltered until consumed + * + * remarks: + * - always in one of two states: + * - empty + * - contains exactly one line of input + * - also record current input position. + * Use this for example to identify where tokenizer rejected input. + * - .current_pos advances by one token + * + * - buffered characters always form a single contiguous range. + * - input_state does not own any storage; storage is owned elsewhere + * + * @text + * + * <------------------.current_line------------------> + * > <-- .whitespace + * cccccccccccccccccccccccccccccccc__TTTTTTTTxxxxxxxxx + * ^ ^ ^ + * .current_line.lo | .current_line.hi + * .current_pos + * + * <----prev_line----> <----current_line----> + * > <--whitespace + * ppppppppppppppppppp cccccccccccc__TTTTTTTT + * ^ + * + * @endtext + **/ + class TkInputState { + public: + /** @defgroup input-state-type-traits input-state type straits **/ + ///@{ + + using CharT = char; + + /** type representing a contiguous span of tokenizer input characters **/ + using span_type = span; + + ///@} + + public: + /** @defgroup input-state-ctors input_state constructors **/ + ///@{ + + TkInputState() = default; + explicit TkInputState(bool debug_flag) : debug_flag_{debug_flag} {} + /** Create instance with supplied @p current_line, @p current_pos, @p whitespace. + * Introduced for unit tests, not used in tokenizer. + **/ + explicit TkInputState(const span& current_line, + size_t current_pos, + size_t whitespace) : current_line_{current_line}, + current_pos_{current_pos}, + whitespace_{whitespace} {} + + ///@} + + /** @defgroup input-state-static-methods input_state static methods **/ + ///@{ + + /** recognize the newline character '\n' **/ + static bool is_newline(CharT ch); + /** identifies whitespace chars. + * These are chars that do not belong to any token. + * They are not permitted to appear within + * a symbol or string token. + * Appearance of a whitespace char forces completioon of + * preceding token. + **/ + static bool is_whitespace(CharT ch); + + ///@} + + /** @defgroup input-state-access-methods **/ + ///@{ + +#pragma GCC diagnostic push +#ifndef __APPLE__ +#pragma GCC diagnostic ignored "-Wchanges-meaning" +#endif + const span_type & current_line() const { return current_line_; } +#pragma GCC diagnostic pop + size_t tk_start() const { return tk_start_; } + size_t current_pos() const { return current_pos_; } + size_t whitespace() const { return whitespace_; } + bool debug_flag() const { return debug_flag_; } + + ///@} + + /** @defgroup input-state-general-methods **/ + ///@{ + + /** Input state less @p n chars. + * Use to recover input state before a complete but error-triggering token + **/ + TkInputState rewind(std::size_t n) const; + + /** Capture prefix of @p input up to first newline. + * Set read position to start of line. + * + * Alters: + * .current_line + * .current_pos + * + * Return pair comprising error code and input span representing first line + * (including trailing newline) from @p input. + **/ + std::pair capture_current_line(const span_type & input, + bool eof_flag); + + /** atomically return current line while discarding it from input state + * + * Alters + * .current_line + * .current_pos + * .whitespace + **/ + span_type consume_current_line(); + + /** Reset input state for start of next line. + * Expression parser may use this to discard remainder of input line + * after a parsing error. + * + * Alters: + * .current_line + * .current_pos + * .whitespace + **/ + void discard_current_line(); + + /** Advance input position by @p z + * + * Alters: + * .current_pos + **/ + void advance(size_t z); + + /** Advance .current_pos to pos. + * Require: pos in @ref current_line_ + **/ + void advance_until(const CharT * pos); + + /** Skip prefix of input, starting at current read position, + * comprising only whitespace. + * + * Presume input position is at end of token; + * on return @ref whitespace_ counts number of whitespace characters + * skipped. + * + * Return pointer to first non-whitespace character after @ref current_pos_ + * or @ref current_line_.hi if reached end of buffered line. + * + * Alters: + * .whitespace + **/ + const CharT * skip_leading_whitespace(); + + ///@} + + private: + /** @defgroup input-state-instance-vars input_state instance variables **/ + ///@{ + + /** remember current input line. Used only to report errors **/ + span current_line_ = span(); + /** start of last token within @ref current_line_ **/ + size_t tk_start_ = 0; + /** input position within @ref current_line_ **/ + size_t current_pos_ = 0; + /** number of whitespace chars since end of preceding token, + * or last newline, whichever is less + **/ + size_t whitespace_ = 0; + + /** true to log input activity */ + bool debug_flag_ = false; + + ///@} + }; /*TkInputState*/ + + inline std::ostream & + operator<<(std::ostream & os, + const TkInputState & x) + { + using xo::print::unq; + + os << ""; + + return os; + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end TkInputState.hpp */ diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp new file mode 100644 index 00000000..0994e3b8 --- /dev/null +++ b/include/xo/tokenizer2/Token.hpp @@ -0,0 +1,226 @@ +/* file Token.hpp + * + * author: Roland Conybeare, Jul 2024 + */ + +#pragma once + +#include "tokentype.hpp" +#include "xo/indentlog/print/tag.hpp" +#include +#include +#include +#include + +namespace xo { + namespace scm { + namespace detail { + /* compute a * b^p, p >= 0 */ + constexpr double + pow_aux(double a, double b, int p) { + while (p > 0) { + if (p % 2 == 1) { + /* a * b^p = a * b^(2q + 1) = a.b * 10^(2q) */ + a *= b; + p -= 1; + } else { + /* a * b^p = a * b^(2q) = a * (b^2)^q */ + b = b * b; + p /= 2; + } + } + + /* a * b^0 = a */ + return a; + } + + constexpr double + pow10(int p) { + if (p >= 0) + return pow_aux(1.0, 10.0, p); + else + return 1.0 / pow_aux(1.0, 10.0, -p); + } + } + + /** @class token + * @brief Represent a Schematika lexical token + **/ + class Token { + public: + /** @defgroup token-ctors token constructors **/ + ///@{ + + /** default ctor creates token with type @c tk_invalid **/ + Token() = default; + /** create token with type @c tk_type and input text @c text **/ + Token(tokentype tk_type, const std::string & text = "") + : tk_type_{tk_type}, text_{text} {} + + /** create invalid token (same as null ctor, but explicit) **/ + static Token invalid() { return Token(); } + /** Create token representing a boolean literal from text @p txt + * @p txt must be @c true or @c false + **/ + static Token bool_token(const std::string & txt) { + return Token(tokentype::tk_bool, txt); + } + /** Create token representing 64-bit signed integer literal parsed from decimal @p txt. + * The string @p txt must be a decimal integer literal, since @ref i64_value re-parses @p txt. + **/ + static Token i64_token(const std::string & txt) { + return Token(tokentype::tk_i64, txt); + } + /** create token representing 64-bit floating-point literal parsed from decimal @p txt + * The string @p txt must be a decimal floating-point literal, since @ref f64_value re-parses @p txt. + **/ + static Token f64_token(const std::string & txt) { + return Token(tokentype::tk_f64, txt); + } + /** create token representing literal string parsed from @p txt **/ + static Token string_token(const std::string & txt) { + return Token(tokentype::tk_string, txt); + } + /** create token representing a symbol parsed from @p txt. + * Note that not all strings are valid symbol names. + **/ + static Token symbol_token(const std::string & txt) { + return Token(tokentype::tk_symbol, txt); + } + /** token representing left angle bracket @c "<" **/ + static Token leftangle() { return Token(tokentype::tk_leftangle); } + /** token representing right angle bracket @c ">" **/ + static Token rightangle() { return Token(tokentype::tk_rightangle); } + /** token representing left parenthesis @c "(" **/ + static Token leftparen() { return Token(tokentype::tk_leftparen); } + /** Token representing right parenthesis @c ")" **/ + static Token rightparen() { return Token(tokentype::tk_rightparen); } + /** token representing left bracket @c "[" **/ + static Token leftbracket() { return Token(tokentype::tk_leftbracket); } + /** token representing right bracket @c "]" **/ + static Token rightbracket() { return Token(tokentype::tk_rightbracket); } + /** token representing left brace @c "{" **/ + static Token leftbrace() { return Token(tokentype::tk_leftbrace); } + /** token representing right brace @c "}' **/ + static Token rightbrace() { return Token(tokentype::tk_rightbrace); } + /** token representing period @c "." **/ + static Token dot() { return Token(tokentype::tk_dot); } + /** token representing comma @c "," **/ + static Token comma() { return Token(tokentype::tk_comma); } + /** token representing colon @c ":" **/ + static Token colon() { return Token(tokentype::tk_colon); } + /** token representing double-colo @c "::" **/ + static Token doublecolon() { return Token(tokentype::tk_doublecolon); } + /** token representing semicolon @c ";" **/ + static Token semicolon() { return Token(tokentype::tk_semicolon); } + /** token representing single-assignment @c "=" **/ + static Token singleassign() { return Token(tokentype::tk_singleassign); } + /** token representing unrestricted assignment @c ":=" **/ + static Token assign_token() { return Token(tokentype::tk_assign); } + /** token representing indirection @c "->" **/ + static Token yields() { return Token(tokentype::tk_yields); } + + /** token for @c "+" **/ + static Token plus_token() { return Token(tokentype::tk_plus); } + /** token for @c "-" **/ + static Token minus_token() { return Token(tokentype::tk_minus); } + /** token for @c "*" **/ + static Token star_token() { return Token(tokentype::tk_star); } + /** token for @c "/" **/ + static Token slash_token() { return Token(tokentype::tk_slash); } + + /** token representing keyword @c type **/ + static Token type() { return Token(tokentype::tk_type); } + /** token representing keyword @c def **/ + static Token def() { return Token(tokentype::tk_def); } + /** token representing keyword @c lambda **/ + static Token lambda() { return Token(tokentype::tk_lambda); } + /** token representing keyword @c if **/ + static Token if_token() { return Token(tokentype::tk_if); } + /** token representing keyword @c else **/ + static Token else_token() { return Token(tokentype::tk_else); } + /** token representing keyword @c let **/ + static Token let() { return Token(tokentype::tk_let); } + /** token representing keyword @c in **/ + static Token in() { return Token(tokentype::tk_in); } + /** token representing keyword @c end **/ + static Token end() { return Token(tokentype::tk_end); } + + ///@} + + /** @defgroup token-access-methods **/ + ///@{ + + tokentype tk_type() const { return tk_type_; } + const std::string & text() const { return text_; } + + ///@} + + /** @defgroup token-general-methods **/ + ///@{ + + /** true if token understood to represent valid input + * i.e. any token type except @c tk_invalid + **/ + bool is_valid() const { return tk_type_ != tokentype::tk_invalid; } + /** true for sentinel token with type tk_invalid **/ + bool is_invalid() const { return tk_type_ == tokentype::tk_invalid; } + + /** true for tokens with variable text. false for those with fixed textual representation **/ + bool has_variable_text() const { return (tk_type_ == tokentype::tk_i64 + || tk_type_ == tokentype::tk_f64 + || tk_type_ == tokentype::tk_string + || tk_type_ == tokentype::tk_symbol); } + + /** expect input matching @c true or @c false **/ + bool bool_value() const; + + /** expect input matching @c [+|-][0-9][0-9]* **/ + std::int64_t i64_value() const; + + /** expect input matching @c [+|-][0-9]*[.][0-9]*[e|E][+|-][0-9]* **/ + double f64_value() const; + + /** print human-readable token representation on stream @p os **/ + void print(std::ostream & os) const; + + ///@} + + private: + /** @defgroup token-instance-vars **/ + ///@{ + + /** category for this token **/ + tokentype tk_type_ = tokentype::tk_invalid; + + /** characters comprising this token. + * only provided for certain token types: + * + * tk_i64 + * tk_f64 + * tk_string + * tk_symbol + **/ + std::string text_; + + ///@} + }; + + inline std::ostream & + operator<< (std::ostream & os, + const Token & tk) + { + tk.print(os); + return os; + } + } /*namespace scm*/ + +#ifndef ppdetail_atomic + namespace print { + PPDETAIL_ATOMIC(xo::scm::token); + } +#endif + +} /*namespace xo*/ + +/* end Token.hpp */ diff --git a/include/xo/tokenizer2/Tokenizer.hpp b/include/xo/tokenizer2/Tokenizer.hpp new file mode 100644 index 00000000..99005fee --- /dev/null +++ b/include/xo/tokenizer2/Tokenizer.hpp @@ -0,0 +1,167 @@ +/* file Tokenizer.hpp + * + * author: Roland Conybeare, Jul 2024 + */ + +#pragma once + +#include "Token.hpp" +#include "TkInputState.hpp" +#include "span.hpp" +#include "scan_result.hpp" +#include "xo/indentlog/scope.hpp" +#include "xo/indentlog/print/ppdetail_atomic.hpp" +#include + +namespace xo { + namespace scm { + /** @class Tokenizer + * @brief Parse a Schematika character stream into lexical tokens + * + * Use: + * + * @code + * // see xo-tokenizer2/example/tokenrepl/tokenrepl.cpp + * // for exact working code + * + * using tokenizer_type = tokenizer; + * using span_type = tokenizer_type::span_type; + * + * tokenizer_type tkz; + * span_type input = ...; + * + * while (!input.empty()) { + * auto [tk, consumed, error] = tkz.scan(input); + * + * if (tk.is_valid()) { + * // do something with tk + * } else if (error.is_error()) { + * error.report(cout); + * break; + * } + * + * input = input.after_prefix(consumed); + * } + * + * if endofinput { + * auto [tk, consumed, error] = tzk.notify_eof() + * + * // do something with (final) tk if tk.is_valid() + * } + * + * @endcode + * + * See tokentype.hpp for token types + **/ + class Tokenizer { + public: + using CharT = char; + using token_type = Token; + using error_type = TokenizerError; + using span_type = span; + using input_state_type = TkInputState; + using result_type = scan_result; + + public: + /** @defgroup tokenizer-ctors tokenizer constructors **/ + ///@{ + + Tokenizer(bool debug_flag = false); + + ///@} + + /** @defgroup tokenizer-access-methods tokenizer access methods **/ + ///@{ + +#pragma GCC diagnostic push +#ifndef __APPLE__ +#pragma GCC diagnostic ignored "-Wchanges-meaning" +#endif + const TkInputState & input_state() const { return input_state_; } +#pragma GCC diagnostic pop + + ///@} + + /** @defgroup tokenizer-general-methods tokenizer methods **/ + ///@{ + + /** identifies punctuation chars. + * These are chars that are not permitted to appear within + * a symbol token. Instead they force completion of + * a preceding token, and start a new token with themselves + **/ + static bool is_1char_punctuation(CharT ch); + + /** more-relaxed version of is_1char_punctuation. + * Chars that are not permitted to appear within a symbol token, + * but may form token combined with next character + **/ + static bool is_2char_punctuation(CharT ch); + + /** assemble token from text @p token_text. + * @p initial_whitespace Amount of whitespace input being consumed from input. + * @p token_text subset of input_line representing a single token. + * @p p_input_state input state containing input_line. On exit current line cleared + * if error + * + * retval.consumed will represent some possibly-empty prefix of @p input + **/ + static scan_result assemble_token(std::size_t initial_whitespace, + const span_type & token_text, + TkInputState * p_input_state); + + /** degenerate version of assemble_token() on reaching end-of-file **/ + static scan_result assemble_final_token(const span_type & token_text, + TkInputState * p_input_state); + + /** true if tokenizer contains stored prefix of + * possibly-incomplete token + **/ + bool has_prefix() const { return !prefix_.empty(); } + + /** scan for next input token, given @p input. + * Note: + * - tokenizer can consume input (e.g. whitespace) + * without completing a token + * - input will remember the extent of the last line of input + * for which parsing has begun, but not completed. + * It's required that at least that portion of the input span + * remain valid across scan(), scan2() calls + * + * @return {parsed token, consumed span} + **/ + scan_result scan(const span_type & input, + bool eof_flag); + + /** discard current line after error. Just cleans up error-reporting state **/ + void discard_current_line(); + + ///@} + + private: + /** @defgroup tokenizer-instance-vars tokenizer instance variables **/ + ///@{ + + /** track input state (line#,pos,..) for error messages. + * There's an ordering problem here: + * 1. input_state_.skip_leading_whitespace() advances + * current line automagically when it sees \n + * 2. need to capture value of @ref input_state_ _before_ newline + * 3. but neeed newline to end token + * Also recall input_state_type needed for reporting errors. + **/ + input_state_type input_state_; + /** Accumulate partial token here. + * This will happen if input sent to @ref tokenizer::scan + * ends without whitespace such that last available token's + * extent is not determined + **/ + std::string prefix_; + + ///@} + }; /*tokenizer*/ + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end Tokenizer.hpp */ diff --git a/include/xo/tokenizer2/TokenizerError.hpp b/include/xo/tokenizer2/TokenizerError.hpp new file mode 100644 index 00000000..a7fab3c2 --- /dev/null +++ b/include/xo/tokenizer2/TokenizerError.hpp @@ -0,0 +1,114 @@ +/* file TokenizerError.hpp + * + * author: Roland Conybeare, Jun 2025 + */ + +#pragma once + +#include "TkInputState.hpp" +#include "tokentype.hpp" +#include "span.hpp" +#include + +namespace xo { + namespace scm { + /** @class tokenizer_error + * @brief represent a lexing error, with context + * + * @tparam CharT representation for single characters + **/ + class TokenizerError { + public: + using CharT = char; + using span_type = span; + + public: + /** @defgroup tokenizer-error-ctors **/ + ///@{ + + /** Default ctor represents a not-an-error sentinel object **/ + TokenizerError() = default; + /** Constructor to capture parsing error context + * @p tk_start current position on entry to scanner + * @p error_pos error location relative to token start + **/ + TokenizerError(const char * src_function, + std::string error_description, + const TkInputState & input_state, + size_t error_pos) + : src_function_{src_function}, + error_description_{std::move(error_description)}, + input_state_{input_state}, + error_pos_{error_pos} + { + scope log(XO_DEBUG(input_state.debug_flag())); + + log && log(xtag("input_state.current_pos", input_state.current_pos()), + xtag("error_pos", error_pos)); + } + ///@} + + /** @defgroup tokenizer-error-access-methods **/ + ///@{ + + const char * src_function() const { return src_function_; } + const std::string & error_description() const { return error_description_; } +#pragma GCC diagnostic push +#ifndef __APPLE__ +#pragma GCC diagnostic ignored "-Wchanges-meaning" +#endif + const TkInputState & input_state() const { return input_state_; } +#pragma GCC diagnostic pop + size_t tk_start() const { return input_state_.current_pos(); } + size_t whitespace() const { return input_state_.whitespace(); } + size_t error_pos() const { return error_pos_; } + + ///@} + + /** @defgroup tokenizer-error-general-methods **/ + ///@{ + + /** true, except for a sentinel error object **/ + bool is_error() const { return !error_description_.empty(); } + /** false except for object in sentinel state **/ + bool is_not_an_error() const { return error_description_.empty(); } + + /** Print representation to stream @p os. Intended for tokenizer diagnostics. + * For Schematika errors prefer @ref report + **/ + void print(std::ostream & os) const; + + /** Print human-oriented error report on @p os. **/ + void report(std::ostream & os) const; + + ///@} + + private: + /** @defgroup tokenizer-error-vars **/ + ///@{ + + /** source location (in tokenizer) at which error identified **/ + char const * src_function_ = nullptr; + /** static error description **/ + std::string error_description_; + /** input state associated with this error. + * Sufficient to precisely locate it with context. + **/ + TkInputState input_state_; + /** position (relative to @ref tk_entry_) of error **/ + size_t error_pos_ = 0; + + ///@} + }; /*error_token*/ + + inline std::ostream & + operator<< (std::ostream & os, + const TokenizerError & tkerr) + { + tkerr.print(os); + return os; + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end tokenizer_error.hpp */ diff --git a/include/xo/tokenizer2/buffer.hpp b/include/xo/tokenizer2/buffer.hpp new file mode 100644 index 00000000..7b19316b --- /dev/null +++ b/include/xo/tokenizer2/buffer.hpp @@ -0,0 +1,328 @@ +/** @file buffer.hpp **/ + +#pragma once + +#include "span.hpp" +#include +#include +#include +#include + +namespace xo { + namespace scm { + /** + * @class buffer buffer.hpp + * + * @brief Container for a (possibly owned) FIFO queue of chars + * + * @tparam CharT. buffer element type. + * + * @code + * .buf + * + * +------------------------------------------+ + * | | ... | | X| ... | X| | ... | | + * +------------------------------------------+ + * ^ ^ ^ ^ + * 0 .lo .hi .buf_z + * + * <-contents-><----avail-----> + * @endcode + * + * Buffer does not support wrapped content: + * content that has not been consumed always occupies contiguous memory. + * + * Example: + * @code + * // 1. + * buffer buf(64*1024); + * buf.empty() -> true + * buf.buf_z() -> 65536 + * buf.lo_pos() -> 0 + * buf.hi_pos() -> 65536 + * buf.contents() -> empty span + * buf.avail() -> span entire buffer memory + * + * // write to (a prefix of) buf.avail() + * ::strncpy(buf.buf(), "hello, world\n", 13); + * buf.produce(span_type(buf.buf(), buf.buf() + 13)); + * + * buf.lo_pos() -> 0 + * buf.hi_pos() -> 13 + * buf.contents() -> "hello, world\n"; + * + * + * // examine stored content (does not change buffer state) + * auto span = buf.contents(); + * cerr << string_view(span.lo(), span.hi()); // "hello, world\n" + * + * // consume (a prefix of) stored content + * buf.consume(span.prefix(7); + * + * buf.lo_pos() -> 7 + * buf.hi_pos() -> 13 + * buf.contents() -> "world\n" + * + * // consuming all remain content resets to original state + * buf.consume(buf.contents()); + * + * buf.empty() -> true + * buf.hi_pos() -> 0 // not 13! + * + * // 2. + * buffer buf; + * buf.empty() -> true + * buf.buf_z() -> 0 + * buf.lo_pos() -> 0 + * buf.hi_pos() -> 0 + * buf.contents() -> empty span + * buf.avail() -> empty span + * + * // allocate memory separately from ctor + * buf.alloc(64*1024); + * @endcode + **/ + template + class buffer { + public: + /** @brief typealias for span of CharT **/ + using span_type = span; + /** @brief typealias for buffer size (counts CharT's, not bytes) **/ + using size_type = std::uint64_t; + + public: + /** @brief create empty buffer. + + Does not allocate any storage; @see alloc + **/ + buffer() = default; + /** @brief create empty buffer, and possibly allocate storage. + + @param buf_z Buffer size. allocate storage (owned by this buffer) if >0. + @param align_z Align to this value, e.g. 8 to align storage on an 8-byte boundary + **/ + buffer(size_type buf_z, + size_type align_z = sizeof(char)) + : is_owner_{true}, + buf_{buf_z ? (new (std::align_val_t(align_z)) CharT [buf_z]) : nullptr}, + buf_z_{buf_z}, + lo_pos_{0}, + hi_pos_{0} + {} + /** @brief buffer is not copyable **/ + buffer(buffer const & x) = delete; + /** @brief destructor. Release storage if owned **/ + ~buffer() { this->reset(); } + + /** @name Access methods **/ + ///@{ + + /** @brief start of buffer memory **/ + CharT * buf() const { return buf_; } + /** @brief buffer size (number of characters) **/ + size_type buf_z() const { return buf_z_; } + /** @brief current start position within buffer **/ + size_type lo_pos() const { return lo_pos_; } + /** @brief current end position within buffer **/ + size_type hi_pos() const { return hi_pos_; } + + ///@} + + /** @brief readonly access to a single buffer element. + + Relative to start of buffer (ignores current consume position) + **/ + CharT const & operator[](size_type i) const { return buf_[i]; } + + /** @brief return span for current buffer contents **/ + span_type contents() const { return span_type(buf_ + lo_pos_, + buf_ + hi_pos_); } + /** @brief returns span for writable buffer contents (unused prefix following produce position **/ + span_type avail() const { return span_type(buf_ + hi_pos_, + buf_ + buf_z_); } + + /** @brief @c true iff buffer is empty **/ + bool empty() const { return lo_pos_ == hi_pos_; } + + + /** + @brief update buffer produce position, after (independently) writing contents of span to it + + @pre left endpoint of @p span equals buffer produce position (@c .hi_pos) + @pre right endpoint of @p span within bounds of buffer memory range + @post right endpoint of @p span equals buffer produce position. + **/ + void produce(span_type const & span) { + assert(span.lo() == buf_ + hi_pos_); + + hi_pos_ += span.size(); + } + + /** + @brief update buffer consume position, when done with contents of span + + @pre left endpoint of @p span equals buffer consume position (@c .lo_pos) + @pre right endpoint of @p span within bounds of buffer memory range + @post Either + buffer is empty, with @c .lo_pos = @c .hi_pos = @c 0. + buffer is non-empty, right endpoint of @p span equals new buffer consume position. + **/ + void consume(span_type const & span) { + if (span.size()) { + assert(span.lo() == buf_ + lo_pos_); + + lo_pos_ += span.size(); + } else { + /* since .consume() that arrives at empty contents also resets .lo_pos .hi_pos, + * we don't want to blow up when called with an empty span -- argument + * may represent some pre-reset location in buffer + */ + } + + if (lo_pos_ == hi_pos_) { + lo_pos_ = 0; + hi_pos_ = 0; + } + } + + /** + @brief allocate buffer with desired amount of memory + + @param buf_z desired buffer size + @param align_z alignment; buffer memory will be aligned on this byte-boundary. + **/ + void alloc(size_type buf_z, size_type align_z = sizeof(char)) { + /* properly reset (+ discard) any existing state */ + this->reset(); + + is_owner_ = true; + if (buf_z) + buf_ = new (std::align_val_t(align_z)) CharT [buf_z]; + buf_z_ = buf_z; + lo_pos_ = 0; + hi_pos_ = 0; + } + + /** + @brief attach buffer to (unowned) range of @p buf_z bytes starting at @p buf[0] + + Buffer is not responsible for managing storage. + + @post + 1. buffer is empty + @post + 2. buffer read position = buffer write position = 0 + **/ + void setbuf(CharT * buf, size_type buf_z) { + /* properly reset (+ discard) any existing state */ + this->reset(); + + is_owner_ = false; + lo_pos_ = 0; + hi_pos_ = 0; + buf_ = buf; + buf_z_ = buf_z; + } + + /** + @brief revert buffer to empty state and possibly zero it + + @param zero_buffer_flag Zero buffer contents iff this is true + + @post + 1. buffer is empty + @post + 2. buffer read position = buffer write position = 0 + **/ + void clear2empty(bool zero_buffer_flag) { + if (buf_ && zero_buffer_flag) + explicit_bzero(buf_, buf_z_ * sizeof(CharT)); + + lo_pos_ = 0; + hi_pos_ = 0; + } + + /** + @brief swap representation with another buffer instance. + **/ + void swap (buffer & x) { + std::swap(is_owner_, x.is_owner_); + std::swap(buf_, x.buf_); + std::swap(buf_z_, x.buf_z_); + std::swap(lo_pos_, x.lo_pos_); + std::swap(hi_pos_, x.hi_pos_); + } + + /** + @brief reset buffer to an empty state and recover owned storage + **/ + void reset() { + if (is_owner_ && buf_) + delete [] buf_; + + is_owner_ = false; + buf_ = nullptr; + buf_z_ = 0; + lo_pos_ = 0; + hi_pos_ = 0; + } + + /** + @brief move-assignment operator. + @param x right-hand-side to move from. + + @post + @p x is in a valid, empty, + **/ + buffer & operator= (buffer && x) { + is_owner_ = x.is_owner_; + buf_ = x.buf_; + buf_z_ = x.buf_z_; + lo_pos_ = x.lo_pos_; + hi_pos_ = x.hi_pos_; + + x.is_owner_ = false; + x.lo_pos_ = 0; + x.hi_pos_ = 0; + x.buf_ = nullptr; + x.buf_z_ = 0; + + return *this; + } + + /** @brief buffer is not assignable */ + buffer & operator= (buffer & x) = delete; + + private: + /** @brief true iff buffer is responsible for freeing storage at @c buf_ **/ + bool is_owner_ = false; + /** @brief buffer contents. buffer memory comprises @c buf_[0] to @c buf_[buf_z_] **/ + CharT * buf_ = nullptr; + /** @brief buffer size (in units of CharT) **/ + size_type buf_z_ = 0; + + /** @brief buffer read (consume) position + + @invariant + 0 <= lo_pos_ <= hi_pos_ < buf_z_ + **/ + size_type lo_pos_ = 0; + /** @brief buffer write (produce) position + + @invariant + 0 <= hi_pos_ < hi_pos_ < buf_z_ + **/ + size_type hi_pos_ = 0; + }; + + /** @brief Overload for @c swap, so that @c buffer swappable **/ + template + inline void + swap(buffer & lhs, + buffer & rhs) { + lhs.swap(rhs); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end buffer.hpp */ diff --git a/include/xo/tokenizer2/scan_result.hpp b/include/xo/tokenizer2/scan_result.hpp new file mode 100644 index 00000000..971e4b93 --- /dev/null +++ b/include/xo/tokenizer2/scan_result.hpp @@ -0,0 +1,81 @@ +/* file scan_result.hpp + * + * author: Roland Conybeare, Jun 2025 + */ + +#pragma once + +#include "Token.hpp" +#include "TokenizerError.hpp" +#include "TkInputState.hpp" + +namespace xo { + namespace scm { + /** @class scan_result + * @brief Represent result of parsing one input token. + * + * @code + * Possible outcomes fall into several categories + * (with T: @c token_.is_valid(), E: @cerror_.is_error()) + * + * | T | E | description | + * |-------+-------+-------------------------------------| + * | false | false | end of input, including end of line | + * | true | false | parsed token in T | + * | false | true | parse error in E | + * + * @endcode + **/ + class scan_result { + public: + using CharT = char; + using token_type = Token; + using span_type = span; + using error_type = TokenizerError; + using input_state_type = TkInputState; + + public: + scan_result(const Token & token, + const span_type & consumed, + const TokenizerError & error = TokenizerError()) + : token_{token}, consumed_{consumed}, error_{error} {} + + static scan_result make_whitespace(const span_type & prefix_input); + static scan_result make_partial(const span_type & prefix_input); + /** + * @p error_src can be __FUNCTION__ from site where error generated. + * @p error_msg error message + * @p error_pos error position, relative to start of token + * @p input_state_ref input state object; + * copied into scan_result, and leaving input_state_ref.current_line cleared + **/ + static scan_result make_error_consume_current_line(const char * error_src, + std::string error_msg, + size_t error_pos, + input_state_type & input_state_ref); + + bool is_eof_or_ambiguous() const { return token_.is_invalid() && error_.is_not_an_error(); } + bool is_token() const { return token_.is_valid(); } + bool is_error() const { return error_.is_error(); } + + const Token & get_token() const { return token_; } + const span_type & consumed() const { return consumed_; } + const TokenizerError & error() const { return error_; } + + public: + /** Successfully parsed token, whenever tk_type != tokentype::tk_invalid. + * Will be tokentype::tk_invalid in normal cause of events for valid input, + * when consuming whitespace + **/ + token_type token_; + /** input span represented by .token, on success. Otherwise not defined **/ + span_type consumed_; + /** error description, whenever .error_.is_error() is true **/ + TokenizerError error_; + }; + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end scan_result.hpp */ diff --git a/include/xo/tokenizer2/span.hpp b/include/xo/tokenizer2/span.hpp new file mode 100644 index 00000000..8cf7a4a7 --- /dev/null +++ b/include/xo/tokenizer2/span.hpp @@ -0,0 +1,291 @@ +/** @file span.hpp **/ + +#pragma once + +#include "xo/indentlog/scope.hpp" +#include "xo/indentlog/print/ppdetail_atomic.hpp" +#include +#include +#include + +namespace xo { + namespace scm { + /** @class span compression/span.hpp + * + * @brief A contiguous range of characters, without ownership. + * + * @tparam CharT type for elements referred to by this span. + **/ + template + class span { + public: + /** @defgroup span-type-traits span type traits **/ + ///@{ + + /** typealias for span size (in units of CharT) **/ + using size_type = std::uint64_t; + + ///@} + + public: + /** @defgroup span-ctors span constructors **/ + ///@{ + + /** null span **/ + span() : lo_{nullptr}, hi_{nullptr} {} + + /** Create span for the contiguous memory range [@p lo, @p hi) **/ + span(CharT * lo, CharT * hi) : lo_{lo}, hi_{hi} {} + + /** explicit conversion from span **/ + template + span(const span & other, + std::enable_if_t + && !std::is_same_v> * = nullptr) + : lo_{other.lo()}, hi_{other.hi()} {} + + /** copy ctor (explicit to avoid ambiguity with template ctor) **/ + span(const span & other) = default; + span & operator=(const span & other) = default; + + /** Create a null span (i.e. with null @p lo, @p hi pointers) + * A null span can be concatenated with any other span + * without triggering matching-endpoint asserts. + **/ + static span make_null() { return span(static_cast(nullptr), static_cast(nullptr)); } + + /** @brief create span for C-style string @p cstr **/ + static span from_cstr(const CharT * cstr) { + CharT * lo = cstr; + CharT * hi = cstr ? cstr + strlen(cstr) : nullptr; + + return span(lo, hi); + } + + /** @brief create span from std::string @p str **/ + static span from_string(const std::string& str) { + CharT * lo = &(*str.begin()); + CharT * hi = &(*str.end()); + + return span(lo, hi); + } + + /** @brief concatenate two contiguous spans */ + static span concat(const span & span1, const span & span2) { + if (span1.is_null()) + return span2; + if (span2.is_null()) + return span1; + + if (span1.hi() != span2.lo()) { + scope log(XO_DEBUG(true)); + + log && log(xtag("span1.hi", (void*)span1.hi()), xtag("span2.lo", (void*)span2.lo())); + } + + assert(span1.hi() == span2.lo()); + + CharT * lo = span1.lo(); + CharT * hi = span2.hi(); + + return span(lo, hi); + } + + ///@} + + /** @defgroup span-access-methods **/ + ///@{ + + CharT * lo() const { return lo_; } /* get member span::lo_ */ + CharT * hi() const { return hi_; } /* get member span::hi_ */ + + ///@} + + /** @defgroup span-general-methods **/ + ///@{ + + /** @brief strip prefix until first occurence of '\n', including the newline **/ + void discard_until_newline() { + for (const CharT * p = lo_; p < hi_; ++p) { + if (*p == '\n') { + lo_ = p + 1; + return; + } + } + + lo_ = hi_; + } + + /** Create new span over supplied type, + * with identical (possibly misaligned) endpoints. + * + * @warning + * 1. New span uses exactly the same memory addresses. + * Endpoint pointers may not be aligned. + * 2. Implementation assumes code compiled with + * @code -fno-strict-aliasing @endcode enabled. + * + * @tparam OtherT element type for new span + **/ + template + span + cast() const { return span(reinterpret_cast(lo_), + reinterpret_cast(hi_)); } + + /** @brief create span including the first @p z members of this span. **/ + span prefix(size_type z) const { return span(lo_, lo_ + z); } + + /** @brief create span representing prefix up to (but not including) @p *p + **/ + span prefix_upto(CharT * p) const { + if (p <= hi_) + return span(lo_, p); + else + return span(lo_, hi_); + } + + /** @brief create span with first @p z members of this span removed **/ + span after_prefix(size_type z) const { + if (lo_ + z > hi_) + z = hi_ - lo_; + + return span(lo_ + z, hi_); + } + + /** @brief create span with @p prefix of this span removed **/ + span after_prefix(const span & prefix) const { + if (!prefix.is_null() && (prefix.lo() != lo_)) { + throw std::runtime_error + ("after_prefix: expected prefix of this span"); + } + + return after_prefix(prefix.size()); + } + + /** Create span starting with position @p p. + * Does boundary checking; will return empty span if @p p is outside @c [lo_,hi) + **/ + span suffix_from(CharT * p) const { + if ((lo_ <= p) && (p <= hi_)) + return span(p, hi_); + else + return span(hi_, hi_); + } + + /** true iff this span is null. distinct from empty. **/ + bool is_null() const { return lo_ == nullptr && hi_ == nullptr; } + /** true iff this span is empty (comprises 0 elements). **/ + bool empty() const { return lo_ == hi_; } + /** report the number of elements (of type CharT) in this span. **/ + size_type size() const { return hi_ - lo_; } + + /** increase extent of this spans to include @p x. + * Requires @c hi() == @c x.lo() + **/ + span & operator+=(const span & x) { + if (hi_ == x.lo_) { + hi_ = x.hi_; + } else if (!x.is_null()) { + assert(false); + } + + return *this; + } + + /** print representation for this span on stream @p os **/ + void print(std::ostream & os) const { + os << ""; + } + ///@} + + private: + /** @defgroup span-instance-vars **/ + ///@{ + + /** start of span. + Span comprises memory address between @p lo (inclusive) and @p hi (exclusive) + **/ + CharT * lo_ = nullptr; + + /** @brief end of span. + Span comprises memory address between @p lo (inclusive) and @p hi (exclusive) + **/ + CharT * hi_ = nullptr; + + ///@} + }; /*span*/ + + /** @defgroup span-operators **/ + ///@{ + + /** compare spans for equality. + * Two spans are equal iff both endpoints match exactly. + **/ + template + inline bool + operator==(const span & lhs, const span & rhs) { + return ((lhs.lo() == rhs.lo()) + && (lhs.hi() == rhs.hi())); + } + + /** compare spans for inequality. + * Two spans are unequal if either paired endpoint differs. + **/ + template + inline bool + operator!=(const span & lhs, const span & rhs) { + return ((lhs.lo() != rhs.lo()) + || (lhs.hi() != rhs.hi())); + } + + /** print a summary of @p x on stream @p os. Intended for diagnostics **/ + template + inline std::ostream & + operator<<(std::ostream & os, + const span & x) { + x.print(os); + return os; + } + + ///@} + } /*namespace scm*/ + + namespace print { + template + class printspan_impl { + public: + printspan_impl(xo::scm::span x) : span_{x} {} + + xo::scm::span span_; + }; + + template + printspan_impl printspan(const xo::scm::span& span) { + return printspan_impl(span); + } + + template + inline std::ostream & + operator<< (std::ostream & os, + const printspan_impl & x) + { + for (const CharT * p = x.span_.lo(); p < x.span_.hi(); ++p) + os << *p; + + return os; + } + +#ifndef ppdetail_atomic + template \ + PPDETAIL_ATOMIC_BODY(printspan_impl); + + template \ + PPDETAIL_ATOMIC_BODY(xo::scm::span); +#endif + + } +} /*namespace xo*/ diff --git a/include/xo/tokenizer2/tokentype.hpp b/include/xo/tokenizer2/tokentype.hpp new file mode 100644 index 00000000..eeeb7dd0 --- /dev/null +++ b/include/xo/tokenizer2/tokentype.hpp @@ -0,0 +1,192 @@ +/** @file tokentype.hpp + * + * author: Roland Conybeare, Jul 2024 + **/ + +#pragma once + +#include "xo/indentlog/print/tag.hpp" // for STRINGIFY +#include "xo/indentlog/print/ppdetail_atomic.hpp" +#include + +namespace xo { + namespace scm { + /** @enum tokentype + * Enum to identify different schematika input token types + * + * Schematica code examples: + * + * @code + * type point :: { xcoord : f64, ycoord : f64 }; + * type matrix :: array; // 2-d array + * + * decl hypot(x : f64, y : f64) -> f64; + * + * def hypot(x : f64, y : f64) { + * let + * x2 = (x * x); + * y2 = (y * y); + * hypot2 = (x2 + y2); + * in + * sqrt(hypot2); + * }; + * + * def someconst 4; + * + * def foo(v : vec) { + * def (pi : f64) = 3.1415926; + * def (h : (f64,f64) -> f64) = hypot; + * + * h = hypot3; + * }; + * + * def matrixproduct(x : matrix, y : matrix) { + * [i, j : x.row(i) * y.col(j)]; + * }; + * @endcode + **/ + enum class tokentype { + /** sentinel value **/ + tk_invalid = -1, + + /** a boolean constant **/ + tk_bool, + + /** an integer constant (signed 64-bit integer) **/ + tk_i64, + + /** a 64-bit floating-point constant **/ + tk_f64, + + /** a string literal **/ + tk_string, + + /** a symbol **/ + tk_symbol, + + /** left-hand parenthesis @c '(' **/ + tk_leftparen, + + /** right-hand parenthesis @c ')' **/ + tk_rightparen, + + /** left-hand bracket @c '[' **/ + tk_leftbracket, + + /** right-hand bracket @c ']' **/ + tk_rightbracket, + + /** left-hand brace @c '{' **/ + tk_leftbrace, + + /** right-hand brace @c '}' **/ + tk_rightbrace, + + /** left-hand angle bracket @c '<' **/ + tk_leftangle, + + /** right-hand angle bracket @c '>' **/ + tk_rightangle, + + /** less-equal @c '<=' **/ + tk_lessequal, + + /** great-equal @c '>=' **/ + tk_greatequal, + + /** dot @c '.' **/ + tk_dot, + + /** comma @c ',' **/ + tk_comma, + + /** colon @c ':' **/ + tk_colon, + + /** double-colon @c '::' **/ + tk_doublecolon, + + /** semi-colon @c ';' **/ + tk_semicolon, + + /** single equals sign @c '=' **/ + tk_singleassign, + + /** assignment @c ':=' **/ + tk_assign, + + /** indirection @c '->' **/ + tk_yields, + + /** note: operators not treated as punctuation + * 'do-always' is a legal variable name, + * as is 'maybe*2', 'maybe+1', 'path/to/foo' + **/ + + /** operator @c '+' **/ + tk_plus, + /** operator @c '-' **/ + tk_minus, + /** operator @c '*' **/ + tk_star, + /** operator @c '/' **/ + tk_slash, + + /** operator @c '==' **/ + tk_cmpeq, + /** operator @c '!=' **/ + tk_cmpne, + + /** keyword @c 'type' **/ + tk_type, + + /** keyword @c 'def' **/ + tk_def, + + /** keyword @c 'lambda' **/ + tk_lambda, + + /** keyword @c 'if' **/ + tk_if, + + /** keyworkd @c 'then' **/ + tk_then, + + /** keyword @c 'else' **/ + tk_else, + + /** keyword @c 'let' **/ + tk_let, + + /** keyword @c 'in' **/ + tk_in, + + /** keyword @c 'end' **/ + tk_end, + + /** counts number of entries **/ + n_tokentype + }; /*tokentype*/ + + /** String representation for enum value. + * For example @c tokentype_descr(tokentype::tk_if) -> @c "if" + **/ + extern char const * + tokentype_descr(tokentype tk_type); + + /** Print enum value for @p tk_type on stream @p os **/ + inline std::ostream & + operator<< (std::ostream & os, tokentype tk_type) { + os << tokentype_descr(tk_type); + return os; + } + } /*namespace scm*/ + +#ifndef ppdetail_atomic + namespace print { + PPDETAIL_ATOMIC(xo::scm::tokentype); + } /*namespace print*/ +#endif +} /*namespace xo*/ + +/* end tokentype.hpp */ diff --git a/src/tokenizer2/CMakeLists.txt b/src/tokenizer2/CMakeLists.txt new file mode 100644 index 00000000..967535e2 --- /dev/null +++ b/src/tokenizer2/CMakeLists.txt @@ -0,0 +1,15 @@ +# tokenizer2/CMakeLists.txt + +set(SELF_LIB xo_tokenizer2) +set(SELF_SRCS + Tokenizer.cpp + TokenizerError.cpp + TkInputState.cpp + scan_result.cpp + Token.cpp + tokentype.cpp) + +xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) +xo_dependency(${SELF_LIB} indentlog) + +# end CMakeLists.txt diff --git a/src/tokenizer2/TkInputState.cpp b/src/tokenizer2/TkInputState.cpp new file mode 100644 index 00000000..30db1dbb --- /dev/null +++ b/src/tokenizer2/TkInputState.cpp @@ -0,0 +1,151 @@ +/** @file TkInputState.cpp + * + * @author Roland Conybeare, Jun 2025 + **/ + +#include "TkInputState.hpp" + +namespace xo { + namespace scm { + using CharT = char; + + bool + TkInputState::is_newline(CharT ch) { + return (ch == '\n'); + } + + bool + TkInputState::is_whitespace(CharT ch) { + switch(ch) { + case ' ': return true; + case '\t': return true; + case '\n': return true; + case '\r': return true; + } + + return false; + } + + TkInputState + TkInputState::rewind(std::size_t n) const + { + return TkInputState(this->current_line_, + (n <= current_pos_) ? current_pos_ - n : 0, + 0 /*whitespace*/); + } + + void + TkInputState::advance(size_t z) + { + scope log(XO_DEBUG(debug_flag_)); + + this->current_pos_ += z; + + log && log(xtag("z", z), xtag("current_pos", current_pos_)); + } + + void + TkInputState::advance_until(const CharT * pos) + { + scope log(XO_DEBUG(debug_flag_)); + + assert(current_line_.lo() <= pos && pos <= current_line_.hi()); + + this->current_pos_ = pos - current_line_.lo(); + + log && log(xtag("current_pos", current_pos_)); + } + + auto + TkInputState::consume_current_line() -> span_type + { + span_type retval = current_line_; + + this->discard_current_line(); + + return retval; + } + + void + TkInputState::discard_current_line() + { + this->current_line_ = span_type::make_null(); + this->current_pos_ = 0; + this->whitespace_ = 0; + } + + auto + TkInputState::capture_current_line(const span_type & input, + bool eof_flag) + -> std::pair + { + // see also discard_current_line() + // note: must capture entirety of first line, + // for example including leading whitespace. + // See discussion in tokenizer scan() method + + scope log(XO_DEBUG(debug_flag_)); + + /* look ahead to {end of line, end of input}, whichever comes first */ + const CharT * sol = input.lo(); + const CharT * eol = sol; + + if (sol == current_line_.lo()) { + log && log("short-circuit - current line already stashed"); + + /* nothing to do here */ + return std::make_pair(input_error::ok, current_line_); + } + + while ((eol < input.hi()) && (*eol != '\n')) + ++eol; + + if (*eol == '\n') { + /* include \n at end-of-line */ + ++eol; + } else { + if (!eof_flag) { + /* caller expected to provide complete line of input. complain and ignore */ + return std::make_pair(input_error::incomplete, + input.prefix(0ul)); + } + } + + this->current_line_ = span_type(sol, eol); + this->current_pos_ = 0; + this->whitespace_ = 0; + + log && log(xtag("current_line", print::printspan(current_line_)), + xtag("current_pos", current_pos_)); + + return std::make_pair(input_error::ok, + span_type(sol, eol)); + } + + const CharT * + TkInputState::skip_leading_whitespace() + { + scope log(XO_DEBUG(debug_flag_)); + + const CharT * ix = current_line_.lo() + current_pos_; + + this->whitespace_ = 0; + + /* skip whitespace + remember beginning of most recent line */ + while (is_whitespace(*ix) && (ix != current_line_.hi())) { + ++ix; + + ++(this->whitespace_); + } + + this->tk_start_ = ix - current_line_.lo(); + this->current_pos_ = ix - current_line_.lo(); + + return ix; + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end TkInputState.cpp */ diff --git a/src/tokenizer2/Token.cpp b/src/tokenizer2/Token.cpp new file mode 100644 index 00000000..f228d56e --- /dev/null +++ b/src/tokenizer2/Token.cpp @@ -0,0 +1,259 @@ +/** @file token.cpp + * + * author: Roland Conybeare + **/ + +#include "Token.hpp" +#include "xo/indentlog/print/tag.hpp" + +namespace xo { + namespace scm { + + bool + Token::bool_value() const + { + if (tk_type_ != tokentype::tk_bool) { + throw (std::runtime_error + (tostr("token::bool_value", + ": token with type tk found where tk_bool expected", + xtag("tk", tk_type_)))); + } + + if (text_ == "true") + return true; + if (text_ == "false") + return false; + + throw (std::runtime_error + (tostr("token::bool_value", + ": unexpected input string tk_bool token", + xtag("text", text_)))); + + return false; + } + + std::int64_t + Token::i64_value() const + { + if (tk_type_ != tokentype::tk_i64) { + throw (std::runtime_error + (tostr("token::i64_value", + ": token with type tk found where tk_i64 expected", + xtag("tk", tk_type_)))); + } + + if (text_.empty()) { + throw (std::runtime_error + (tostr("token::i64_value", + ": unexpected empty input string for tk_i64 token"))); + } + + int sign = 1; + int value = 0; + { + auto ix = text_.begin(); + auto end_ix = text_.end(); + + char ch = *ix; + + if (ch == '+') { + ++ix; + } else if (ch == '-') { + sign = -1; + ++ix; + } + + if (ix == end_ix) { + throw (std::runtime_error + (tostr("token::i64_value", + ": input text found where at least one digit expected", + xtag("text", text_)))); + } + + for (; ix != end_ix; ++ix) { + char ch = *ix; + + if ((ch >= '0') && (ch <= '9')) { + value *= 10; + value += (ch - '0'); + } else { + throw (std::runtime_error + (tostr("token::i64_value", + ": unexpected char ch in integer token", + xtag("ch", ch)))); + } + } + } + + return sign * value; + } /*i64_value*/ + + double + Token::f64_value() const + { + if (tk_type_ != tokentype::tk_f64) { + throw (std::runtime_error + (tostr("token::f64_value", + ": token with type tk found where tk_f64 expected", + xtag("tk", tk_type_)))); + } + + if (text_.empty()) { + throw (std::runtime_error + (tostr("token::f64_value", + ": unexpected empty input string for tk_f64 token"))); + } + + int sign = 1; + /* integer representing denormalized unsigned mantissa + * (mantissa scaled by smallest power of 10 sufficient to make + * it an integer) + */ + std::int64_t mantissa = 0; + /* counts #of digits to the right of decimal point '.' */ + int rh_digits = 0; + /* sign of exponent */ + int exp_sign = 1; + /* value of exponenct = integer to the right of 'e' or 'E' */ + int exponent = 0; + + /* floating-point value will represent + * sign * mantissa * 10^(sign*exponent - rh_digits) + */ + { + auto ix = text_.begin(); + auto end_ix = text_.end(); + + char ch = *ix; + + if (ch == '+') { + ++ix; + } else if (ch == '-') { + sign = -1; + ++ix; + } + + if (ix == end_ix) { + throw (std::runtime_error + (tostr("token::f64_value", + ": input text found where at least one digit expected", + xtag("text", text_)))); + } + + /* true iff decimal point '.' present in mantissa */ + bool have_decimal_point = false; + /* true iff exponent prefix 'e' or 'E' present */ + //bool have_exponent = false; + /* counts number of digits in mantissa + * (both before and after, but not including, any decimal point + */ + int m_digits = 0; + /* digits to the left of decimal point */ + int lh_digits = 0; + + /* loop over mantissa digits */ + for (; ix != end_ix; ++ix) { + char ch = *ix; + + if (ch == '.') { + if (have_decimal_point) { + throw (std::runtime_error + (tostr("token::f64_value", + ": input text found where at most one decimal point expected", + xtag("text", text_)))); + } + + have_decimal_point = true; + lh_digits = m_digits; + } else if ((ch >= '0') && (ch <= '9')) { + mantissa *= 10; + mantissa += (ch - '0'); + ++m_digits; + } else if (ch == 'e' || ch == 'E') { + //have_exponent = true; + break; // done with mantissa + } else { + throw (std::runtime_error + (tostr("token::i64_value", + ": unexpected char ch in integer token", + xtag("ch", ch)))); + } + } + + if (have_decimal_point) + rh_digits = m_digits - lh_digits; + + if (ix != end_ix) { + /* continue to read exponent */ + + /* skip e|E */ + ++ix; + + if (ix == end_ix) { + throw (std::runtime_error + (tostr("token::f64_value", + ": on input text, expect at least one digit following exponent marker e|E", + xtag("text", text_)))); + } + + char ch = *ix; + + if (ch == '+') { + ++ix; /*skip*/ + } else if (ch == '-') { + exp_sign = -1; + ++ix; + } + + for (; ix != end_ix; ++ix) { + char ch = *ix; + + if ((ch >= '0') && (ch <= '9')) { + exponent *= 10; + exponent += (ch - '0'); + } else { + throw (std::runtime_error + (tostr("token::f64_value", + "; on input text, expect only digits following" + " (possibly signed) exponenct marker", + xtag("text", text_)))); + } + } + } + } + + /* floating-point value will represent + * sign * mantissa * 10^(sign*exponent - rh_digits) + */ + + double mantissa_f64 = sign * mantissa; + +#ifdef OBSOLETE_DEBUG + std::cerr << xtag("text", text_) + << xtag("rh_digits", rh_digits) + << xtag("mantissa_f64", mantissa_f64) + << xtag("exp_sign", exp_sign) + << xtag("exponent", exponent) + << std::endl; +#endif + + double retval = (mantissa_f64 + * detail::pow10((exp_sign * exponent) + - rh_digits)); + + return retval; + } /*f64_value*/ + + void + Token::print(std::ostream & os) const + { + os << ""; + } /*print*/ + } /*namespace scm*/ +} /*namespace xo*/ + +/* end token.cpp */ diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp new file mode 100644 index 00000000..00ef4eec --- /dev/null +++ b/src/tokenizer2/Tokenizer.cpp @@ -0,0 +1,836 @@ +/** @file Tokenizer.cpp + * + * @author Roland Conybeare, Jul 2024 + **/ + +#include "Tokenizer.hpp" + +namespace xo { + namespace scm { + Tokenizer::Tokenizer(bool debug_flag) + : input_state_{debug_flag} + {} + + void + Tokenizer::discard_current_line() + { + this->input_state_.discard_current_line(); + } + + bool + Tokenizer::is_1char_punctuation(CharT ch) + { + switch(ch) { + case '(': + return true; + case ')': + return true; + case '[': + return true; + case ']': + return true; + case '{': + return true; + case '}': + return true; + case '<': + /* can't be 1char punctuation -- can begin lessequal token */ + return false; + case '>': + /* can't be 1char punctuation -- can begin greatequal token, + * and appears in tk_yields token + */ + return false; + case ',': + return true; + case ';': + return true; + case ':': + /* can't be 1char punctuation -- can begin assignment token */ + return false; + case '=': + /* can't be 1char punctuation -- can begin comparison token '==' */ + return false; + case '!': + /* can't be 1char punctuation -- can begin comparison token '!=' */ + return false; + case '-': + /* can't be punctuation + * - can appear inside f64 token: e.g. 1.23e-9. + * - begins tk_yields token: -> + */ + return false; + case '+': + /* can't be punctuation -- can appear inside f64 token: e.g. 1.23e+4 */ + return false; + case '*': + /* not punctuation -- allowed in symbol */ + return false; + case '/': + /* not punctuation -- for symmetry with +,- */ + return false; + case '.': + /* can't be punctuation -- can appear inside f64 token: e.g. 1.23 */ + return false; + } + + return false; + } + + bool + Tokenizer::is_2char_punctuation(CharT ch) + { + /* can't put '-' here, because of the way it appears in numeric literals + * characters here may not appear in symbol names + */ + + switch(ch) { + case '<': + /* can begin <= */ + return true; + case '>': + /* can begin >= */ + return true; + case ':': + /* can begin := */ + return true; + case '=': + /* can begin == */ + return true; + case '!': + /* can begin != */ + return true; + } + + return false; + } + + auto + Tokenizer::assemble_token(std::size_t initial_whitespace, + const span_type & token_text, + input_state_type * p_input_state) -> result_type + { + /* literal|pretty|streamlined */ + log_config::style = function_style::streamlined; + + scope log(XO_DEBUG(p_input_state->debug_flag())); + log && log(xtag("token_text", token_text), + xtag("initial_whitespace", initial_whitespace), + xtag("input_state", *p_input_state)); + + tokentype tk_type = tokentype::tk_invalid; + std::string tk_text; + + const CharT * tk_start = token_text.lo(); + const CharT * tk_end = token_text.hi(); + + const CharT * ix = tk_start; + + /* switch here applies to the first character in a token */ + switch (*ix) { + case '-': + case '+': + if (token_text.size() == 1) { + /* standalone '+' or '-' */ + if (*ix == '+') + tk_type = tokentype::tk_plus; + else if(*ix == '-') + tk_type = tokentype::tk_minus; + } + + /** fall through to numeric literal code below **/ + [[fallthrough]]; + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + /* examples of valid floating-point numbers: + * .0 + * 1e0 + * 1e + * 0. + * +1e0 + * -1e0 + * +1E+2 + * -1E+2 + * -0.123e-10 + * non-examples: + * . + * - + * + + * e0 + * .e0 + * -.e-0 + * +.e+0 + * + * in particular: to be recognized as a number, + * must contain at least one digit + */ + + log && log("possible number-token"); + + /* true if initial sign -/+ encountered */ + bool sign_flag = false; + /* true if '.' encountered */ + bool period_flag = false; + /* true if 'e' | 'E' encountered. + */ + bool exponent_flag = false; + /* true when sign '-' | '+' precedes exponenct digits */ + bool exponent_sign_flag = false; + /* true when at least one digit follows exponent marker */ + bool exponent_digit_flag = false; + /* true if at least one digit encountered */ + bool number_flag = false; + + log && log(xtag("*ix", *ix), + xtag("tk.length", token_text.size())); + if (log && (ix + 1 < tk_end)) + log(xtag("*(ix+1)", *(ix + 1))); + + if ((*ix == '-') && (ix + 2 == token_text.hi()) && (*(ix + 1) == '>')) { + /* composing exactly '->' */ + tk_type = tokentype::tk_yields; + } else { + /* token (if valid) will be one of: {tk_i64, tk_f64, tk_dot}: */ + for (; ix != token_text.hi(); ++ix) { + if ((*ix == '-') || (*ix == '+')) { + /* sign allowed: + * 1. before period and before first digit + * 2. after exponent + */ + if (!period_flag && !number_flag && !sign_flag) { + sign_flag = true; + } else if (exponent_flag && !exponent_digit_flag) { + exponent_sign_flag = true; + } else { + return result_type::make_error_consume_current_line + (__FUNCTION__ /*src_function*/, + "improperly placed sign indicator", + (ix - tk_start), + *p_input_state); + } + } else if (*ix == '.') { + if (period_flag) { + return result_type::make_error_consume_current_line + (__FUNCTION__ /*src_function*/, + "duplicate decimal point in numeric literal", + (ix - tk_start), + *p_input_state); + } + + period_flag = true; + } else if ((*ix == 'e') || (*ix == 'E')) { + if (exponent_flag) { + return result_type::make_error_consume_current_line + (__FUNCTION__ /*src_function*/, + "duplicate exponent marker in numeric literal", + (ix - tk_start), + *p_input_state); + } + + exponent_flag = true; + } else if (isdigit(*ix)) { + if (exponent_flag) { + /* need digit before exponent to recognize as number */ + exponent_digit_flag = true; + } else { + number_flag = true; + } + } else { + return result_type::make_error_consume_current_line + (__FUNCTION__ /*src_function*/, + "unexpected character in numeric constant" /*error_description*/, + (ix - tk_start), + *p_input_state); + } + } + + if (number_flag) { + if (period_flag || exponent_flag) { + tk_type = tokentype::tk_f64; + } else { + tk_type = tokentype::tk_i64; + } + } else if (period_flag && !exponent_flag) { + tk_type = tokentype::tk_dot; + } else { + /* not a valid token */ + } + + log && log(xtag("sign_flag", sign_flag)); + log && log(xtag("period_flag", period_flag), + xtag("exponent_flag", exponent_flag), + xtag("exponent_sign_flag", exponent_sign_flag), + xtag("number_flag", number_flag)); + log && log(xtag("tk_type", tk_type)); + } + + break; + } + case '*': + if (token_text.size() == 1) { + /* standalone '*' */ + tk_type = tokentype::tk_star; + ++ix; + } else { + /* '*' isn't punctuation -- but may allow appearance in a longer token + * + * thinking that x*y is a symbol with an embedded '*' character; + * in particular want to support kebab-case symbols like 'foo-config' + */ + } + break; + case '/': + if (token_text.size() == 1) { + /* standalone '/' */ + tk_type = tokentype::tk_slash; + ++ix; + } + break; + case '=': + log && log("singleassign or cmpeq token"); + + if (*(ix + 1) == '=') { + tk_type = tokentype::tk_cmpeq; + ++ix; + ++ix; + } else { + /* standalone '=' */ + tk_type = tokentype::tk_singleassign; + ++ix; + } + break; + case '!': + if (*(ix + 1) == '=') { + tk_type = tokentype::tk_cmpne; + ++ix; + ++ix; + } else { + /* standlone '!' */ + + // TODO + } + break; + case '"': + { + log && log("recognize string-token"); + + tk_type = tokentype::tk_string; + + tk_text.reserve(token_text.hi() - token_text.lo()); + + ++ix; /*skip initial " char*/ + + /* true on final " */ + bool endofstring = false; + + for (; ix != token_text.hi(); ++ix) { + log && log(xtag("*ix", *ix)); + + switch(*ix) { + case '"': + endofstring = true; + + /* skip final " char, don't capture */ + ++ix; + + break; + case '\\': + /* skip escape char, don't capture */ + ++ix; + + if (ix == token_text.hi()) { + return result_type::make_error_consume_current_line + (__FUNCTION__ /*src_function*/, + "expecting key following escape character \\", + (ix - tk_start), + *p_input_state); + } + + switch(*ix) { + case '\\': + log && log(xtag("*ix", *ix), xtag("escaped", "t")); + tk_text.push_back(*ix); + break; + case 'n': + log && log(xtag("*ix", *ix), xtag("newline", "t")); + tk_text.push_back('\n'); + break; + case 't': + log && log(xtag("*ix", *ix), xtag("tab", "t")); + tk_text.push_back('\t'); + break; + case 'r': + log && log(xtag("*ix", *ix), xtag("cr", "t")); + tk_text.push_back('\r'); + break; + case '"': + log && log(xtag("*ix", *ix), xtag("quote", "t")); + tk_text.push_back('"'); + break; + default: + return result_type::make_error_consume_current_line + (__FUNCTION__ /*src_function*/, + "expecting one of n|r|\"|\\ following escape \\", + (ix - tk_start), + *p_input_state); + } + break; + default: + tk_text.push_back(*ix); + break; + } + + if (endofstring) + break; + } + + if (!endofstring) { + return result_type::make_error_consume_current_line + (__FUNCTION__ /*src_function*/, + "missing terminating '\"' to complete literal string", + (ix - tk_start), + *p_input_state); + } + + log && log(tostr("tokenizer::assemble_token", + xtag("tk_text", tk_text))); + + break; + } + case 'a': case 'A': + case 'b': case 'B': + case 'c': case 'C': + case 'd': case 'D': + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + case 'h': case 'H': + case 'i': case 'I': + case 'j': case 'J': + case 'k': case 'K': + case 'l': case 'L': + case 'm': case 'M': + case 'n': case 'N': + case 'o': case 'O': + case 'p': case 'P': + case 'q': case 'Q': + case 'r': case 'R': + case 's': case 'S': + case 't': case 'T': + case 'u': case 'U': + case 'v': case 'V': + case 'w': case 'W': + case 'x': case 'X': + case 'y': case 'Y': + case 'z': case 'Z': + { + /* symbol/identifier must begin with a letter? + * we want to accept some other chars too. + * specifically want to allow identifiers: + * this-is-the-way + * this+is+also+the+way + * how/much/is/that/doggy + * put*an*asterisk*in*that + * something%special% + * + * like pure lisp, we don't allow: + * - identifier beginning with digit + * - period . + * + * unlike pure lisp, we don't allow anywhere in a symbol: + * - colon : + * - semicolon ; + * - comma , + * + * also we don't allow symbols to begin with special chars + */ + + tk_type = tokentype::tk_symbol; + break; + } + case '<': + { + log && log("leftangle or lessequal token"); + + if (*(ix + 1) == '=') { + tk_type = tokentype::tk_lessequal; + ++ix; + ++ix; + } else { + tk_type = tokentype::tk_leftangle; + ++ix; + } + break; + } + case '>': + { + log && log("rightangle or greatequal token"); + + if (*(ix + 1) == '=') { + tk_type = tokentype::tk_greatequal; + ++ix; + ++ix; + } else { + tk_type = tokentype::tk_rightangle; + ++ix; + } + break; + } + case '(': + tk_type = tokentype::tk_leftparen; + ++ix; + break; + case ')': + tk_type = tokentype::tk_rightparen; + ++ix; + break; + case '[': + tk_type = tokentype::tk_leftbracket; + ++ix; + break; + case ']': + tk_type = tokentype::tk_rightbracket; + ++ix; + break; + case '{': + tk_type = tokentype::tk_leftbrace; + ++ix; + break; + case '}': + tk_type = tokentype::tk_rightbrace; + ++ix; + break; + case ',': + tk_type = tokentype::tk_comma; + ++ix; + break; + case ';': + tk_type = tokentype::tk_semicolon; + ++ix; + break; + case ':': + { + log && log("colon or assignment token"); + + if (*(ix + 1) == '=') { + tk_type = tokentype::tk_assign; + ++ix; + ++ix; + } else { + tk_type = tokentype::tk_colon; + ++ix; + } + break; + } + default: + break; + } + + if (tk_type == tokentype::tk_invalid) { + return result_type::make_error_consume_current_line + (__FUNCTION__ /*src_function*/, + "illegal input character", + (ix - tk_start), + *p_input_state); + } + + if ((tk_type == tokentype::tk_i64) + || (tk_type == tokentype::tk_f64) + || (tk_type == tokentype::tk_symbol)) + { + /* note: capturing token text here; + * for numeric literals will re-parse in token::i64_value() / token::f64_value() + */ + tk_text = std::string(tk_start, tk_end); + } else if (tk_type == tokentype::tk_string) { + ; /* nothing to do here -- desired tk_text already constructed */ + } + + if (tk_type == tokentype::tk_symbol) { + /* check for keywords */ + + bool keep_text = false; + + if ((tk_text == "true") || (tk_text == "false")) { + tk_type = tokentype::tk_bool; + keep_text = true; + } else if (tk_text == "type") { + tk_type = tokentype::tk_type; + } else if (tk_text == "def") { + tk_type = tokentype::tk_def; + } else if (tk_text == "lambda") { + tk_type = tokentype::tk_lambda; + } else if (tk_text == "if") { + tk_type = tokentype::tk_if; + } else if (tk_text == "then") { + tk_type = tokentype::tk_then; + } else if (tk_text == "else") { + tk_type = tokentype::tk_else; + } else if (tk_text == "let") { + tk_type = tokentype::tk_let; + } else if (tk_text == "in") { + tk_type = tokentype::tk_in; + } else if (tk_text == "end") { + tk_type = tokentype::tk_end; + } else { + /* keep as symbol */ + keep_text = true; + } + + if (!keep_text) + tk_text.clear(); + } + + /* input.prefix(0): + * require caller preserves current input line until it's entirely exhausted + */ + return result_type(token_type(tk_type, std::move(tk_text)), + p_input_state->current_line().prefix(0)); + } /*assemble_token*/ + + auto + Tokenizer::assemble_final_token(const span_type & token_text, + input_state_type * p_input_state) -> result_type + { + return assemble_token(0 /*initial_whitespace*/, + token_text, + p_input_state); + } + + auto + Tokenizer::scan(const span_type & input, + bool eof_flag) -> result_type + { + scope log(XO_DEBUG(input_state_.debug_flag())); + + log && log(xtag("input", input)); + + /* - Always at beginning of token when scan() invoked + * - scan will not report any portion of line as consumed until it has + * emitted all tokens in that line. + * rationale: caller is allowed to discard storage that + * scan() reports as consumed. But will be holding that line + * until all tokens have been read. + * - this means caller will typically call scan() + * with the same input span multiple times + */ + + /* automagically no-ops when the same input presented twice */ + this->input_state_.capture_current_line(input, eof_flag); + + const CharT * ix = this->input_state_.skip_leading_whitespace(); + + if(ix == input.hi()) { + log && log("end input -> consume current line"); + + /* entirety of current line has been tokenized + * -> caller may consume it + */ + return result_type::make_whitespace(this->input_state_.consume_current_line()); + } + + /* ix: if ix < input.hi: first non-whitespace character after input_state_.current_pos_ */ + + // TODO: + // 1. hoist complete_flag up here + // 2. use in each branch + // 3. common check for prefix-capturing after if-cascade below done + + /* here: *ix is not whitespace */ + + auto whitespace_z = input_state_.whitespace(); + + log && log(xtag("whitespace_z", whitespace_z)); + + /* tk_start points to known beginning of token + * (after any whitespace) + * + * goal is to leave ix pointing to 1 char past the end of the token + */ + const CharT * tk_start = ix; + + if (is_1char_punctuation(*ix)) { + /* 1-character token */ + ++ix; + } else if (is_2char_punctuation(*ix)) { + CharT ch1 = *ix; + + (void)ch1; + + ++ix; + +#ifdef OBSOLETE // no longer a thing. either input ends in whitespace, or ends translation unit + if (ix == input.hi()) { + /* need more input to know if/when token complete */ + this->prefix_ += std::string(tk_start, input.hi()); + + log && log(xtag("captured-prefix1", this->prefix_)); + } else +#endif + { + CharT ch2 = *ix; + + if (((ch2 >= '0') && (ch2 <= '9')) + || ((ch2 >= 'A') && (ch2 <= 'Z')) + || ((ch2 >= 'a') && (ch2 <= 'z'))) + { + /* treat as 1 char punctuation */ + ; + } else { + /* include next char */ + ++ix; + } + } + } else if (*ix == '"') { + bool complete_flag = false; + + /* 1. embedded space/tab allowed in string literal. + * 2. embedded newline/cr not allowed. + */ + CharT prev_ch = '"'; + + ++ix; + + for (; ix != input.hi(); ++ix) { + /* looking for unescaped " char to end literal */ + if (*ix == '"') { + if (prev_ch != '\\') { + ++ix; /* include terminating " for assemble_token */ + complete_flag = true; + break; + } + } else if ((*ix == '\n') || (*ix == '\r')) { + log && log ("string literal with naked newline or CR"); + + return result_type::make_error_consume_current_line + (__FUNCTION__ /*src_function*/, + "must use \\n or \\r to encode newline/cr in string literal", + (ix - tk_start), + this->input_state_); + } + + prev_ch = *ix; + } + + if (!complete_flag) { + log && log("unterminated string literal"); + + return result_type::make_error_consume_current_line + (__FUNCTION__ /*src_function*/, + "unterminated string literal", + (ix - tk_start), + this->input_state_); + } + } else { + /* ix is start of some token */ + + if (*ix == '-') { + /* this section load-bearing for input '->' scanning from beginning of token */ + ++ix; + + if (ix == input.hi()) { + /* need more input to know if/when token complete -- see captured-prefix5 below */ + } else { + CharT ch2 = *ix; + + if (ch2 == '>') { + /* include next char and complete token */ + ++ix; + + log && log("complete '->' token"); + + this->input_state_.advance_until(ix); + + return assemble_token(whitespace_z, + span_type(tk_start, ix) /*token*/, + &(this->input_state_)); + } + + /* here: -123, -.5e-21 for example */ + } + } else if (*ix == '>') { + /* this section load-bearing for input '>=' scanning from beginning of token. + * Need this because '>' necessarily excluded from is_1char_punctuation() + */ + ++ix; + + if (ix == input.hi()) { + /* need more input to know if/when token complete -- see captured-prefix5 below */ + } else { + CharT ch2 = *ix; + + if (ch2 != '=') { + log && log("complete '>=' token"); + + this->input_state_.advance_until(ix); + + /* ignore next char and complete token */ + return assemble_token(whitespace_z, + span_type(tk_start, ix) /*token*/, + &(this->input_state_)); + } + + /* here: >= for example */ + } + } + + /* scan until: + * - whitespace + * - punctuation + */ + for (; ix != input.hi(); ++ix) { + if (input_state_type::is_whitespace(*ix) + || is_1char_punctuation(*ix) + || is_2char_punctuation(*ix)) + { + break; + } + + /* this section load-bearing for input '>' after beginning of a token, e.g. p> */ + if ((ix > tk_start) && (*ix == '>')) + break; + + /* this section load-bearing for input '->' at the end of another token, e.g. p->q */ + if (*ix == '-') { + if (ix + 1 == input.hi()) { + /* need more input to know if/when token complete + * + * apple-banana parses as: {tk_symbol: apple-banana} + * apple-> parses as: {tk_symbol: apple} {tk_yields} + * apple- illegal (may not end symbol with '-') + */ + break; + } + + if (*(ix + 1) == '>') { + /* treat '->' as punctuation; complete preceding token */ + break; + } + } + } + } + + log && log("assemble token z", xtag("token_z", ix - tk_start)); + + assert(tk_start < ix); + + this->input_state_.advance_until(ix); + + return assemble_token(whitespace_z, + span_type(tk_start, ix) /*token*/, + &(this->input_state_)); + } /*scan*/ + } /*namespace scm*/ +} /*namespace xo*/ + +/* end Tokenizer.cpp */ diff --git a/src/tokenizer2/TokenizerError.cpp b/src/tokenizer2/TokenizerError.cpp new file mode 100644 index 00000000..ffe3c8b4 --- /dev/null +++ b/src/tokenizer2/TokenizerError.cpp @@ -0,0 +1,60 @@ +/** @file TokenizerError.cpp + * + * @author Roland Conybeare, Jun 2025 + **/ + +#include "TokenizerError.hpp" + +namespace xo { + namespace scm { + + void + TokenizerError::print(std::ostream & os) const + { + os << ""; + } + + void + TokenizerError::report(std::ostream & os) const + { + using namespace std; + + if (!error_description_.empty()) { + const char * prefix = "input: "; + /* input_state.tk_start: position of first character in token + * input_state.current_pos: position of first character following preceding token. + * error_pos: position (relative to start) at which failure detected + */ + const size_t tk_start = input_state_.tk_start(); + const size_t tk_indent = (strlen(prefix) + tk_start); + const size_t error_pos = 1 + tk_start + error_pos_; + + os << "token col: " << tk_start << ", error col: " << error_pos << "\n"; + os << prefix; + for (const char *p = input_state_.current_line().lo(), + *e = input_state_.current_line().hi(); p < e; ++p) + { + os << *p; + } + //os << endl; + os << std::setw(tk_indent) << " "; + + for (size_t i = 0; i < error_pos_; ++i) { + os << '_'; + } + os << '^' << endl; + + os << error_description_ << endl; + } + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end TokenizerError.cpp */ diff --git a/src/tokenizer2/scan_result.cpp b/src/tokenizer2/scan_result.cpp new file mode 100644 index 00000000..05c5c0f7 --- /dev/null +++ b/src/tokenizer2/scan_result.cpp @@ -0,0 +1,43 @@ +/** @file scan_result.cpp + * + * @author Roland Conybeare, 2025 + **/ + +#include "scan_result.hpp" + +namespace xo { + namespace scm { + scan_result + scan_result::make_whitespace(const span_type& whitespace_input) + { + return scan_result(token_type::invalid(), whitespace_input /*consumed*/); + } + + scan_result + scan_result::make_partial(const span_type& prefix_input) + { + return scan_result(token_type::invalid(), prefix_input /*consumed*/); + } + + scan_result + scan_result::make_error_consume_current_line(const char * error_src, + std::string error_msg, + size_t error_pos, + input_state_type & input_state_ref) + { + /* report+consume entire input line */ + + /* copy before altered by .consume_current_line() */ + input_state_type input_state_copy = input_state_ref; + + return scan_result(token_type::invalid(), + input_state_ref.consume_current_line(), + error_type(error_src, + error_msg, + input_state_copy, + error_pos)); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end scan_result.cpp */ diff --git a/src/tokenizer2/tokentype.cpp b/src/tokenizer2/tokentype.cpp new file mode 100644 index 00000000..33d683de --- /dev/null +++ b/src/tokenizer2/tokentype.cpp @@ -0,0 +1,74 @@ +/* file tokentype.cpp + * + * author: Roland Conybeare + */ + +#include "tokentype.hpp" + +namespace xo { + namespace scm { + char const * + tokentype_descr(tokentype tk_type) + { +#define CASE(x) case tokentype::x: return STRINGIFY(x) + + switch(tk_type) { + CASE(tk_bool); + CASE(tk_i64); + CASE(tk_f64); + CASE(tk_string); + CASE(tk_symbol); + CASE(tk_leftparen); + + CASE(tk_rightparen); + CASE(tk_leftbracket); + CASE(tk_rightbracket); + CASE(tk_leftbrace); + CASE(tk_rightbrace); + + CASE(tk_leftangle); + CASE(tk_rightangle); + CASE(tk_lessequal); + CASE(tk_greatequal); + CASE(tk_dot); + CASE(tk_comma); + CASE(tk_colon); + + CASE(tk_doublecolon); + CASE(tk_semicolon); + CASE(tk_singleassign); + CASE(tk_assign); + CASE(tk_yields); + + CASE(tk_plus); + CASE(tk_minus); + CASE(tk_star); + CASE(tk_slash); + + CASE(tk_cmpeq); + CASE(tk_cmpne); + + CASE(tk_type); + CASE(tk_def); + CASE(tk_lambda); + CASE(tk_if); + CASE(tk_then); + CASE(tk_else); + CASE(tk_let); + + CASE(tk_in); + CASE(tk_end); + + case tokentype::tk_invalid: + case tokentype::n_tokentype: + return "?tokentype"; + } + +#undef CASE + + return "???"; + } /*tokentype_descr*/ + } /*namespace scm*/ +} /*namespace xo*/ + +/* end tokentype.cpp */ From 185519a22e65ea477851f90650917464fbcb816d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 10 Jan 2026 12:39:09 -0500 Subject: [PATCH 068/342] + xo-tokenizer2 xo-reader2 xo-expression2 xo-interpreter2 2nd gen schematika interpreter using fomo --- CMakeLists.txt | 41 +++++++++++++++++++++++++++++++++ README.md | 1 - cmake/xo-bootstrap-macros.cmake | 33 ++++++++++++++++++++++++++ cmake/xo_reader2Config.cmake.in | 12 ++++++++++ include/xo/reader2/.gitkeep | 0 5 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 CMakeLists.txt delete mode 100644 README.md create mode 100644 cmake/xo-bootstrap-macros.cmake create mode 100644 cmake/xo_reader2Config.cmake.in create mode 100644 include/xo/reader2/.gitkeep diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..a8508472 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,41 @@ +# xo-reader2/CMakeLists.txt + +cmake_minimum_required(VERSION 3.10) + +project(xo_reader2 VERSION 1.0) +enable_language(CXX) + +include(GNUInstallDirs) +include(cmake/xo-bootstrap-macros.cmake) + +xo_cxx_toplevel_options3() + +# ---------------------------------------------------------------- +# c++ settings + +# one-time project-specific c++ flags. usually empty +set(PROJECT_CXX_FLAGS "") +add_definitions(${PROJECT_CXX_FLAGS}) + +# ---------------------------------------------------------------- +# output targets + +#add_subdirectory(utest) + +# ---------------------------------------------------------------- +# header-only library + +set(SELF_LIB xo_reader2) +xo_add_headeronly_library(${SELF_LIB}) +xo_install_library4(${SELF_LIB} ${PROJECT_NAME}Targets) +xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) + +# ---------------------------------------------------------------- +# input dependencies +# +# NOTE: dependency set here must be kept consistent with +# xo-reader2/cmake/xo_reader2Config.cmake.in + +#xo_headeronly_dependency(${SELF_LIB} xo_flatstring) + +# end CMakeLists.txt diff --git a/README.md b/README.md deleted file mode 100644 index 112a599e..00000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# xo-reader2 diff --git a/cmake/xo-bootstrap-macros.cmake b/cmake/xo-bootstrap-macros.cmake new file mode 100644 index 00000000..2cf387e5 --- /dev/null +++ b/cmake/xo-bootstrap-macros.cmake @@ -0,0 +1,33 @@ +# ---------------------------------------------------------------- +# for example: +# $ PREFIX=/usr/local # for example +# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=$PREFIX -B .build +# +# will get +# CMAKE_MODULE_PATH +# from xo-cmake-config --cmake-module-path +# +# and expect .cmake macros in +# CMAKE_MODULE_PATH/xo_macros/xo_cxx.cmake +# ---------------------------------------------------------------- + +find_program(XO_CMAKE_CONFIG_EXECUTABLE NAMES xo-cmake-config REQUIRED) + +if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL "prefix")) + message(FATAL "could not find xo-cmake-config executable") +endif() + +if (NOT XO_SUBMODULE_BUILD) + if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix)) + # default to typical install location for xo-project-macros + execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --cmake-module-path OUTPUT_VARIABLE CMAKE_MODULE_PATH) + message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + endif() +endif() + +# needs to have been installed somewhere on CMAKE_MODULE_PATH, +# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX) +# +include(xo_macros/xo_cxx) + +xo_cxx_bootstrap_message() diff --git a/cmake/xo_reader2Config.cmake.in b/cmake/xo_reader2Config.cmake.in new file mode 100644 index 00000000..b5c3cd5c --- /dev/null +++ b/cmake/xo_reader2Config.cmake.in @@ -0,0 +1,12 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +# note: changes to find_dependency() calls here +# must coordinate with xo_dependency() calls +# in CMakeLists.txt +# +#find_dependency(xo_flatstring) + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/include/xo/reader2/.gitkeep b/include/xo/reader2/.gitkeep new file mode 100644 index 00000000..e69de29b From 1575f8a14736c9f5e1d42b5a82cee360c4d88ce0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 11 Jan 2026 18:42:08 -0500 Subject: [PATCH 069/342] xo-tokenizer2: use xo-arena DCircularBuffer to buffer input line --- cmake/xo_tokenizer2Config.cmake.in | 5 +- example/tokenrepl/tokenrepl.cpp | 66 ++--- include/xo/tokenizer2/TkInputState.hpp | 6 +- include/xo/tokenizer2/Tokenizer.hpp | 32 ++- include/xo/tokenizer2/TokenizerError.hpp | 2 +- include/xo/tokenizer2/scan_result.hpp | 2 +- include/xo/tokenizer2/span.hpp | 291 ----------------------- src/tokenizer2/CMakeLists.txt | 2 + src/tokenizer2/TkInputState.cpp | 3 +- src/tokenizer2/Tokenizer.cpp | 56 ++++- 10 files changed, 106 insertions(+), 359 deletions(-) delete mode 100644 include/xo/tokenizer2/span.hpp diff --git a/cmake/xo_tokenizer2Config.cmake.in b/cmake/xo_tokenizer2Config.cmake.in index b5c3cd5c..13f1dac1 100644 --- a/cmake/xo_tokenizer2Config.cmake.in +++ b/cmake/xo_tokenizer2Config.cmake.in @@ -4,9 +4,10 @@ include(CMakeFindDependencyMacro) # note: changes to find_dependency() calls here # must coordinate with xo_dependency() calls -# in CMakeLists.txt +# in src/tokenizer2/CMakeLists.txt # -#find_dependency(xo_flatstring) +find_dependency(xo_arena) +find_dependency(indentlog) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") check_required_components("@PROJECT_NAME@") diff --git a/example/tokenrepl/tokenrepl.cpp b/example/tokenrepl/tokenrepl.cpp index f97b9cd0..0852f028 100644 --- a/example/tokenrepl/tokenrepl.cpp +++ b/example/tokenrepl/tokenrepl.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -14,7 +14,7 @@ bool replxx_getline(bool interactive, std::size_t parser_stack_size, replxx::Replxx & rx, - std::string& input) + const char ** p_input) { using namespace std; @@ -34,40 +34,23 @@ bool replxx_getline(bool interactive, if (retval) { //cerr << "got reval->true" << endl; - input = input_cstr; + *p_input = input_cstr; } else { //cerr << "got retval->false" << endl; } - rx.history_add(input); - - // we want tokenizer to see newline, it's syntax - input.push_back('\n'); + rx.history_add(input_cstr); return retval; } -#ifdef OBSOLETE -bool repl_getline(bool interactive, - std::istream & in, - std::ostream & out, - std::string & input) -{ - if (interactive) { - out << "> "; - std::flush(out); - } - - return static_cast(std::getline(in, input)); -} -#endif - int main() { using xo::scm::Tokenizer; - using xo::scm::span; using xo::scm::operator<<; + using xo::mm::CircularBufferConfig; + using xo::mm::span; using replxx::Replxx; using namespace std; @@ -82,36 +65,39 @@ main() { rx.set_max_history_size(1000); rx.history_load("repl_history.txt"); - Tokenizer tkz(xo::log_config::min_log_level <= xo::log_level::info); + Tokenizer tkz(CircularBufferConfig{.name_ = "tokenrepl-input", + .max_capacity_ = 4*1024, + .max_captured_span_ = 128}, + true /*debug_flag*/); - string input_str; + const char * input_cstr = nullptr;; size_t line_no = 1; constexpr std::size_t c_maxlines = 25; - while ( - //repl_getline(interactive, cin, cout, input_str) // once upon a time - replxx_getline(interactive, 0 /*parser_stack_size*/, rx, input_str)) + while (replxx_getline(interactive, 0 /*parser_stack_size*/, rx, &input_cstr)) { - span_type input = span_type::from_string(input_str); - //cout << "input: " << input << endl; // reminder: input may contain multiple tokens - while (!input.empty()) { - auto [tk, consumed, error] = tkz.scan(input, false /*!eof*/); + if (input_cstr && *input_cstr) { + auto [error, input] = tkz.buffer_input_line(input_cstr, false /*!eof*/); - if (tk.is_valid()) { - cout << tk << endl; - } else if (error.is_error()) { - cout << "tokenizer error: " << endl; - error.report(cout); + { + auto [tk, consumed, error] = tkz.scan(input); - break; + if (tk.is_valid()) { + cout << tk << endl; + } else if (error.is_error()) { + cout << "tokenizer error: " << endl; + error.report(cout); + + break; + } + + input = input.after_prefix(consumed); } - - input = input.after_prefix(consumed); } /* here: input.empty() or error encountered */ diff --git a/include/xo/tokenizer2/TkInputState.hpp b/include/xo/tokenizer2/TkInputState.hpp index 531585a1..ea315a0a 100644 --- a/include/xo/tokenizer2/TkInputState.hpp +++ b/include/xo/tokenizer2/TkInputState.hpp @@ -63,7 +63,7 @@ namespace xo { using CharT = char; /** type representing a contiguous span of tokenizer input characters **/ - using span_type = span; + using span_type = xo::mm::span; ///@} @@ -76,7 +76,7 @@ namespace xo { /** Create instance with supplied @p current_line, @p current_pos, @p whitespace. * Introduced for unit tests, not used in tokenizer. **/ - explicit TkInputState(const span& current_line, + explicit TkInputState(const span_type & current_line, size_t current_pos, size_t whitespace) : current_line_{current_line}, current_pos_{current_pos}, @@ -191,7 +191,7 @@ namespace xo { ///@{ /** remember current input line. Used only to report errors **/ - span current_line_ = span(); + span_type current_line_ = span_type(); /** start of last token within @ref current_line_ **/ size_t tk_start_ = 0; /** input position within @ref current_line_ **/ diff --git a/include/xo/tokenizer2/Tokenizer.hpp b/include/xo/tokenizer2/Tokenizer.hpp index 99005fee..40a98cd9 100644 --- a/include/xo/tokenizer2/Tokenizer.hpp +++ b/include/xo/tokenizer2/Tokenizer.hpp @@ -9,8 +9,9 @@ #include "TkInputState.hpp" #include "span.hpp" #include "scan_result.hpp" -#include "xo/indentlog/scope.hpp" -#include "xo/indentlog/print/ppdetail_atomic.hpp" +#include +#include +#include #include namespace xo { @@ -58,15 +59,24 @@ namespace xo { using CharT = char; using token_type = Token; using error_type = TokenizerError; - using span_type = span; - using input_state_type = TkInputState; + using DCircularBuffer = xo::mm::DCircularBuffer; + using CircularBufferConfig = xo::mm::CircularBufferConfig; + using span_type = xo::mm::span; + //using input_state_type = TkInputState; using result_type = scan_result; public: /** @defgroup tokenizer-ctors tokenizer constructors **/ ///@{ - Tokenizer(bool debug_flag = false); + /** + * @p config gives configuration for circular input buffer + * @p debug_flag enables tokenizer debug output + **/ + Tokenizer(const CircularBufferConfig & config = CircularBufferConfig{.name_ = "tkz-input", + .max_capacity_ = 4*1024, + .max_captured_span_ = 128}, + bool debug_flag = false); ///@} @@ -119,6 +129,11 @@ namespace xo { **/ bool has_prefix() const { return !prefix_.empty(); } + /** buffer contents of input_cstr. + * May throw if buffer space exhausted + **/ + std::pair buffer_input_line(const char * input_cstr, bool eof_flag); + /** scan for next input token, given @p input. * Note: * - tokenizer can consume input (e.g. whitespace) @@ -130,8 +145,7 @@ namespace xo { * * @return {parsed token, consumed span} **/ - scan_result scan(const span_type & input, - bool eof_flag); + scan_result scan(const span_type & input); /** discard current line after error. Just cleans up error-reporting state **/ void discard_current_line(); @@ -142,6 +156,8 @@ namespace xo { /** @defgroup tokenizer-instance-vars tokenizer instance variables **/ ///@{ + /** Buffer input here. vm-aware. uses mmap directly **/ + DCircularBuffer input_buffer_; /** track input state (line#,pos,..) for error messages. * There's an ordering problem here: * 1. input_state_.skip_leading_whitespace() advances @@ -150,7 +166,7 @@ namespace xo { * 3. but neeed newline to end token * Also recall input_state_type needed for reporting errors. **/ - input_state_type input_state_; + TkInputState input_state_; /** Accumulate partial token here. * This will happen if input sent to @ref tokenizer::scan * ends without whitespace such that last available token's diff --git a/include/xo/tokenizer2/TokenizerError.hpp b/include/xo/tokenizer2/TokenizerError.hpp index a7fab3c2..a1cb99ee 100644 --- a/include/xo/tokenizer2/TokenizerError.hpp +++ b/include/xo/tokenizer2/TokenizerError.hpp @@ -20,7 +20,7 @@ namespace xo { class TokenizerError { public: using CharT = char; - using span_type = span; + using span_type = xo::mm::span; public: /** @defgroup tokenizer-error-ctors **/ diff --git a/include/xo/tokenizer2/scan_result.hpp b/include/xo/tokenizer2/scan_result.hpp index 971e4b93..249154f1 100644 --- a/include/xo/tokenizer2/scan_result.hpp +++ b/include/xo/tokenizer2/scan_result.hpp @@ -30,7 +30,7 @@ namespace xo { public: using CharT = char; using token_type = Token; - using span_type = span; + using span_type = xo::mm::span; using error_type = TokenizerError; using input_state_type = TkInputState; diff --git a/include/xo/tokenizer2/span.hpp b/include/xo/tokenizer2/span.hpp deleted file mode 100644 index 8cf7a4a7..00000000 --- a/include/xo/tokenizer2/span.hpp +++ /dev/null @@ -1,291 +0,0 @@ -/** @file span.hpp **/ - -#pragma once - -#include "xo/indentlog/scope.hpp" -#include "xo/indentlog/print/ppdetail_atomic.hpp" -#include -#include -#include - -namespace xo { - namespace scm { - /** @class span compression/span.hpp - * - * @brief A contiguous range of characters, without ownership. - * - * @tparam CharT type for elements referred to by this span. - **/ - template - class span { - public: - /** @defgroup span-type-traits span type traits **/ - ///@{ - - /** typealias for span size (in units of CharT) **/ - using size_type = std::uint64_t; - - ///@} - - public: - /** @defgroup span-ctors span constructors **/ - ///@{ - - /** null span **/ - span() : lo_{nullptr}, hi_{nullptr} {} - - /** Create span for the contiguous memory range [@p lo, @p hi) **/ - span(CharT * lo, CharT * hi) : lo_{lo}, hi_{hi} {} - - /** explicit conversion from span **/ - template - span(const span & other, - std::enable_if_t - && !std::is_same_v> * = nullptr) - : lo_{other.lo()}, hi_{other.hi()} {} - - /** copy ctor (explicit to avoid ambiguity with template ctor) **/ - span(const span & other) = default; - span & operator=(const span & other) = default; - - /** Create a null span (i.e. with null @p lo, @p hi pointers) - * A null span can be concatenated with any other span - * without triggering matching-endpoint asserts. - **/ - static span make_null() { return span(static_cast(nullptr), static_cast(nullptr)); } - - /** @brief create span for C-style string @p cstr **/ - static span from_cstr(const CharT * cstr) { - CharT * lo = cstr; - CharT * hi = cstr ? cstr + strlen(cstr) : nullptr; - - return span(lo, hi); - } - - /** @brief create span from std::string @p str **/ - static span from_string(const std::string& str) { - CharT * lo = &(*str.begin()); - CharT * hi = &(*str.end()); - - return span(lo, hi); - } - - /** @brief concatenate two contiguous spans */ - static span concat(const span & span1, const span & span2) { - if (span1.is_null()) - return span2; - if (span2.is_null()) - return span1; - - if (span1.hi() != span2.lo()) { - scope log(XO_DEBUG(true)); - - log && log(xtag("span1.hi", (void*)span1.hi()), xtag("span2.lo", (void*)span2.lo())); - } - - assert(span1.hi() == span2.lo()); - - CharT * lo = span1.lo(); - CharT * hi = span2.hi(); - - return span(lo, hi); - } - - ///@} - - /** @defgroup span-access-methods **/ - ///@{ - - CharT * lo() const { return lo_; } /* get member span::lo_ */ - CharT * hi() const { return hi_; } /* get member span::hi_ */ - - ///@} - - /** @defgroup span-general-methods **/ - ///@{ - - /** @brief strip prefix until first occurence of '\n', including the newline **/ - void discard_until_newline() { - for (const CharT * p = lo_; p < hi_; ++p) { - if (*p == '\n') { - lo_ = p + 1; - return; - } - } - - lo_ = hi_; - } - - /** Create new span over supplied type, - * with identical (possibly misaligned) endpoints. - * - * @warning - * 1. New span uses exactly the same memory addresses. - * Endpoint pointers may not be aligned. - * 2. Implementation assumes code compiled with - * @code -fno-strict-aliasing @endcode enabled. - * - * @tparam OtherT element type for new span - **/ - template - span - cast() const { return span(reinterpret_cast(lo_), - reinterpret_cast(hi_)); } - - /** @brief create span including the first @p z members of this span. **/ - span prefix(size_type z) const { return span(lo_, lo_ + z); } - - /** @brief create span representing prefix up to (but not including) @p *p - **/ - span prefix_upto(CharT * p) const { - if (p <= hi_) - return span(lo_, p); - else - return span(lo_, hi_); - } - - /** @brief create span with first @p z members of this span removed **/ - span after_prefix(size_type z) const { - if (lo_ + z > hi_) - z = hi_ - lo_; - - return span(lo_ + z, hi_); - } - - /** @brief create span with @p prefix of this span removed **/ - span after_prefix(const span & prefix) const { - if (!prefix.is_null() && (prefix.lo() != lo_)) { - throw std::runtime_error - ("after_prefix: expected prefix of this span"); - } - - return after_prefix(prefix.size()); - } - - /** Create span starting with position @p p. - * Does boundary checking; will return empty span if @p p is outside @c [lo_,hi) - **/ - span suffix_from(CharT * p) const { - if ((lo_ <= p) && (p <= hi_)) - return span(p, hi_); - else - return span(hi_, hi_); - } - - /** true iff this span is null. distinct from empty. **/ - bool is_null() const { return lo_ == nullptr && hi_ == nullptr; } - /** true iff this span is empty (comprises 0 elements). **/ - bool empty() const { return lo_ == hi_; } - /** report the number of elements (of type CharT) in this span. **/ - size_type size() const { return hi_ - lo_; } - - /** increase extent of this spans to include @p x. - * Requires @c hi() == @c x.lo() - **/ - span & operator+=(const span & x) { - if (hi_ == x.lo_) { - hi_ = x.hi_; - } else if (!x.is_null()) { - assert(false); - } - - return *this; - } - - /** print representation for this span on stream @p os **/ - void print(std::ostream & os) const { - os << ""; - } - ///@} - - private: - /** @defgroup span-instance-vars **/ - ///@{ - - /** start of span. - Span comprises memory address between @p lo (inclusive) and @p hi (exclusive) - **/ - CharT * lo_ = nullptr; - - /** @brief end of span. - Span comprises memory address between @p lo (inclusive) and @p hi (exclusive) - **/ - CharT * hi_ = nullptr; - - ///@} - }; /*span*/ - - /** @defgroup span-operators **/ - ///@{ - - /** compare spans for equality. - * Two spans are equal iff both endpoints match exactly. - **/ - template - inline bool - operator==(const span & lhs, const span & rhs) { - return ((lhs.lo() == rhs.lo()) - && (lhs.hi() == rhs.hi())); - } - - /** compare spans for inequality. - * Two spans are unequal if either paired endpoint differs. - **/ - template - inline bool - operator!=(const span & lhs, const span & rhs) { - return ((lhs.lo() != rhs.lo()) - || (lhs.hi() != rhs.hi())); - } - - /** print a summary of @p x on stream @p os. Intended for diagnostics **/ - template - inline std::ostream & - operator<<(std::ostream & os, - const span & x) { - x.print(os); - return os; - } - - ///@} - } /*namespace scm*/ - - namespace print { - template - class printspan_impl { - public: - printspan_impl(xo::scm::span x) : span_{x} {} - - xo::scm::span span_; - }; - - template - printspan_impl printspan(const xo::scm::span& span) { - return printspan_impl(span); - } - - template - inline std::ostream & - operator<< (std::ostream & os, - const printspan_impl & x) - { - for (const CharT * p = x.span_.lo(); p < x.span_.hi(); ++p) - os << *p; - - return os; - } - -#ifndef ppdetail_atomic - template \ - PPDETAIL_ATOMIC_BODY(printspan_impl); - - template \ - PPDETAIL_ATOMIC_BODY(xo::scm::span); -#endif - - } -} /*namespace xo*/ diff --git a/src/tokenizer2/CMakeLists.txt b/src/tokenizer2/CMakeLists.txt index 967535e2..ccf1b551 100644 --- a/src/tokenizer2/CMakeLists.txt +++ b/src/tokenizer2/CMakeLists.txt @@ -10,6 +10,8 @@ set(SELF_SRCS tokentype.cpp) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) +# deps must coordinate with xo-tokenizer/cmake/xo_tokenizer2Config.cmake.in +xo_dependency(${SELF_LIB} xo_arena) xo_dependency(${SELF_LIB} indentlog) # end CMakeLists.txt diff --git a/src/tokenizer2/TkInputState.cpp b/src/tokenizer2/TkInputState.cpp index 30db1dbb..1eca02dd 100644 --- a/src/tokenizer2/TkInputState.cpp +++ b/src/tokenizer2/TkInputState.cpp @@ -84,7 +84,8 @@ namespace xo { // for example including leading whitespace. // See discussion in tokenizer scan() method - scope log(XO_DEBUG(debug_flag_)); + scope log(XO_DEBUG(debug_flag_), + xtag("input", input)); /* look ahead to {end of line, end of input}, whichever comes first */ const CharT * sol = input.lo(); diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index 00ef4eec..888a0c43 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -6,9 +6,13 @@ #include "Tokenizer.hpp" namespace xo { + using std::byte; + namespace scm { - Tokenizer::Tokenizer(bool debug_flag) - : input_state_{debug_flag} + Tokenizer::Tokenizer(const CircularBufferConfig & config, + bool debug_flag) + : input_buffer_{DCircularBuffer::map(config)}, + input_state_{debug_flag} {} void @@ -108,7 +112,7 @@ namespace xo { auto Tokenizer::assemble_token(std::size_t initial_whitespace, const span_type & token_text, - input_state_type * p_input_state) -> result_type + TkInputState * p_input_state) -> result_type { /* literal|pretty|streamlined */ log_config::style = function_style::streamlined; @@ -600,7 +604,7 @@ namespace xo { auto Tokenizer::assemble_final_token(const span_type & token_text, - input_state_type * p_input_state) -> result_type + TkInputState * p_input_state) -> result_type { return assemble_token(0 /*initial_whitespace*/, token_text, @@ -608,12 +612,43 @@ namespace xo { } auto - Tokenizer::scan(const span_type & input, - bool eof_flag) -> result_type + Tokenizer::buffer_input_line(const char * input_cstr, + bool eof_flag) -> std::pair { scope log(XO_DEBUG(input_state_.debug_flag())); - log && log(xtag("input", input)); + log && log(xtag("input", input_cstr)); + + auto buf_input_0 = input_buffer_.input_range().hi(); + + auto remainder = input_buffer_.append + (DCircularBuffer::const_span_type + ((const byte *)input_cstr, + (const byte *)input_cstr + strlen(input_cstr))); + + const char * newline_cstr = "\n"; + auto remainder2 = input_buffer_.append + (DCircularBuffer::const_span_type + ((const byte *)newline_cstr, + (const byte *)newline_cstr + strlen(newline_cstr))); + + if (!remainder.empty() || !remainder2.empty()) { + throw std::runtime_error(tostr("Tokenizer::buffer_line: line too long!", + xtag("remainder.size", remainder.size()))); + } + + auto buf_input_1 = input_buffer_.input_range().hi(); + + span_type input = span_type((const char *)buf_input_0, + (const char *)buf_input_1); + + return this->input_state_.capture_current_line(input, eof_flag); + } + + auto + Tokenizer::scan(const span_type & input) -> result_type + { + scope log(XO_DEBUG(input_state_.debug_flag())); /* - Always at beginning of token when scan() invoked * - scan will not report any portion of line as consumed until it has @@ -625,9 +660,6 @@ namespace xo { * with the same input span multiple times */ - /* automagically no-ops when the same input presented twice */ - this->input_state_.capture_current_line(input, eof_flag); - const CharT * ix = this->input_state_.skip_leading_whitespace(); if(ix == input.hi()) { @@ -789,7 +821,7 @@ namespace xo { * - punctuation */ for (; ix != input.hi(); ++ix) { - if (input_state_type::is_whitespace(*ix) + if (TkInputState::is_whitespace(*ix) || is_1char_punctuation(*ix) || is_2char_punctuation(*ix)) { @@ -829,7 +861,7 @@ namespace xo { return assemble_token(whitespace_z, span_type(tk_start, ix) /*token*/, &(this->input_state_)); - } /*scan*/ + } /*_scan_aux*/ } /*namespace scm*/ } /*namespace xo*/ From a7ed10c16a6011cc59ef0e4ce30da9bbfdfac4a0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 11 Jan 2026 19:10:42 -0500 Subject: [PATCH 070/342] xo-tokenizer: example tokenrepl restored to wokring order Now with CBufferedInput in Tokenizer --- example/tokenrepl/tokenrepl.cpp | 15 ++++++++++++++- src/tokenizer2/Tokenizer.cpp | 14 ++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/example/tokenrepl/tokenrepl.cpp b/example/tokenrepl/tokenrepl.cpp index 0852f028..1cf02244 100644 --- a/example/tokenrepl/tokenrepl.cpp +++ b/example/tokenrepl/tokenrepl.cpp @@ -51,6 +51,8 @@ main() { using xo::scm::operator<<; using xo::mm::CircularBufferConfig; using xo::mm::span; + using xo::scope; + using xo::xtag; using replxx::Replxx; using namespace std; @@ -65,10 +67,13 @@ main() { rx.set_max_history_size(1000); rx.history_load("repl_history.txt"); + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + Tokenizer tkz(CircularBufferConfig{.name_ = "tokenrepl-input", .max_capacity_ = 4*1024, .max_captured_span_ = 128}, - true /*debug_flag*/); + c_debug_flag); const char * input_cstr = nullptr;; @@ -84,9 +89,17 @@ main() { if (input_cstr && *input_cstr) { auto [error, input] = tkz.buffer_input_line(input_cstr, false /*!eof*/); + if (log) { + log(xtag("msg", "buffered input line")); + log(xtag("input", input)); + } + + while (!input.empty()) { auto [tk, consumed, error] = tkz.scan(input); + log && log(xtag("consumed", consumed), xtag("tk", tk)); + if (tk.is_valid()) { cout << tk << endl; } else if (error.is_error()) { diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index 888a0c43..4fa98a97 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -622,15 +622,9 @@ namespace xo { auto buf_input_0 = input_buffer_.input_range().hi(); auto remainder = input_buffer_.append - (DCircularBuffer::const_span_type - ((const byte *)input_cstr, - (const byte *)input_cstr + strlen(input_cstr))); - - const char * newline_cstr = "\n"; + (DCircularBuffer::const_span_type::from_cstr(input_cstr)); auto remainder2 = input_buffer_.append - (DCircularBuffer::const_span_type - ((const byte *)newline_cstr, - (const byte *)newline_cstr + strlen(newline_cstr))); + (DCircularBuffer::const_span_type::from_cstr("\n")); if (!remainder.empty() || !remainder2.empty()) { throw std::runtime_error(tostr("Tokenizer::buffer_line: line too long!", @@ -639,8 +633,8 @@ namespace xo { auto buf_input_1 = input_buffer_.input_range().hi(); - span_type input = span_type((const char *)buf_input_0, - (const char *)buf_input_1); + span_type input = span_type(buf_input_0, + buf_input_1); return this->input_state_.capture_current_line(input, eof_flag); } From 7ee57309b567358edc33759c119006a6dce72d3c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 18 Jan 2026 17:59:46 -0500 Subject: [PATCH 071/342] xo-reader2 scaffold (fomo+arena version of xo-reader/) [WIP] --- CMakeLists.txt | 42 ++++-- DESIGN.md | 12 ++ cmake/xo_reader2Config.cmake.in | 4 +- idl/ISyntaxStateMachine_DExprSeqState.json5 | 13 ++ idl/SyntaxStateMachine.json5 | 56 ++++++++ include/xo/reader2/DExprSeqState.hpp | 76 ++++++++++ include/xo/reader2/ExpressionParser.hpp | 80 +++++++++++ include/xo/reader2/ParserResult.hpp | 52 +++++++ include/xo/reader2/ParserStack.hpp | 47 ++++++ include/xo/reader2/ParserStateMachine.hpp | 115 +++++++++++++++ include/xo/reader2/Reader.hpp | 25 ++++ include/xo/reader2/SyntaxStateMachine.hpp | 22 +++ .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 78 ++++++++++ .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 87 ++++++++++++ .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 64 +++++++++ .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 88 ++++++++++++ .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 85 +++++++++++ include/xo/reader2/syntaxstatetype.hpp | 38 +++++ src/reader2/CMakeLists.txt | 30 ++++ src/reader2/DExprSeqState.cpp | 101 +++++++++++++ src/reader2/ISyntaxStateMachine_Any.cpp | 47 ++++++ .../ISyntaxStateMachine_DExprSeqState.cpp | 39 +++++ src/reader2/ParserResult.cpp | 32 +++++ src/reader2/ParserStack.cpp | 28 ++++ src/reader2/ParserStateMachine.cpp | 134 ++++++++++++++++++ 25 files changed, 1381 insertions(+), 14 deletions(-) create mode 100644 DESIGN.md create mode 100644 idl/ISyntaxStateMachine_DExprSeqState.json5 create mode 100644 idl/SyntaxStateMachine.json5 create mode 100644 include/xo/reader2/DExprSeqState.hpp create mode 100644 include/xo/reader2/ExpressionParser.hpp create mode 100644 include/xo/reader2/ParserResult.hpp create mode 100644 include/xo/reader2/ParserStack.hpp create mode 100644 include/xo/reader2/ParserStateMachine.hpp create mode 100644 include/xo/reader2/Reader.hpp create mode 100644 include/xo/reader2/SyntaxStateMachine.hpp create mode 100644 include/xo/reader2/ssm/ASyntaxStateMachine.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp create mode 100644 include/xo/reader2/ssm/RSyntaxStateMachine.hpp create mode 100644 include/xo/reader2/syntaxstatetype.hpp create mode 100644 src/reader2/CMakeLists.txt create mode 100644 src/reader2/DExprSeqState.cpp create mode 100644 src/reader2/ISyntaxStateMachine_Any.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DExprSeqState.cpp create mode 100644 src/reader2/ParserResult.cpp create mode 100644 src/reader2/ParserStack.cpp create mode 100644 src/reader2/ParserStateMachine.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a8508472..30732417 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,20 +22,36 @@ add_definitions(${PROJECT_CXX_FLAGS}) #add_subdirectory(utest) -# ---------------------------------------------------------------- -# header-only library +# note: manual target; generated code committed to git +xo_add_genfacet( + TARGET xo-reader2-facet-syntaxstatemachine + FACET SyntaxStateMachine + INPUT idl/SyntaxStateMachine.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 + ) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-exprseqstate + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ExprSeqState + INPUT idl/ISyntaxStateMachine_DExprSeqState.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# ---------------------------------------------------------------- +# shared library + +add_subdirectory(src/reader2) + +# ---------------------------------------------------------------- +# cmake helper (for external xo-reader2 users) -set(SELF_LIB xo_reader2) -xo_add_headeronly_library(${SELF_LIB}) -xo_install_library4(${SELF_LIB} ${PROJECT_NAME}Targets) xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) -# ---------------------------------------------------------------- -# input dependencies -# -# NOTE: dependency set here must be kept consistent with -# xo-reader2/cmake/xo_reader2Config.cmake.in - -#xo_headeronly_dependency(${SELF_LIB} xo_flatstring) - # end CMakeLists.txt diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 00000000..69596c44 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,12 @@ +Uses arena allocators for fast+efficient parsing. + +Composition of nested state machines. + +## SyntaxStateMachine + +a state machine dedicated to some particular Schematika syntax. +Examples: if-expression, type declaration, function call + +## DExprSeqState + +top-level expression sequence diff --git a/cmake/xo_reader2Config.cmake.in b/cmake/xo_reader2Config.cmake.in index b5c3cd5c..2b36efff 100644 --- a/cmake/xo_reader2Config.cmake.in +++ b/cmake/xo_reader2Config.cmake.in @@ -6,7 +6,9 @@ include(CMakeFindDependencyMacro) # must coordinate with xo_dependency() calls # in CMakeLists.txt # -#find_dependency(xo_flatstring) +find_dependency(xo_gc) +find_dependency(xo_tokenizer2) +find_dependency(xo_expression2) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") check_required_components("@PROJECT_NAME@") diff --git a/idl/ISyntaxStateMachine_DExprSeqState.json5 b/idl/ISyntaxStateMachine_DExprSeqState.json5 new file mode 100644 index 00000000..0d0cdcac --- /dev/null +++ b/idl/ISyntaxStateMachine_DExprSeqState.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExprSeqState", + using_doxygen: true, + repr: "DExprSeqState", + doc: [ "implement ASyntaxStateMachine for DExprSeqState" ], +} diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 new file mode 100644 index 00000000..0023a16e --- /dev/null +++ b/idl/SyntaxStateMachine.json5 @@ -0,0 +1,56 @@ +{ + mode: "facet", + // includes in ASyntaxStateMachine.hpp + includes: [ + "\"ParserStateMachine.hpp\"", + "\"syntaxstatetype.hpp\"", + "", + ], + // extra includes in SyntaxStateMachine.hpp, if any + user_hpp_includes: [], + namespace1: "xo", + namespace2: "scm", + // text after includes, before ASyntaxStateMachine + pretext: ["// {pretex} here"], + facet: "SyntaxStateMachine", + detail_subdir: "ssm", + brief: "specialized state machine for parsing some particular schematika syntax", + using_doxygen: true, + doc: [ + "Assistant to schematika parser dedicated to particular syntax" + ], + types: [ + // { name: string, doc: [ string ], definition: string }, + ], + const_methods: [ + { + name: "ssm_type", + doc: ["identify a type of syntax state machine"], + return_type: "syntaxstatetype", + args: [], + const: true, + noexcept: true, + attributes: [], + }, + { + name: "get_expect_str", + doc: ["text describing expected/allowed input to this ssm in current state"], + return_type: "std::string_view", + args: [], + const: true, + noexcept: true, + attributes: [], + }, + ], + nonconst_methods: [ + { + name: "on_if_token", + doc: ["update state machine for incoming if-keyword-token @p tk"], + return_type: "void", + args: [ + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, + ], +} diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp new file mode 100644 index 00000000..f1faed86 --- /dev/null +++ b/include/xo/reader2/DExprSeqState.hpp @@ -0,0 +1,76 @@ +/** @file DExprSeqState.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "ParserStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include + +namespace xo { + namespace scm { + enum class exprseqtype { + /** toplevel interactive sequence. + * allows: rvalue expressions + **/ + toplevel_interactive, + /** toplevel non-interactive sequence. + * allows: + **/ + toplevel_batch, + /** counts number of valid enums **/ + N + }; + + /** @class DExprSeqState + * @brief state machine for parsing a sequence of expression + * + * Similar to exprseq_xs in xo-expresion + **/ + class DExprSeqState { + public: + using AAllocator = xo::mm::AAllocator; + + public: + explicit DExprSeqState(exprseqtype ty); + + /** start interactive top-level session **/ + static void start_interactive(obj mm, + ParserStateMachine * p_psm); + /** start non-interactive top-level session **/ + static void start_batch(obj mm, + ParserStateMachine * p_psm); + + public: + /** @defgroup scm-exprseq-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** text describing expected/allowed input to this ssm in current state. + * Intended to drive error mesages + **/ + std::string_view get_expect_str() const noexcept; + + /** update state for this syntax on incoming token @p tk, + * overall parser state in @p p_psm + **/ + void on_if_token(const Token & tk, ParserStateMachine * p_psm); + + ///@} + + private: + /** sequence type. accept rvalue expressions when + * this is toplevel_interactive. + * Always accept definitions and declarations. + **/ + exprseqtype seqtype_; + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExprSeqState.hpp */ diff --git a/include/xo/reader2/ExpressionParser.hpp b/include/xo/reader2/ExpressionParser.hpp new file mode 100644 index 00000000..e59464b5 --- /dev/null +++ b/include/xo/reader2/ExpressionParser.hpp @@ -0,0 +1,80 @@ +/** @file ExpressionParser.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#include "ExprState.hpp" +#include +#include +#include + +namespace xo { + namespace scm { + /** @class ExpressionParser + * @brief Assemble Schematika expressions from token sequences + * + * Parser represents Each partially assembled expression by + * an ExprState object. + * Expreesions form a tree: + * each expression belongs to at most one parent. + * + **/ + class ExpressionParser { + public: + void push_exprstate(obj xstate); + + private: + /* TODO: + * ASymbolTable + * DLocalSymtab + * DGlobalSymtab + * + * Will also need + * DVariable + * DLambda + * + * For DGlobalSymtab perhaps use DArenaHashMap. + * May also want to use DArenaHashMap+DArena to intern strings + * + * Also: + * TypeUnifier + */ + + /** Arena for internal parsing stack. + * Must be owned exclusively because destructively + * modified as parser completes parsing of each sub-expression + * + * Contents will be a stack of ExprState instances + **/ + DArena parser_alloc_; + +#ifdef NOT_YET + /** Arena for internal environment stack. + * This represents just nesting for environments. + * Details for each frame survive parsing and are + * stored in @ref expr_alloc_. + * Maybe that means we don't need env_alloc_ + **/ + DArena env_alloc_; +#endif + + /** Allocator for parsed expressions. + * Information available during subsequent execution + * (whether compiling or interpreting) must be stored here. + * + * Also use this allocator for error messages arising + * during parsing + * + * Memory use patterns for executions are not predictable, + * and require garbage collection, e.g. DX1Collector. + * + * May alternatively be able to use DArena in a compile-only + * scenario, where top-level Expressions can be discarded + * once compiled. + **/ + obj expr_alloc_; + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ExpressionParser.hpp */ diff --git a/include/xo/reader2/ParserResult.hpp b/include/xo/reader2/ParserResult.hpp new file mode 100644 index 00000000..3aadbdae --- /dev/null +++ b/include/xo/reader2/ParserResult.hpp @@ -0,0 +1,52 @@ +/** @file ParserResult.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include +#include +#include + +namespace xo { + namespace scm { + enum class parser_result_type { + /** no result yet (no input or incomplete expression) **/ + none, + /** emit expression **/ + expression, + /** emit parsing error **/ + error, + N + }; + + class ParserResult { + public: + ParserResult() = default; + ParserResult(parser_result_type type, + obj expr, + std::string_view error_src_fn, + const DString * error_description); + + /** create ParserResult for a parsing error. + * Reporting detailed message @p errmsg + * from syntax state machine @p ssm + **/ + static ParserResult error(std::string_view ssm, + const DString * errmsg); + + parser_result_type result_type() const { return result_type_; } + obj result_expr() const { return result_expr_; } + const DString * error_description() const { return error_description_; } + + private: + parser_result_type result_type_ = parser_result_type::none; + obj result_expr_; + std::string_view error_src_fn_; + const DString * error_description_ = nullptr; + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ParserResult.hpp */ diff --git a/include/xo/reader2/ParserStack.hpp b/include/xo/reader2/ParserStack.hpp new file mode 100644 index 00000000..424be42b --- /dev/null +++ b/include/xo/reader2/ParserStack.hpp @@ -0,0 +1,47 @@ +/** @file ParserStack.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include +#include + +namespace xo { + namespace scm { + + /** @brief A stack of expression state machines + * + * Each state machine is dedicated to a particular syntax instance. + * The innermost machine is in xsm; machines for surrounding expressions + * are in progressively removed frames reached via parent links. + **/ + class ParserStack { + public: + using AAllocator = xo::mm::AAllocator; + + public: + ParserStack(obj ssm, ParserStack * parent); + + /** create new top of stack for syntax @p ssm, using memory from @p mm. + * previous stack given by @p parent + **/ + ParserStack * push(obj mm, + obj ssm); + + obj top() const noexcept { return ssm_; } + ParserStack * parent() const noexcept { return parent_; } + + private: + /** top of parsing stack: always non-null **/ + obj ssm_; + /** remainder of parsing stack excluding top **/ + ParserStack * parent_ = nullptr; + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ParserStack.hpp */ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp new file mode 100644 index 00000000..339fa029 --- /dev/null +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -0,0 +1,115 @@ +/** @file ParserStateMachine.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "ParserResult.hpp" +#include +#include +#include + +namespace xo { + namespace scm { + // defined in ssm/ASyntaxStateMachine.hpp, but + // including here would create include cycle + // + class ASyntaxStateMachine; + + // note: load-bearing to forward-declare ParserStack, + // because ASyntaxStateMachine.hpp includes ParserStateMachine.hpp; + // before obj is defined. + class ParserStack; + + /** @brief State machine embodying Schematika parser + **/ + class ParserStateMachine { + public: + using AAllocator = xo::mm::AAllocator; + using ArenaConfig = xo::mm::ArenaConfig; + using DArena = xo::mm::DArena; + + public: + ParserStateMachine(const ArenaConfig & config); + + /** @defgroup scm-parserstatemachine-bookkeeping bookkeeping methods **/ + ///@{ + + /** push syntax @p ssm onto @ref stack_ **/ + void push_ssm(obj ssm); + + ///@} + + /** @defgroup scm-parserstatemachine-inputmethods input methods **/ + ///@{ + + /** update state to respond to input token @p tk. + * record output (if any) in @ref result_ + **/ + void on_token(const Token & tk); + + /** update state for incoming if-token @p tk **/ + void on_if_token(const Token & tk); + + ///@} + + /** @defgroup scm-parserstatemachine-error-entrypoints error entry points **/ + ///@{ + + /** capture error message @p errmsg from @p ssm_name, + * as current state machine output. + * + * @p errmsg will have been allocated from the @p expr_alloc_ allocator + **/ + void capture_error(std::string_view ssm_name, + const DString * errmsg); + + /** report illegal input from syntax state machine @p ssm_name + * recognized on input token @p tk. @p expect_str describes + * expected input in that state + **/ + void illegal_input_on_token(std::string_view ssm_name, + const Token & tk, + std::string_view expect_str); + + ///@} + + private: + /** Arena for internal parsing stack. + * Must be owned exclusively because destructively + * modified as parser completes parsing of each sub-expression + * + * Contents will be a stack of ExprState instances + **/ + DArena parser_alloc_; + + /** parser stack. Memory from @ref parser_alloc_ **/ + ParserStack * stack_ = nullptr; + + /** Allocator for parsed expressions. + * Information available during subsequent execution + * (whether compiling or interpreting) must be stored here. + * + * Also use this allocator for error messages arising + * during parsing + * + * Memory use patterns for executions are not predictable, + * and benefit from garbage collection, e.g. DX1Collector. + * + * May alternatively be able to use DArena in a compile-only + * scenario, where top-level Expressions can be discarded + * once compiled. + **/ + obj expr_alloc_; + + /** current output from parser **/ + ParserResult result_; + + /** true to enable debug output **/ + bool debug_flag_ = false; + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ParserStateMachine.hpp */ diff --git a/include/xo/reader2/Reader.hpp b/include/xo/reader2/Reader.hpp new file mode 100644 index 00000000..9ae65d61 --- /dev/null +++ b/include/xo/reader2/Reader.hpp @@ -0,0 +1,25 @@ +/** @file Reader.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include + +namespace xo { + namespace scm { + /** @class Reader + * @brief Assemble Schematika expressions from lexical tokens + **/ + class Reader { + public: + private: + /** tokenizer: assembles Schematika tokens from text **/ + Tokenizer tokenizer_; + + /** parser: assemble Schematika expressions from token sequences **/ + ExpressionParser parser_; + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end Reader.hpp */ diff --git a/include/xo/reader2/SyntaxStateMachine.hpp b/include/xo/reader2/SyntaxStateMachine.hpp new file mode 100644 index 00000000..deda9e1d --- /dev/null +++ b/include/xo/reader2/SyntaxStateMachine.hpp @@ -0,0 +1,22 @@ +/** @file SyntaxStateMachine.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/SyntaxStateMachine.json5] + * 2. jinja2 template for facet .hpp file: + * [facet.hpp.j2] + * 3. idl for facet methods + * [idl/SyntaxStateMachine.json5] + **/ + +#pragma once + +#include "ssm/ASyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Any.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "ssm/RSyntaxStateMachine.hpp" + + +/* end SyntaxStateMachine.hpp */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp new file mode 100644 index 00000000..a519b246 --- /dev/null +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -0,0 +1,78 @@ +/** @file ASyntaxStateMachine.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/SyntaxStateMachine.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [abstract_facet.hpp.j2] + * 3. idl for facet methods + * [idl/SyntaxStateMachine.json5] + **/ + +#pragma once + +// includes (via {facet_includes}) +#include "ParserStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include +#include +#include +#include + +// {pretex} here + +namespace xo { +namespace scm { + +using Copaque = const void *; +using Opaque = void *; + +/** +Assistant to schematika parser dedicated to particular syntax +**/ +class ASyntaxStateMachine { +public: + /** @defgroup scm-syntaxstatemachine-type-traits **/ + ///@{ + // types + /** integer identifying a type **/ + using typeseq = xo::facet::typeseq; + using Copaque = const void *; + using Opaque = void *; + ///@} + + /** @defgroup scm-syntaxstatemachine-methods **/ + ///@{ + // const methods + /** RTTI: unique id# for actual runtime data representation **/ + virtual typeseq _typeseq() const noexcept = 0; + /** identify a type of syntax state machine **/ + virtual syntaxstatetype ssm_type(Copaque data) const noexcept = 0; + /** text describing expected/allowed input to this ssm in current state **/ + virtual std::string_view get_expect_str(Copaque data) const noexcept = 0; + + // nonconst methods + /** update state machine for incoming if-keyword-token @p tk **/ + virtual void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; + ///@} +}; /*ASyntaxStateMachine*/ + +/** Implementation ISyntaxStateMachine_DRepr of ASyntaxStateMachine for state DRepr + * should provide a specialization: + * + * template <> + * struct xo::facet::FacetImplementation { + * using Impltype = ISyntaxStateMachine_DRepr; + * }; + * + * then ISyntaxStateMachine_ImplType --> ISyntaxStateMachine_DRepr + **/ +template +using ISyntaxStateMachine_ImplType = xo::facet::FacetImplType; + +} /*namespace scm*/ +} /*namespace xo*/ + +/* ASyntaxStateMachine.hpp */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp new file mode 100644 index 00000000..2d5dd0c3 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -0,0 +1,87 @@ +/** @file ISyntaxStateMachine_Any.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/SyntaxStateMachine.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/SyntaxStateMachine.json5] + **/ + +#pragma once + +#include "ASyntaxStateMachine.hpp" +#include + +namespace xo { namespace scm { class ISyntaxStateMachine_Any; } } + +namespace xo { +namespace facet { + +template <> +struct FacetImplementation +{ + using ImplType = xo::scm::ISyntaxStateMachine_Any; +}; + +} +} + +namespace xo { +namespace scm { + + /** @class ISyntaxStateMachine_Any + * @brief ASyntaxStateMachine implementation for empty variant instance + **/ + class ISyntaxStateMachine_Any : public ASyntaxStateMachine { + public: + /** @defgroup scm-syntaxstatemachine-any-type-traits **/ + ///@{ + + /** integer identifying a type **/ + using typeseq = xo::facet::typeseq; + + ///@} + /** @defgroup scm-syntaxstatemachine-any-methods **/ + ///@{ + + const ASyntaxStateMachine * iface() const { return std::launder(this); } + + // from ASyntaxStateMachine + + // const methods + typeseq _typeseq() const noexcept override { return s_typeseq; } + [[noreturn]] syntaxstatetype ssm_type(Copaque) const noexcept override { _fatal(); } + [[noreturn]] std::string_view get_expect_str(Copaque) const noexcept override { _fatal(); } + + // nonconst methods + [[noreturn]] void on_if_token(Opaque, const Token &, ParserStateMachine *) override; + + ///@} + + private: + /** @defgraoup scm-syntaxstatemachine-any-private-methods **/ + ///@{ + + [[noreturn]] static void _fatal(); + + ///@} + + public: + /** @defgroup scm-syntaxstatemachine-any-member-vars **/ + ///@{ + + static typeseq s_typeseq; + static bool _valid; + + ///@} + }; + +} /*namespace scm */ +} /*namespace xo */ + +/* ISyntaxStateMachine_Any.hpp */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp new file mode 100644 index 00000000..b1d889b1 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -0,0 +1,64 @@ +/** @file ISyntaxStateMachine_DExprSeqState.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExprSeqState.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExprSeqState.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExprSeqState.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExprSeqState; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExprSeqState + **/ + class ISyntaxStateMachine_DExprSeqState { + public: + /** @defgroup scm-syntaxstatemachine-dexprseqstate-type-traits **/ + ///@{ + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexprseqstate-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExprSeqState & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExprSeqState & self) noexcept; + + // non-const methods + /** update state machine for incoming if-keyword-token @p tk **/ + static void on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp new file mode 100644 index 00000000..c3aec83e --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -0,0 +1,88 @@ +/** @file ISyntaxStateMachine_Xfer.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/SyntaxStateMachine.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/SyntaxStateMachine.json5] + **/ + +#pragma once + +#include "ParserStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include + +namespace xo { +namespace scm { + /** @class ISyntaxStateMachine_Xfer + **/ + template + class ISyntaxStateMachine_Xfer : public ASyntaxStateMachine { + public: + /** @defgroup scm-syntaxstatemachine-xfer-type-traits **/ + ///@{ + /** actual implementation (not generated; often delegates to DRepr) **/ + using Impl = ISyntaxStateMachine_DRepr; + /** integer identifying a type **/ + using typeseq = ASyntaxStateMachine::typeseq; + ///@} + + /** @defgroup scm-syntaxstatemachine-xfer-methods **/ + ///@{ + + static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; } + static DRepr & _dcast(Opaque d) { return *(DRepr *)d; } + + // from ASyntaxStateMachine + + // const methods + typeseq _typeseq() const noexcept override { return s_typeseq; } + syntaxstatetype ssm_type(Copaque data) const noexcept override { + return I::ssm_type(_dcast(data)); + } + std::string_view get_expect_str(Copaque data) const noexcept override { + return I::get_expect_str(_dcast(data)); + } + + // non-const methods + void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_if_token(_dcast(data), tk, p_psm); + } + + ///@} + + private: + using I = Impl; + + public: + /** @defgroup scm-syntaxstatemachine-xfer-member-vars **/ + ///@{ + + /** typeseq for template parameter DRepr **/ + static typeseq s_typeseq; + /** true iff satisfies facet implementation **/ + static bool _valid; + + ///@} + }; + + template + xo::facet::typeseq + ISyntaxStateMachine_Xfer::s_typeseq + = xo::facet::typeseq::id(); + + template + bool + ISyntaxStateMachine_Xfer::_valid + = xo::facet::valid_facet_implementation(); + +} /*namespace scm */ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_Xfer.hpp */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp new file mode 100644 index 00000000..5f920614 --- /dev/null +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -0,0 +1,85 @@ +/** @file RSyntaxStateMachine.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/SyntaxStateMachine.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/SyntaxStateMachine.json5] + **/ + +#pragma once + +#include "ASyntaxStateMachine.hpp" + +namespace xo { +namespace scm { + +/** @class RSyntaxStateMachine + **/ +template +class RSyntaxStateMachine : public Object { +private: + using O = Object; + +public: + /** @defgroup scm-syntaxstatemachine-router-type-traits **/ + ///@{ + using ObjectType = Object; + using DataPtr = Object::DataPtr; + using typeseq = xo::reflect::typeseq; + ///@} + + /** @defgroup scm-syntaxstatemachine-router-ctors **/ + ///@{ + RSyntaxStateMachine() {} + RSyntaxStateMachine(Object::DataPtr data) : Object{std::move(data)} {} + RSyntaxStateMachine(const ASyntaxStateMachine * iface, void * data) + requires std::is_same_v + : Object(iface, data) {} + + ///@} + /** @defgroup scm-syntaxstatemachine-router-methods **/ + ///@{ + + // const methods + typeseq _typeseq() const noexcept { return O::iface()->_typeseq(); } + syntaxstatetype ssm_type() const noexcept { + return O::iface()->ssm_type(O::data()); + } + std::string_view get_expect_str() const noexcept { + return O::iface()->get_expect_str(O::data()); + } + + // non-const methods (still const in router!) + void on_if_token(const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_if_token(O::data(), tk, p_psm); + } + + ///@} + /** @defgroup scm-syntaxstatemachine-member-vars **/ + ///@{ + + static bool _valid; + + ///@} +}; + +template +bool +RSyntaxStateMachine::_valid = xo::facet::valid_object_router(); + +} /*namespace scm*/ +} /*namespace xo*/ + +namespace xo { namespace facet { + template + struct RoutingFor { + using RoutingType = xo::scm::RSyntaxStateMachine; + }; +} } + +/* end RSyntaxStateMachine.hpp */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp new file mode 100644 index 00000000..913cd118 --- /dev/null +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -0,0 +1,38 @@ +/** @file syntaxstatetype.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include + +namespace xo { + namespace scm { + /** @enum syntaxstatemachine + * @brief Label a specialized parsing state machine + * + * Label for a schematika syntax state machine + * dedicated to some particular piece of syntax + **/ + enum class syntaxstatetype { + invalid = -1, + + /** toplevel of some translation unit. See @ref DExprSeqState **/ + expect_toplevel_expression_sequence, + + /** comes lasts, counts number of valid enums **/ + N + }; + + const char * syntaxstatetype_descr(syntaxstatetype x); + + inline std::ostream & + operator<< (std::ostream & os, syntaxstatetype x) { + os << syntaxstatetype_descr(x); + return os; + } + } +} /*namespace xo*/ + +/* end syntaxstatetype.hpp */ diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt new file mode 100644 index 00000000..e8bfb1d7 --- /dev/null +++ b/src/reader2/CMakeLists.txt @@ -0,0 +1,30 @@ +# reader2/CMakeLists.txt + +set(SELF_LIB xo_reader2) +set(SELF_SRCS + #init_reader2.cpp + + ParserStateMachine.cpp + ParserStack.cpp + ParserResult.cpp + + ISyntaxStateMachine_Any.cpp + + DExprSeqState.cpp + ISyntaxStateMachine_DExprSeqState.cpp + + #reader2_register_facets.cpp + #reader2_register_types.cpp + ) + +xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) +# note: deps here must also appear in cmake/xo_expression2Config.cmake.in +xo_dependency(${SELF_LIB} xo_gc) +xo_dependency(${SELF_LIB} xo_tokenizer2) +xo_dependency(${SELF_LIB} xo_expression2) +#xo_dependency(${SELF_LIB} reflect) +#xo_dependency(${SELF_LIB} xo_object2) +#xo_dependency(${SELF_LIB} xo_printable2) +#xo_dependency(${SELF_LIB} xo_flatstring) +#xo_dependency(${SELF_LIB} subsys) +#xo_dependency(${SELF_LIB} indentlog) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp new file mode 100644 index 00000000..7d2368e5 --- /dev/null +++ b/src/reader2/DExprSeqState.cpp @@ -0,0 +1,101 @@ +/** @file DExprSeqState.cpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DExprSeqState.hpp" +#include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" + +namespace xo { + using xo::mm::AAllocator; + using xo::facet::with_facet; + using xo::reflect::typeseq; + + namespace scm { + DExprSeqState::DExprSeqState(exprseqtype ty) : seqtype_{ty} + {} + + namespace { + obj + make_exprseq_ssm(obj mm, + exprseqtype seqtype) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DExprSeqState)); + + DExprSeqState * ssm = new (mem) DExprSeqState(seqtype); + + return with_facet::mkobj(ssm); + } + } + + void + DExprSeqState::start_interactive(obj mm, + ParserStateMachine * p_psm) + { + + + p_psm->push_ssm(make_exprseq_ssm(mm, + exprseqtype::toplevel_interactive)); + } + + void + DExprSeqState::start_batch(obj mm, + ParserStateMachine * p_psm) + { + (void)mm; + (void)p_psm; +#ifdef NOT_YET + p_psm->push_ssm(make_exprseq_ssm(mm, + exprseqtype::toplevel_batch)); +#endif + } + + // SyntaxStateMachine facet methods + + syntaxstatetype + DExprSeqState::ssm_type() const noexcept + { + return syntaxstatetype::expect_toplevel_expression_sequence; + } + + std::string_view + DExprSeqState::get_expect_str() const noexcept + { + // TODO: provisional. Will expand as more syntax implemented + + switch (seqtype_) { + case exprseqtype::toplevel_interactive: + return "def|expression|..."; + case exprseqtype::toplevel_batch: + return "def|..."; + case exprseqtype::N: + break; + } + + assert(false); + return "impossible-DExprSeqState::get_expr_str"; + } + + void + DExprSeqState::on_if_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (seqtype_) { + case exprseqtype::toplevel_interactive: + assert(false); // DfElseState::start(p_psm); + break; + case exprseqtype::toplevel_batch: + p_psm->illegal_input_on_token("DExprSeqState::on_if_token", + tk, + this->get_expect_str()); + break; + case exprseqtype::N: + assert(false); // unreachable + break; + } + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExprSeqState.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp new file mode 100644 index 00000000..8c4c0b42 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -0,0 +1,47 @@ +/** @file ISyntaxStateMachine_Any.cpp + * + **/ + +#include "ssm/ISyntaxStateMachine_Any.hpp" +#include + +namespace xo { +namespace scm { + +using xo::facet::DVariantPlaceholder; +using xo::facet::typeseq; +using xo::facet::valid_facet_implementation; + +void +ISyntaxStateMachine_Any::_fatal() +{ + /* control here on uninitialized IAllocator_Any. + * Initialized instance will have specific implementation type + */ + std::cerr << "fatal" + << ": attempt to call uninitialized" + << " ISyntaxStateMachine_Any method" + << std::endl; + std::terminate(); +} + +typeseq +ISyntaxStateMachine_Any::s_typeseq = typeseq::id(); + +bool +ISyntaxStateMachine_Any::_valid + = valid_facet_implementation(); + +// nonconst methods + +auto +ISyntaxStateMachine_Any::on_if_token(Opaque, const Token &, ParserStateMachine *) -> void +{ + _fatal(); +} + + +} /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_Any.cpp */ \ No newline at end of file diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp new file mode 100644 index 00000000..87f4f2d8 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -0,0 +1,39 @@ +/** @file ISyntaxStateMachine_DExprSeqState.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExprSeqState.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExprSeqState.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExprSeqState::ssm_type(const DExprSeqState & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExprSeqState::get_expect_str(const DExprSeqState & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExprSeqState::on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_if_token(tk, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExprSeqState.cpp */ \ No newline at end of file diff --git a/src/reader2/ParserResult.cpp b/src/reader2/ParserResult.cpp new file mode 100644 index 00000000..28553228 --- /dev/null +++ b/src/reader2/ParserResult.cpp @@ -0,0 +1,32 @@ +/** @file ParserResult.cpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#include "ParserResult.hpp" + +namespace xo { + namespace scm { + ParserResult::ParserResult(parser_result_type type, + obj expr, + std::string_view error_src_fn, + const DString * error_description) + : result_type_{type}, + result_expr_{expr}, + error_src_fn_{error_src_fn}, + error_description_{error_description} + {} + + ParserResult + ParserResult::error(std::string_view ssm_name, + const DString * errmsg) + { + return ParserResult(parser_result_type::error, + obj(), + ssm_name, + errmsg); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ParserResult.cpp */ diff --git a/src/reader2/ParserStack.cpp b/src/reader2/ParserStack.cpp new file mode 100644 index 00000000..7e8f6b1b --- /dev/null +++ b/src/reader2/ParserStack.cpp @@ -0,0 +1,28 @@ +/** @file ParserStack.cpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#include "ParserStack.hpp" +#include "SyntaxStateMachine.hpp" + +namespace xo { + using xo::facet::typeseq; + + namespace scm { + + ParserStack * + ParserStack::push(obj mm, + obj ssm) + + { + void * mem = mm.alloc(typeseq::id(), + sizeof(ParserStack)); + + return new (mem) ParserStack(ssm, parent_); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ParserStack.cpp */ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp new file mode 100644 index 00000000..a691bb57 --- /dev/null +++ b/src/reader2/ParserStateMachine.cpp @@ -0,0 +1,134 @@ +/** @file ParserStateMachine.cpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#include "ParserStateMachine.hpp" +#include "ParserStack.hpp" +#include "SyntaxStateMachine.hpp" +#include +#include +#include +#include +#include + +namespace xo { + using xo::facet::with_facet; + + namespace scm { + void + ParserStateMachine::push_ssm(obj ssm) + { + scope log(XO_DEBUG(debug_flag_)); + + // note: using parser_alloc_ for parser stack, since stacklike behavior + + auto alloc = with_facet::mkobj(&parser_alloc_); + + this->stack_ = stack_->push(alloc, ssm); + } + + void + ParserStateMachine::on_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + if (!stack_) { + // parsing stack should always have toplevel expression sequence + throw std::runtime_error(tostr("unexpected empty parsing stack", + xtag("token", tk), + xtag("help", "do it the same. but better!") + )); + } + + switch (tk.tk_type()) { + case tokentype::tk_if: + this->on_if_token(tk); + break; + + + // all the not-yet handled cases + case tokentype::tk_invalid: + case tokentype::tk_bool: + case tokentype::tk_i64: + case tokentype::tk_f64: + case tokentype::tk_string: + case tokentype::tk_symbol: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_colon: + case tokentype::tk_doublecolon: + case tokentype::tk_semicolon: + case tokentype::tk_singleassign: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_def: + case tokentype::tk_lambda: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + throw std::runtime_error(tostr("NOT IMPLEMENTED", + xtag("token", tk))); + + } + } + + void + ParserStateMachine::on_if_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + stack_->top().on_if_token(tk, this); + } + + void + ParserStateMachine::capture_error(std::string_view ssm_name, + const DString * errmsg) + { + this->result_ = ParserResult::error(ssm_name, errmsg); + } + + void + ParserStateMachine::illegal_input_on_token(std::string_view ssm_name, + const Token & tk, + std::string_view expect_str) + { + // TODO: + // - want to write error message using DArena + // - need something like log_streambuf and/or tostr() that's arena-aware + + auto errmsg_string = tostr("Unexpected token for parsing state", + xtag("token", tk), + xtag("expecting", expect_str), + xtag("ssm", ssm_name), + xtag("via", "ParserStateMachine::illegal_input_on_token")); + + auto errmsg = DString::from_view(expr_alloc_, + std::string_view(errmsg_string)); + + this->capture_error(ssm_name, errmsg); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ParserStateMachine.cpp */ From f25d1fb7384f60eddd416898a47f775ca4dd21bd Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 18 Jan 2026 17:59:46 -0500 Subject: [PATCH 072/342] xo-reader2 scaffold (fomo+arena version of xo-reader/) [WIP] --- include/xo/tokenizer2/tokentype.hpp | 4 ++-- src/tokenizer2/tokentype.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xo/tokenizer2/tokentype.hpp b/include/xo/tokenizer2/tokentype.hpp index eeeb7dd0..91cb3622 100644 --- a/include/xo/tokenizer2/tokentype.hpp +++ b/include/xo/tokenizer2/tokentype.hpp @@ -164,8 +164,8 @@ namespace xo { /** keyword @c 'end' **/ tk_end, - /** counts number of entries **/ - n_tokentype + /** comes last, counts number of entries **/ + N }; /*tokentype*/ /** String representation for enum value. diff --git a/src/tokenizer2/tokentype.cpp b/src/tokenizer2/tokentype.cpp index 33d683de..40c2dbfb 100644 --- a/src/tokenizer2/tokentype.cpp +++ b/src/tokenizer2/tokentype.cpp @@ -60,7 +60,7 @@ namespace xo { CASE(tk_end); case tokentype::tk_invalid: - case tokentype::n_tokentype: + case tokentype::N: return "?tokentype"; } From 3198e302346914b3b49ef46d241e0a41d1ded67c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 18 Jan 2026 18:57:33 -0500 Subject: [PATCH 073/342] xo-reader2: + regression2_register_facets() --- .../xo/reader2/reader2_register_facets.hpp | 15 +++++++++ src/reader2/CMakeLists.txt | 2 +- src/reader2/ParserStack.cpp | 4 +++ src/reader2/reader2_register_facets.cpp | 33 +++++++++++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 include/xo/reader2/reader2_register_facets.hpp create mode 100644 src/reader2/reader2_register_facets.cpp diff --git a/include/xo/reader2/reader2_register_facets.hpp b/include/xo/reader2/reader2_register_facets.hpp new file mode 100644 index 00000000..6e606e40 --- /dev/null +++ b/include/xo/reader2/reader2_register_facets.hpp @@ -0,0 +1,15 @@ +/** @file reader2_register_facets.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +namespace xo { + namespace scm { + /** Register reader2 (facet,impl) combinations with FacetRegistry **/ + bool reader2_register_facets(); + } +} + +/* end reader2_register_facets.hpp */ diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index e8bfb1d7..ee214f56 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -13,7 +13,7 @@ set(SELF_SRCS DExprSeqState.cpp ISyntaxStateMachine_DExprSeqState.cpp - #reader2_register_facets.cpp + reader2_register_facets.cpp #reader2_register_types.cpp ) diff --git a/src/reader2/ParserStack.cpp b/src/reader2/ParserStack.cpp index 7e8f6b1b..3648cb4d 100644 --- a/src/reader2/ParserStack.cpp +++ b/src/reader2/ParserStack.cpp @@ -10,6 +10,10 @@ namespace xo { using xo::facet::typeseq; namespace scm { + ParserStack::ParserStack(obj ssm, + ParserStack * parent) + : ssm_{ssm}, parent_{parent} + {} ParserStack * ParserStack::push(obj mm, diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp new file mode 100644 index 00000000..e5b1d157 --- /dev/null +++ b/src/reader2/reader2_register_facets.cpp @@ -0,0 +1,33 @@ +/** @file reader2_register_facets.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "reader2_register_facets.hpp" + +#include + +#include +#include +#include + +namespace xo { + using xo::facet::FacetRegistry; + using xo::facet::typeseq; + + namespace scm { + bool + reader2_register_facets() + { + scope log(XO_DEBUG(true)); + + FacetRegistry::register_impl(); + + log && log(xtag("DExprSeqState.tseq", typeseq::id())); + + return true; + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end reader2_register_facets.cpp */ From a96196b365800ea0cd614c6875d9ccf7e193ec0f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 18 Jan 2026 19:09:48 -0500 Subject: [PATCH 074/342] xo-reader2: + init_reader2 + reader2_register_types --- include/xo/reader2/init_reader2.hpp | 21 ++++++++++ include/xo/reader2/reader2_register_types.hpp | 17 ++++++++ src/reader2/CMakeLists.txt | 6 +-- src/reader2/init_reader2.cpp | 41 +++++++++++++++++++ src/reader2/reader2_register_types.cpp | 29 +++++++++++++ 5 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 include/xo/reader2/init_reader2.hpp create mode 100644 include/xo/reader2/reader2_register_types.hpp create mode 100644 src/reader2/init_reader2.cpp create mode 100644 src/reader2/reader2_register_types.cpp diff --git a/include/xo/reader2/init_reader2.hpp b/include/xo/reader2/init_reader2.hpp new file mode 100644 index 00000000..e0bf18b4 --- /dev/null +++ b/include/xo/reader2/init_reader2.hpp @@ -0,0 +1,21 @@ +/** @file init_reader2.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include + +namespace xo { + /* tag to represent the xo-reader2/ subsystem within ordered initialization */ + enum S_reader2_tag {}; + + template <> + struct InitSubsys { + static void init(); + static InitEvidence require(); + }; +} /*namespace xo*/ + +/* end init_reader2.hpp */ diff --git a/include/xo/reader2/reader2_register_types.hpp b/include/xo/reader2/reader2_register_types.hpp new file mode 100644 index 00000000..a7e6c0e1 --- /dev/null +++ b/include/xo/reader2/reader2_register_types.hpp @@ -0,0 +1,17 @@ +/** @file reader2_register_types.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include + +namespace xo { + namespace scm { + /** Register reader2 gc-aware types with collector **/ + bool reader2_register_types(obj gc); + } +} + +/* end reader2_register_types.hpp */ diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index ee214f56..f6fc817f 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -2,7 +2,7 @@ set(SELF_LIB xo_reader2) set(SELF_SRCS - #init_reader2.cpp + init_reader2.cpp ParserStateMachine.cpp ParserStack.cpp @@ -14,7 +14,7 @@ set(SELF_SRCS ISyntaxStateMachine_DExprSeqState.cpp reader2_register_facets.cpp - #reader2_register_types.cpp + reader2_register_types.cpp ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) @@ -26,5 +26,5 @@ xo_dependency(${SELF_LIB} xo_expression2) #xo_dependency(${SELF_LIB} xo_object2) #xo_dependency(${SELF_LIB} xo_printable2) #xo_dependency(${SELF_LIB} xo_flatstring) -#xo_dependency(${SELF_LIB} subsys) +xo_dependency(${SELF_LIB} subsys) #xo_dependency(${SELF_LIB} indentlog) diff --git a/src/reader2/init_reader2.cpp b/src/reader2/init_reader2.cpp new file mode 100644 index 00000000..aa7e291c --- /dev/null +++ b/src/reader2/init_reader2.cpp @@ -0,0 +1,41 @@ +/** @file init_reader2.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "init_reader2.hpp" +#include "reader2_register_facets.hpp" +#include "reader2_register_types.hpp" + +#include +#include + +namespace xo { + using xo::scm::reader2_register_facets; + using xo::scm::reader2_register_types; + using xo::mm::CollectorTypeRegistry; + + void + InitSubsys::init() + { + reader2_register_facets(); + + CollectorTypeRegistry::instance().register_types(&reader2_register_types); + } + + InitEvidence + InitSubsys::require() + { + InitEvidence retval; + + /* direct subsystem deps for xo-reader2/ */ + retval ^= InitSubsys::require(); + + /* xo-reader2/'s own initialization code */ + retval ^= Subsystem::provide("reader2", &init); + + return retval; + } +} /*namespace xo*/ + +/* end init_reader2.cpp */ diff --git a/src/reader2/reader2_register_types.cpp b/src/reader2/reader2_register_types.cpp new file mode 100644 index 00000000..3720752d --- /dev/null +++ b/src/reader2/reader2_register_types.cpp @@ -0,0 +1,29 @@ +/** @file reader2_register_types.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "reader2_register_types.hpp" + +#include + +namespace xo { + using xo::mm::ACollector; + using xo::scope; + + namespace scm { + bool + reader2_register_types(obj /*gc*/) + { + scope log(XO_DEBUG(true)); + + bool ok = true; + + /* no gc-aware types yet; scaffold for future use */ + + return ok; + } + } +} /*namespace xo*/ + +/* end reader2_register_types.cpp */ From 0aa1692f8c3814991d0203c49e6bba4fa6c510a3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 18 Jan 2026 19:25:43 -0500 Subject: [PATCH 075/342] xo-result2: + SchematikaParser --- include/xo/reader2/ParserStateMachine.hpp | 13 ++ include/xo/reader2/SchematikaParser.hpp | 231 ++++++++++++++++++++++ src/reader2/CMakeLists.txt | 1 + src/reader2/ParserStateMachine.cpp | 7 + src/reader2/SchematikaParser.cpp | 92 +++++++++ 5 files changed, 344 insertions(+) create mode 100644 include/xo/reader2/SchematikaParser.hpp create mode 100644 src/reader2/SchematikaParser.cpp diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 339fa029..cae4a551 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -33,12 +33,25 @@ namespace xo { public: ParserStateMachine(const ArenaConfig & config); + /** @defgroup scm-parserstatemachine-accessors accessor methods **/ + ///@{ + + bool debug_flag() const noexcept { return debug_flag_; } + ParserStack * stack() const noexcept { return stack_; } + const ParserResult & result() const noexcept { return result_; } + obj expr_alloc() const noexcept { return expr_alloc_; } + + ///@} + /** @defgroup scm-parserstatemachine-bookkeeping bookkeeping methods **/ ///@{ /** push syntax @p ssm onto @ref stack_ **/ void push_ssm(obj ssm); + /** reset result to none **/ + void reset_result() { result_ = ParserResult(); } + ///@} /** @defgroup scm-parserstatemachine-inputmethods input methods **/ diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp new file mode 100644 index 00000000..8b4688ce --- /dev/null +++ b/include/xo/reader2/SchematikaParser.hpp @@ -0,0 +1,231 @@ +/** @file SchematikaParser.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "ParserStateMachine.hpp" +#include "ParserResult.hpp" +#include + +namespace xo { + namespace scm { + /** schematica parser + * + * Examples: + * + * decltype point + * + * // forward declarations + * decl pi : f64; + * decl fib(n : i32) -> i32; + * + * def pi = 3.14159265; // constant. = is single assignment + * + * def fib(n : i32) -> i32 { + * // nested defs ok + * def aux(n : i32, s1 : i32, s2 : i32) -> i32 { + * // or: + * // (n == 0) ? s1 : aux(n - 1, s1 + s2, s1) + * // + * if (n == 0) { + * s1; + * } else { + * aux(n - 1, s1 + s2, s1); + * } + * + * // or: + * // if (n == 0) ? s1 : aux(n - 1, s1 + s2, s1) + * } + * + * aux(n=n, s1=1, s2=0); + * } + * + * def x := "fu"; // non-constant + * x += "bar"; + * + * def anotherfib = lambda(n : i32) { fib(n) }; + * + * def any : object; + * def l : list = '(); + * + * deftype point :: {x : f64, y : f64}; + * deftype polar :: {arg : f64, mag : f64}; + * deftype converter :: (point -> polar); + * + * def polar2rect(pt : polar) -> point { + * point(x = pt.mag * cos(arg), + * y = pt.mag * sin(arg)); + * } + * + * Grammar: + * toplevel-program = $toplevel-expression(1); ..; $toplevel-expression(n) + * + * if interactive: + * toplevel-expression = expression + * else + * toplevel-expression = type-decl | define-expr + * + * type-decl = decltype $typename [<$tp1 .. $tpn>] + * expression = type-decl + * | define-expr + * | literal-expr + * | variable-expr + * | apply-expr + * | if-expr + * | lambda-expr + * | arithmetic-expr + * | block + * + * define-expr = type-decl + * | type-def + * | variable-def + * | function-decl + * | function-def + * + * type-def = deftype $typename [<$tp1 .. $tpn>] :: type-def-rhs + * type-def-rhs = object + * | bool + * | i128 | i64 | i32 | i16 | i8 + * | f128 | f64 | f32 | f16 + * | struct $typename { ($membername(i) : $typename(i))* } + * [end $typename] + * | tuple $typename { $typename(1), .., $typename(n) } + * [end $typename] + * | copytype $typename + * | subtype $typename { ($member(i) : $typename(i))* } + * + * variable-def = decl $varname [: $typename] [= expression] + * function-decl = decl $functionname($varname(1) : $typename(1), + * .., + * $varname(n) : $typename(n)) -> $typename[ret] + * function-def = def $functionname($varname(1) : $typename(1), + * .., + * $varname(n) : $typename(n)) [-> $typename[ret]] + * body-expr + * [ end $functionname ] + * literal-expr = boolean-literal + * | integer-literal + * | fp-literal + * | string-literal + * | symbol-literal + * | struct-literal + * + * + * boolean-literal = true | false + * + * variable-expr = $varname + * apply-expr = fn-expr(arg-expr(1), .., arg-expr(n)) + * fn-expr = expression + * arg-expr(i) = expression + * + * if-expr = if (test-expr) then-block else else-block + * | ((test-expr) ? then-expr : else-expr) + * test-expr = expression + * then-block = block + * else-block = block + * + * block = { (definition | expression)* } + * + * lambda-expr = lambda ($paramname(1) : $type(1), + * .., + * $paramname(n) : $type(n)) body-expr + * body-expr = expression + * + * arithmetic-expr = expression binop expression + * + * binop = + + * | - + * | * + * | / + * | | + * | & + * | ^ + * | == + * | != + * | < + * | <= + * | => + * | > + * + **/ + class SchematikaParser { + public: + using ArenaConfig = xo::mm::ArenaConfig; + using token_type = Token; + + public: + /** create parser in initial state; + * parser is ready to receive tokens via @ref include_token + * + * @p config arena configuration for parser memory + * @p debug_flag true to enable debug logging + **/ + SchematikaParser(const ArenaConfig & config, bool debug_flag); + + bool debug_flag() const { return debug_flag_; } + + /** true if parser is at top-level, + * i.e. ready for next top-level expression + **/ + bool is_at_toplevel() const; + + /** true iff parser contains state for an incomplete expression. + * For this to be true, parser must have consumed at least one token + * since end of last toplevel expression + **/ + bool has_incomplete_expr() const; + + /** put parser into state for beginning an interactive session. + **/ + void begin_interactive_session(); + + /** put parser into state for beginning of a translation unit + * (i.e. input stream) + **/ + void begin_translation_unit(); + + /** include next token @p tk and increment parser state. + * + * @param tk next input token + * @return parsed expression, if @p tk completes an expression. + * otherwise nullptr + **/ + const ParserResult & include_token(const token_type & tk); + + /** reset parsed result expression; use using return value from + * @ref include_token. Complicating api here to avoid copying ParserResult + * on each token + **/ + void reset_result(); + + /** reset to starting parsing state. + * use this after encountering an error, to avoid cascade of + * spurious secondary errors. particularly important when + * invoked as part of a REPL. + **/ + void reset_to_idle_toplevel(); + + /** print human-readable representation on stream @p os **/ + void print(std::ostream & os) const; + + private: + /** state machine **/ + ParserStateMachine psm_; + + /** debug flag (also stored in psm_) **/ + bool debug_flag_ = false; + }; /*SchematikaParser*/ + + inline std::ostream & + operator<< (std::ostream & os, + const SchematikaParser & x) { + x.print(os); + return os; + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end SchematikaParser.hpp */ diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index f6fc817f..f3eaace2 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -4,6 +4,7 @@ set(SELF_LIB xo_reader2) set(SELF_SRCS init_reader2.cpp + SchematikaParser.cpp ParserStateMachine.cpp ParserStack.cpp ParserResult.cpp diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index a691bb57..c2297da4 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -16,6 +16,13 @@ namespace xo { using xo::facet::with_facet; namespace scm { + ParserStateMachine::ParserStateMachine(const ArenaConfig & config) + : parser_alloc_{DArena::map(config)}, + expr_alloc_{with_facet::mkobj(&parser_alloc_)}, + debug_flag_{config.debug_flag_} + { + } + void ParserStateMachine::push_ssm(obj ssm) { diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp new file mode 100644 index 00000000..712c55d8 --- /dev/null +++ b/src/reader2/SchematikaParser.cpp @@ -0,0 +1,92 @@ +/** @file SchematikaParser.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "SchematikaParser.hpp" +#include "ParserStateMachine.hpp" +#include "ParserStack.hpp" +#include "DExprSeqState.hpp" +#include +#include + +namespace xo { + using xo::tostr; + using xo::xtag; + + namespace scm { + // ----- SchematikaParser ----- + + SchematikaParser::SchematikaParser(const ArenaConfig & config, bool debug_flag) + : psm_{config}, + debug_flag_{debug_flag} + { + } + + bool + SchematikaParser::is_at_toplevel() const { + return psm_.stack() == nullptr; + } + + bool + SchematikaParser::has_incomplete_expr() const { + /* (don't count toplevel exprseq) */ + ParserStack * stack = psm_.stack(); + if (!stack) + return false; + return stack->parent() != nullptr; + } + + void + SchematikaParser::begin_interactive_session() { + DExprSeqState::start_interactive(psm_.expr_alloc(), &psm_); + } + + void + SchematikaParser::begin_translation_unit() { + DExprSeqState::start_batch(psm_.expr_alloc(), &psm_); + } + + const ParserResult & + SchematikaParser::include_token(const token_type & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + if (psm_.stack() == nullptr) { + throw std::runtime_error(tostr("SchematikaParser::include_token", + ": parser not expecting input" + "(call parser.begin_translation_unit()..?)", + xtag("token", tk))); + } + + /* stack is non-empty */ + + psm_.on_token(tk); + + return psm_.result(); + } /*include_token*/ + + void + SchematikaParser::reset_result() + { + psm_.reset_result(); + } + + void + SchematikaParser::reset_to_idle_toplevel() + { + psm_.reset_stack(); + psm_.reset_result(); + } /*reset_to_idle_toplevel*/ + + void + SchematikaParser::print(std::ostream & os) const { + os << "" << std::endl; + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end SchematikaParser.cpp */ From a8eb35bd1a404c4ab379e0c12a34ad34afc21b5c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 18 Jan 2026 20:23:00 -0500 Subject: [PATCH 076/342] xo-reader2: corrections to toplevel SchematikaParser setup --- include/xo/reader2/DExprSeqState.hpp | 8 ++-- include/xo/reader2/ParserStack.hpp | 5 ++- include/xo/reader2/ParserStateMachine.hpp | 21 +++++++++- src/reader2/DExprSeqState.cpp | 24 +++++------- src/reader2/ParserStack.cpp | 5 ++- src/reader2/ParserStateMachine.cpp | 48 ++++++++++++++++++++++- src/reader2/SchematikaParser.cpp | 16 +++----- 7 files changed, 93 insertions(+), 34 deletions(-) diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index f1faed86..f081691a 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -38,11 +38,11 @@ namespace xo { explicit DExprSeqState(exprseqtype ty); /** start interactive top-level session **/ - static void start_interactive(obj mm, - ParserStateMachine * p_psm); + static void establish_interactive(obj mm, + ParserStateMachine * p_psm); /** start non-interactive top-level session **/ - static void start_batch(obj mm, - ParserStateMachine * p_psm); + static void establish_batch(obj mm, + ParserStateMachine * p_psm); public: /** @defgroup scm-exprseq-ssm-facet syntaxstatemachine facet methods **/ diff --git a/include/xo/reader2/ParserStack.hpp b/include/xo/reader2/ParserStack.hpp index 424be42b..4a87de7f 100644 --- a/include/xo/reader2/ParserStack.hpp +++ b/include/xo/reader2/ParserStack.hpp @@ -28,8 +28,9 @@ namespace xo { /** create new top of stack for syntax @p ssm, using memory from @p mm. * previous stack given by @p parent **/ - ParserStack * push(obj mm, - obj ssm); + static ParserStack * push(ParserStack * stack, + obj mm, + obj ssm); obj top() const noexcept { return ssm_; } ParserStack * parent() const noexcept { return parent_; } diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index cae4a551..c3c179ad 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -41,16 +41,28 @@ namespace xo { const ParserResult & result() const noexcept { return result_; } obj expr_alloc() const noexcept { return expr_alloc_; } + /** true iff state machine is currently idle (at top-level) **/ + bool is_at_toplevel() const noexcept; + + /** true iff state machine currently has incomplete expression **/ + bool has_incomplete_expr() const noexcept; + ///@} /** @defgroup scm-parserstatemachine-bookkeeping bookkeeping methods **/ ///@{ + /** establish toplevel @p ssm. Must have empty stack **/ + void establish_toplevel_ssm(obj ssm); + /** push syntax @p ssm onto @ref stack_ **/ void push_ssm(obj ssm); /** reset result to none **/ - void reset_result() { result_ = ParserResult(); } + void reset_result(); + + /** reset after reporting error **/ + void clear_error_reset(); ///@} @@ -89,6 +101,7 @@ namespace xo { ///@} private: + /** Arena for internal parsing stack. * Must be owned exclusively because destructively * modified as parser completes parsing of each sub-expression @@ -97,6 +110,12 @@ namespace xo { **/ DArena parser_alloc_; + /** Checkpoint of toplevel parser allocator. + * Retore parser_alloc to this checkpoint to proceed + * after encountering a parsing error. + **/ + DArena::Checkpoint parser_alloc_ckp_; + /** parser stack. Memory from @ref parser_alloc_ **/ ParserStack * stack_ = nullptr; diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 7d2368e5..4d6ae613 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -30,25 +30,21 @@ namespace xo { } void - DExprSeqState::start_interactive(obj mm, - ParserStateMachine * p_psm) + DExprSeqState::establish_interactive(obj mm, + ParserStateMachine * p_psm) { - - - p_psm->push_ssm(make_exprseq_ssm(mm, - exprseqtype::toplevel_interactive)); + p_psm->establish_toplevel_ssm(make_exprseq_ssm + (mm, + exprseqtype::toplevel_interactive)); } void - DExprSeqState::start_batch(obj mm, - ParserStateMachine * p_psm) + DExprSeqState::establish_batch(obj mm, + ParserStateMachine * p_psm) { - (void)mm; - (void)p_psm; -#ifdef NOT_YET - p_psm->push_ssm(make_exprseq_ssm(mm, - exprseqtype::toplevel_batch)); -#endif + p_psm->establish_toplevel_ssm(make_exprseq_ssm + (mm, + exprseqtype::toplevel_batch)); } // SyntaxStateMachine facet methods diff --git a/src/reader2/ParserStack.cpp b/src/reader2/ParserStack.cpp index 3648cb4d..5b416c54 100644 --- a/src/reader2/ParserStack.cpp +++ b/src/reader2/ParserStack.cpp @@ -16,14 +16,15 @@ namespace xo { {} ParserStack * - ParserStack::push(obj mm, + ParserStack::push(ParserStack * stack, + obj mm, obj ssm) { void * mem = mm.alloc(typeseq::id(), sizeof(ParserStack)); - return new (mem) ParserStack(ssm, parent_); + return new (mem) ParserStack(ssm, stack); } } /*namespace scm*/ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index c2297da4..4f54a584 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -23,6 +23,35 @@ namespace xo { { } + bool + ParserStateMachine::is_at_toplevel() const noexcept + { + return ((stack_ == nullptr) + || (stack_->parent() == nullptr)); + } + + bool + ParserStateMachine::has_incomplete_expr() const noexcept + { + // don't count toplevel expression + + return !(this->is_at_toplevel()); + } + + void + ParserStateMachine::establish_toplevel_ssm(obj ssm) + { + scope log(XO_DEBUG(debug_flag_)); + + assert(stack_ == nullptr); + + auto alloc = with_facet::mkobj(&parser_alloc_); + + this->stack_ = ParserStack::push(nullptr /*stack*/, + alloc, ssm); + this->parser_alloc_ckp_ = parser_alloc_.checkpoint(); + } + void ParserStateMachine::push_ssm(obj ssm) { @@ -32,7 +61,24 @@ namespace xo { auto alloc = with_facet::mkobj(&parser_alloc_); - this->stack_ = stack_->push(alloc, ssm); + this->stack_ = ParserStack::push(stack_, alloc, ssm); + } + + void + ParserStateMachine::reset_result() + { + this->result_ = ParserResult(); + } + + void + ParserStateMachine::clear_error_reset() + { + this->reset_result(); + + while (stack_ && stack_->parent()) + stack_ = stack_->parent(); + + this->parser_alloc_.restore(parser_alloc_ckp_); } void diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 712c55d8..2e607e77 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -25,26 +25,23 @@ namespace xo { bool SchematikaParser::is_at_toplevel() const { - return psm_.stack() == nullptr; + return psm_.is_at_toplevel(); } bool SchematikaParser::has_incomplete_expr() const { - /* (don't count toplevel exprseq) */ - ParserStack * stack = psm_.stack(); - if (!stack) - return false; - return stack->parent() != nullptr; + return !(this->is_at_toplevel()); } void SchematikaParser::begin_interactive_session() { - DExprSeqState::start_interactive(psm_.expr_alloc(), &psm_); + DExprSeqState::establish_interactive(psm_.expr_alloc(), &psm_); + } void SchematikaParser::begin_translation_unit() { - DExprSeqState::start_batch(psm_.expr_alloc(), &psm_); + DExprSeqState::establish_batch(psm_.expr_alloc(), &psm_); } const ParserResult & @@ -75,8 +72,7 @@ namespace xo { void SchematikaParser::reset_to_idle_toplevel() { - psm_.reset_stack(); - psm_.reset_result(); + psm_.clear_error_reset(); } /*reset_to_idle_toplevel*/ void From e38b61ce76b7b73176a4cb894c4ab3acbcfdeb5d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 18 Jan 2026 20:37:15 -0500 Subject: [PATCH 077/342] xo-reader2: ParserStateMachine w/ separate allocator --- include/xo/reader2/ParserStateMachine.hpp | 7 ++++--- include/xo/reader2/SchematikaParser.hpp | 8 +++++++- src/reader2/ParserStateMachine.cpp | 9 ++++++--- src/reader2/SchematikaParser.cpp | 11 +++++++---- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index c3c179ad..466e07f8 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -31,15 +31,16 @@ namespace xo { using DArena = xo::mm::DArena; public: - ParserStateMachine(const ArenaConfig & config); + ParserStateMachine(const ArenaConfig & config, + obj * expr_alloc); /** @defgroup scm-parserstatemachine-accessors accessor methods **/ ///@{ bool debug_flag() const noexcept { return debug_flag_; } ParserStack * stack() const noexcept { return stack_; } + obj * expr_alloc() const noexcept { return expr_alloc_; } const ParserResult & result() const noexcept { return result_; } - obj expr_alloc() const noexcept { return expr_alloc_; } /** true iff state machine is currently idle (at top-level) **/ bool is_at_toplevel() const noexcept; @@ -133,7 +134,7 @@ namespace xo { * scenario, where top-level Expressions can be discarded * once compiled. **/ - obj expr_alloc_; + obj * expr_alloc_ = nullptr; /** current output from parser **/ ParserResult result_; diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 8b4688ce..7d5f36d2 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -8,6 +8,7 @@ #include "ParserStateMachine.hpp" #include "ParserResult.hpp" #include +#include namespace xo { namespace scm { @@ -153,6 +154,7 @@ namespace xo { class SchematikaParser { public: using ArenaConfig = xo::mm::ArenaConfig; + using AAllocator = xo::mm::AAllocator; using token_type = Token; public: @@ -160,9 +162,13 @@ namespace xo { * parser is ready to receive tokens via @ref include_token * * @p config arena configuration for parser memory + * @p expr_alloc allocator for schematika expressions. + * Probably shared with execution. * @p debug_flag true to enable debug logging **/ - SchematikaParser(const ArenaConfig & config, bool debug_flag); + SchematikaParser(const ArenaConfig & config, + obj * expr_alloc, + bool debug_flag); bool debug_flag() const { return debug_flag_; } diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 4f54a584..4756975a 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -16,9 +16,10 @@ namespace xo { using xo::facet::with_facet; namespace scm { - ParserStateMachine::ParserStateMachine(const ArenaConfig & config) + ParserStateMachine::ParserStateMachine(const ArenaConfig & config, + obj * expr_alloc) : parser_alloc_{DArena::map(config)}, - expr_alloc_{with_facet::mkobj(&parser_alloc_)}, + expr_alloc_{expr_alloc}, debug_flag_{config.debug_flag_} { } @@ -176,7 +177,9 @@ namespace xo { xtag("ssm", ssm_name), xtag("via", "ParserStateMachine::illegal_input_on_token")); - auto errmsg = DString::from_view(expr_alloc_, + assert(expr_alloc_); + + auto errmsg = DString::from_view(*expr_alloc_, std::string_view(errmsg_string)); this->capture_error(ssm_name, errmsg); diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 2e607e77..67af915f 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -11,14 +11,17 @@ #include namespace xo { + using xo::mm::AAllocator; using xo::tostr; using xo::xtag; namespace scm { // ----- SchematikaParser ----- - SchematikaParser::SchematikaParser(const ArenaConfig & config, bool debug_flag) - : psm_{config}, + SchematikaParser::SchematikaParser(const ArenaConfig & config, + obj * expr_alloc, + bool debug_flag) + : psm_{config, expr_alloc}, debug_flag_{debug_flag} { } @@ -35,13 +38,13 @@ namespace xo { void SchematikaParser::begin_interactive_session() { - DExprSeqState::establish_interactive(psm_.expr_alloc(), &psm_); + DExprSeqState::establish_interactive(*(psm_.expr_alloc()), &psm_); } void SchematikaParser::begin_translation_unit() { - DExprSeqState::establish_batch(psm_.expr_alloc(), &psm_); + DExprSeqState::establish_batch(*(psm_.expr_alloc()), &psm_); } const ParserResult & From 301a7c76232cbacff82bc6ec94b14bbc10c32200 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 19 Jan 2026 00:38:43 -0500 Subject: [PATCH 078/342] xo-reader2: + DDefineSsm + utest --- CMakeLists.txt | 2 +- idl/ISyntaxStateMachine_DDefineSsm.json5 | 13 + include/xo/reader2/DDefineSsm.hpp | 97 +++++ include/xo/reader2/SchematikaParser.hpp | 2 +- .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 66 +++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 2 + src/reader2/DDefineSsm.cpp | 395 ++++++++++++++++++ .../ISyntaxStateMachine_DDefineSsm.cpp | 50 +++ src/reader2/SchematikaParser.cpp | 2 +- utest/CMakeLists.txt | 11 + utest/SchematikaParser.test.cpp | 95 +++++ utest/reader2_utest_main.cpp | 27 ++ 13 files changed, 762 insertions(+), 3 deletions(-) create mode 100644 idl/ISyntaxStateMachine_DDefineSsm.json5 create mode 100644 include/xo/reader2/DDefineSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp create mode 100644 src/reader2/DDefineSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DDefineSsm.cpp create mode 100644 utest/CMakeLists.txt create mode 100644 utest/SchematikaParser.test.cpp create mode 100644 utest/reader2_utest_main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 30732417..1f3a4520 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ add_definitions(${PROJECT_CXX_FLAGS}) # ---------------------------------------------------------------- # output targets -#add_subdirectory(utest) +add_subdirectory(utest) # note: manual target; generated code committed to git xo_add_genfacet( diff --git a/idl/ISyntaxStateMachine_DDefineSsm.json5 b/idl/ISyntaxStateMachine_DDefineSsm.json5 new file mode 100644 index 00000000..11d2c5f7 --- /dev/null +++ b/idl/ISyntaxStateMachine_DDefineSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DDefineSsm", + using_doxygen: true, + repr: "DDefineSsm", + doc: [ "implement ASyntaxStateMachine for DDefineSsm" ], +} diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp new file mode 100644 index 00000000..10ec3097 --- /dev/null +++ b/include/xo/reader2/DDefineSsm.hpp @@ -0,0 +1,97 @@ +/** @file DDefineSsm.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "ParserStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include + +namespace xo { + namespace scm { + /** + * @pre + * + * def foo : f64 = 1 ; + * ^ ^ ^ ^ ^ ^ ^ ^ + * | | | | | | | (done) + * | | | | | | def_6:expect_rhs_expression:expr_progress + * | | | | | def_5:expect_rhs_expression + * | | | | def_4 + * | | | def_3:expect_type + * | | def_2 + * | def_1:expect_symbol + * def_0 + * expect_toplevel_expression_sequence + * + * def_0 --on_def_token()--> def_1 + * def_1 --on_symbol()--> def_2 + * def_2 --on_colon_token()--> def_3 + * --on_singleassign_token()--> def_5 + * def_3 --on_typedescr()--> def_4 + * def_4 --on_singleassign_token()--> def_5 + * def_5 --on_expr()--> def_6 + * def_6 --on_semicolon_token()--> (done) + * + * def_1:expect_symbol: got 'def' keyword, symbol to follow + * def_1: got symbol name + * def_3:expect_symbol got (optional) colon, type name to follow + * def_4: got symbol type + * def_6:expect_rhs_expression got (optional) equal sign, value to follow + * (done): definition complete, pop exprstate from stack + * + * @endpre + **/ + enum class defexprstatetype { + invalid = -1, + + def_0, + def_1, + def_2, + def_3, + def_4, + def_5, + def_6, + + n_defexprstatetype, + }; + + extern const char * defexprstatetype_descr(defexprstatetype x); + + std::ostream & + operator<<(std::ostream & os, defexprstatetype x); + + /** @class DDefineSsm + * @brief state machine for parsing a define expression + **/ + class DDefineSsm { + public: + + public: + /** @defgroup scm-define-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** text describing expected/allowed input to this ssm in current state. + * Intended to drive error mesages + **/ + std::string_view get_expect_str() const noexcept; + + /** update state for this syntax on incoming token @p tk, + * overall parser state in @p p_psm + **/ + void on_if_token(const Token & tk, ParserStateMachine * p_psm); + + ///@} + + private: + /** identify define-expression state **/ + defexprstatetype defstate_; + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DDefineSsm.hpp */ diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 7d5f36d2..b0f78bff 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -198,7 +198,7 @@ namespace xo { * @return parsed expression, if @p tk completes an expression. * otherwise nullptr **/ - const ParserResult & include_token(const token_type & tk); + const ParserResult & on_token(const token_type & tk); /** reset parsed result expression; use using return value from * @ref include_token. Complicating api here to avoid copying ParserResult diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp new file mode 100644 index 00000000..adb39c48 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -0,0 +1,66 @@ +/** @file ISyntaxStateMachine_DDefineSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DDefineSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DDefineSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DDefineSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DDefineSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DDefineSsm + **/ + class ISyntaxStateMachine_DDefineSsm { + public: + /** @defgroup scm-syntaxstatemachine-ddefinessm-type-traits **/ + ///@{ + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-ddefinessm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DDefineSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DDefineSsm & self) noexcept; + + // non-const methods + /** update state machine for incoming define-keyworkd-token @p tk **/ + static void on_def_token(DDefineSsm & self, const Token & tk, ParserStateMachine * ps_psm); + /** update state machine for incoming if-keyword-token @p tk **/ + static void on_if_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 913cd118..ae02cad4 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -21,6 +21,9 @@ namespace xo { /** toplevel of some translation unit. See @ref DExprSeqState **/ expect_toplevel_expression_sequence, + /** handle define-expression. See @ref DDefineSsm **/ + defexpr, + /** comes lasts, counts number of valid enums **/ N }; diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index f3eaace2..ff8eb418 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -14,6 +14,8 @@ set(SELF_SRCS DExprSeqState.cpp ISyntaxStateMachine_DExprSeqState.cpp + DDefineSsm.cpp + reader2_register_facets.cpp reader2_register_types.cpp ) diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp new file mode 100644 index 00000000..609ec0db --- /dev/null +++ b/src/reader2/DDefineSsm.cpp @@ -0,0 +1,395 @@ +/** @file DDefineSsm.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DDefineSsm.hpp" +#ifdef NOT_YET +#include "parserstatemachine.hpp" +#include "expect_symbol_xs.hpp" +#include "expect_expr_xs.hpp" +#include "expect_type_xs.hpp" +#include "pretty_expression.hpp" +#endif + +namespace xo { + namespace scm { + // ----- defexprstatetype ----- + + const char * + defexprstatetype_descr(defexprstatetype x) { + switch (x) { + case defexprstatetype::invalid: return "invalid"; + case defexprstatetype::def_0: return "def_0"; + case defexprstatetype::def_1: return "def_1"; + case defexprstatetype::def_2: return "def_2"; + case defexprstatetype::def_3: return "def_3"; + case defexprstatetype::def_4: return "def_4"; + case defexprstatetype::def_5: return "def_5"; + case defexprstatetype::def_6: return "def_6"; + case defexprstatetype::n_defexprstatetype: break; + } + + return "???defexprstatetype"; + } + + std::ostream & + operator<<(std::ostream & os, defexprstatetype x) { + os << defexprstatetype_descr(x); + return os; + } + + // ----- define_xs ----- + +#ifdef NOT_YET + std::unique_ptr + define_xs::make() { + return std::make_unique(define_xs(DefineExprAccess::make_empty())); + } + + void + define_xs::start(parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + p_psm->push_exprstate(define_xs::make()); + p_psm->top_exprstate().on_def_token(token_type::def(), p_psm); + } + + define_xs::define_xs(rp def_expr) + : exprstate(exprstatetype::defexpr), + defxs_type_{defexprstatetype::def_0}, + def_expr_{std::move(def_expr)} + {} + + // const char * + // define_xs::get_expect_str() const { ... } + + void + define_xs::on_expr(bp expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log(xtag("defxs_type", defxs_type_)); + + if (this->defxs_type_ == defexprstatetype::def_5) { + /* have all the ingredients to create an expression + * representing a definition + * + * 1. if ir_type is a symbol, interpret as variable name. + * Need to be able to locate variable by type + * 2. if ir_type is an expression, adopt as rhs + */ + rp rhs_value = expr.promote(); + + if (this->cvt_expr_) { + this->cvt_expr_->assign_arg(rhs_value); + } else { + /* note: establishes .def_expr_ valuetype */ + this->def_expr_->assign_rhs(rhs_value); + } + + rp def_expr = this->def_expr_; + + this->defxs_type_ = defexprstatetype::def_6; + return; + } + + constexpr const char * c_self_name = "define_xs::on_expr"; + const char * exp = get_expect_str(); + + this->illegal_input_on_expr(c_self_name, expr, exp, p_psm); + } + + void + define_xs::on_expr_with_semicolon(bp expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log(xtag("defxs_type", defxs_type_)); + + this->on_expr(expr, p_psm); + /* semicolon is allowed to terminate def expr */ + this->on_semicolon_token(token_type::semicolon(), p_psm); + } + + void + define_xs::on_symbol(const std::string & symbol_name, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log(xtag("defxs_type", defxs_type_), xtag("env_stack_size", p_psm->env_stack_size())); + + if (this->defxs_type_ == defexprstatetype::def_1) { + this->defxs_type_ = defexprstatetype::def_2; + this->def_expr_->assign_lhs_name(symbol_name); + + // if this is a genuine top-level define (i.e. nesting level = 0), + // then we need to upsert so we can refer to rhs later. + // + // In other contexts (e.g. body-of-lambda) will be rewriting + // { + // def y = foo(x,x); + // bar(y,y); + // } + // into something like + // { + // (lambda (y123) bar(y123,y123))(foo(x,x)); + // } + // + // This works in the body of lambda, because we don't evaluate anything + // until lambda definition is complete. + // + // For interactive top-level defs we want to evaluate as we go, + // so need incremental bindings. + + if (p_psm->env_stack_size() == 1) { + /* remember variable binding in lexical context, + * so we can refer to it later + */ + p_psm->upsert_var(this->def_expr_->lhs_variable()); + } + + return; + } + + constexpr const char * c_self_name = "define_xs::on_symbol"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_symbol(c_self_name, symbol_name, exp, p_psm); + } + + void + define_xs::on_typedescr(TypeDescr td, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("defxs_type", defxs_type_); + + if (this->defxs_type_ == defexprstatetype::def_3) { + this->defxs_type_ = defexprstatetype::def_4; + this->cvt_expr_ = ConvertExprAccess::make(td /*dest_type*/, + nullptr /*source_expr*/); + /* note: establishes .def_expr_ valuetype */ + this->def_expr_->assign_rhs(this->cvt_expr_); + return; + } + + constexpr const char * c_self_name = "define_xs::on_symbol"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_type(c_self_name, td, exp, p_psm); + } + + void + define_xs::on_def_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + log && log("defxs_type", defxs_type_); + + if (this->defxs_type_ == defexprstatetype::def_0) { + this->defxs_type_ = defexprstatetype::def_1; + + expect_symbol_xs::start(p_psm); + return; + } + + constexpr const char * c_self_name = "define_xs::on_def_token"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + + void + define_xs::on_colon_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + log && log("defxs_type", defxs_type_); + + if (this->defxs_type_ == defexprstatetype::def_2) { + this->defxs_type_ = defexprstatetype::def_3; + + expect_type_xs::start(p_psm); + return; + } + + constexpr const char * c_self_name = "define_xs::on_symbol"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + + void + define_xs::on_semicolon_token(const token_type & tk, + parserstatemachine * p_psm) + { + /* def expr consumes semicolon */ + + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("defxs_type", defxs_type_); + + if (this->defxs_type_ == defexprstatetype::def_6) { + rp def_expr = this->def_expr_; + + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->top_exprstate().on_expr(def_expr, p_psm); + return; + } + + constexpr const char * c_self_name = "define_xs::on_symbol"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + + void + define_xs::on_singleassign_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + log && log("defxs_type", defxs_type_); + + if ((this->defxs_type_ == defexprstatetype::def_2) + || (this->defxs_type_ == defexprstatetype::def_4)) + { + this->defxs_type_ = defexprstatetype::def_5; + expect_expr_xs::start(p_psm); + return; + } + + constexpr const char * c_self_name = "define_xs::on_singleassign_token"; + const char * exp = get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + + void + define_xs::on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + constexpr const char * c_self_name = "define_xs::on_rightparen"; + const char * exp = get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + + void + define_xs::on_i64_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + constexpr const char * c_self_name = "define_xs::on_i64"; + const char * exp = get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + + void + define_xs::on_f64_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + constexpr const char * c_self_name = "define_xs::on_f64"; + const char * exp = get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + + void + define_xs::print(std::ostream & os) const { + os << ""; + } + + bool + define_xs::pretty_print(const xo::print::ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, "define_xs", + refrtag("defxs_type", defxs_type_)); + } +#endif + + //////////////////////////////////////////////////////////////// + + syntaxstatetype + DDefineSsm::ssm_type() const noexcept + { + return syntaxstatetype::defexpr; + } + + std::string_view + DDefineSsm::get_expect_str() const noexcept + { + /* + * def foo = 1 ; + * def foo : f64 = 1 ; + * ^ ^ ^ ^ ^ ^ ^ ^ + * | | | | | | | (done) + * | | | | | | def_6 + * | | | | | def_5:expect_rhs_expression + * | | | | def_4 + * | | | def_3:expect_type + * | | def_2 + * | def_1:expect_symbol + * expect_toplevel_expression_sequence + * + * note that we skip from def_2 -> def_5 if '=' instead of ':' + */ + switch (this->defstate_) { + case defexprstatetype::invalid: + case defexprstatetype::def_0: + case defexprstatetype::n_defexprstatetype: + assert(false); // impossible + return nullptr; + case defexprstatetype::def_1: + return "symbol"; + case defexprstatetype::def_2: + return "singleassign|colon"; + case defexprstatetype::def_4: + return "singleassign"; + case defexprstatetype::def_3: + return "type"; + case defexprstatetype::def_5: + return "expression"; + case defexprstatetype::def_6: + return "semicolon"; + } + + return "?expect"; + } + + void + DDefineSsm::on_if_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DDefineSsm::on_if_token", + tk, + this->get_expect_str()); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DDefineSsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp new file mode 100644 index 00000000..bf17c9b5 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -0,0 +1,50 @@ +/** @file ISyntaxStateMachine_DDefineSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DDefineSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DDefineSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DDefineSsm::ssm_type(const DDefineSsm & self) noexcept + -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DDefineSsm::get_expect_str(const DDefineSsm & self) noexcept + -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DDefineSsm::on_def_token(DDefineSsm & self, + const Token & tk, + ParserStateMachine * ps_psm) -> void + { + self.on_def_token(tk, ps_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::on_if_token(DDefineSsm & self, + const Token & tk, + ParserStateMachine * p_psm) -> void + { + self.on_if_token(tk, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DDefineSsm.cpp */ diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 67af915f..f9f0b482 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -48,7 +48,7 @@ namespace xo { } const ParserResult & - SchematikaParser::include_token(const token_type & tk) + SchematikaParser::on_token(const token_type & tk) { scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt new file mode 100644 index 00000000..f6de05ed --- /dev/null +++ b/utest/CMakeLists.txt @@ -0,0 +1,11 @@ +# build unittest xo-reader2/utest + +set(UTEST_EXE utest.reader2) +set(UTEST_SRCS + reader2_utest_main.cpp + SchematikaParser.test.cpp +) + +xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) +xo_self_dependency(${UTEST_EXE} xo_reader2) +xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp new file mode 100644 index 00000000..1f066f3e --- /dev/null +++ b/utest/SchematikaParser.test.cpp @@ -0,0 +1,95 @@ +/** @file SchematikaParser.test.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include +#include +#include + +namespace xo { + using xo::scm::SchematikaParser; + using xo::scm::ParserResult; + using xo::scm::parser_result_type; + using xo::scm::Token; + using xo::mm::ArenaConfig; + using xo::mm::AAllocator; + using xo::mm::DArena; + using xo::facet::with_facet; + + namespace ut { + TEST_CASE("SchematikaParser-ctor", "[reader2][SchematikaParser]") + { + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); + + REQUIRE(parser.debug_flag() == false); + REQUIRE(parser.is_at_toplevel() == true); + } + + TEST_CASE("SchematikaParser-begin-interactive", "[reader2][SchematikaParser]") + { + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); + + parser.begin_interactive_session(); + + // after begin_interactive_session, parser has toplevel exprseq + // but is still "at toplevel" in the sense of ready for input + REQUIRE(parser.has_incomplete_expr() == false); + } + + TEST_CASE("SchematikaParser-begin-batch", "[reader2][SchematikaParser]") + { + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); + + parser.begin_translation_unit(); + + // after begin_translation_unit, parser has toplevel exprseq + // but is still "at toplevel" in the sense of ready for input + REQUIRE(parser.has_incomplete_expr() == false); + } + + TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]") + { + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); + + parser.begin_interactive_session(); + + parser.on_token(Token::if_token()); + + // after begin_interactive_session, parser has toplevel exprseq + // but is still "at toplevel" in the sense of ready for input + REQUIRE(parser.has_incomplete_expr() == false); + } + + } /*namespace ut*/ +} /*namespace xo*/ + +/* end SchematikaParser.test.cpp */ diff --git a/utest/reader2_utest_main.cpp b/utest/reader2_utest_main.cpp new file mode 100644 index 00000000..cccb0e64 --- /dev/null +++ b/utest/reader2_utest_main.cpp @@ -0,0 +1,27 @@ +/** @file reader2_utest_main.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include + +#define CATCH_CONFIG_RUNNER +#include "catch2/catch.hpp" + +int +main(int argc, char* argv[]) +{ + using xo::Subsystem; + + // initialize subsystems + Subsystem::initialize_all(); + + // Run Catch2's test session + int result = Catch::Session().run(argc, argv); + + // cleanup here, if any + + return result; +} + +/* end reader2_utest_main.cpp */ From b5d2f3efabb1d62dd6b9718207d7a35b36ae9f3c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 19 Jan 2026 00:39:16 -0500 Subject: [PATCH 079/342] xo-reader: + DDefineSsm + utest --- CMakeLists.txt | 12 ++++ idl/SyntaxStateMachine.json5 | 9 +++ include/xo/reader2/DDefineSsm.hpp | 27 +++++++- include/xo/reader2/DExprSeqState.hpp | 5 ++ include/xo/reader2/ParserResult.hpp | 4 ++ include/xo/reader2/ParserStateMachine.hpp | 6 ++ include/xo/reader2/SchematikaParser.hpp | 2 +- include/xo/reader2/SyntaxStateMachine.hpp | 2 +- .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 4 +- .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 3 +- .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 4 +- .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 5 +- .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 5 +- src/reader2/CMakeLists.txt | 1 + src/reader2/DDefineSsm.cpp | 61 ++++++++++++++++--- src/reader2/DExprSeqState.cpp | 20 +++++- src/reader2/ISyntaxStateMachine_Any.cpp | 6 ++ .../ISyntaxStateMachine_DExprSeqState.cpp | 15 ++++- src/reader2/ParserStateMachine.cpp | 20 ++++-- src/reader2/SchematikaParser.cpp | 2 +- utest/SchematikaParser.test.cpp | 34 ++++++++++- 21 files changed, 219 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f3a4520..a00bc2c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,18 @@ xo_add_genfacetimpl( OUTPUT_CPP_DIR src/reader2 ) +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-definessm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR DefineSsm + INPUT idl/ISyntaxStateMachine_DDefineSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + # ---------------------------------------------------------------- # shared library diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 0023a16e..f2058e9d 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -43,6 +43,15 @@ }, ], nonconst_methods: [ + { + name: "on_def_token", + doc: ["update state machine for incoming define-keyworkd-token @p tk"], + return_type: "void", + args: [ + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "ps_psm"}, + ], + }, { name: "on_if_token", doc: ["update state machine for incoming if-keyword-token @p tk"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 10ec3097..3a34d0a3 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -3,6 +3,8 @@ * @author Roland Conybeare, Jan 2026 **/ +#pragma once + #include "ParserStateMachine.hpp" #include "SyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" @@ -67,8 +69,24 @@ namespace xo { **/ class DDefineSsm { public: + using DArena = xo::mm::DArena; public: + /** @defgroup scm-define-ssm-facet constructors **/ + ///@{ + + DDefineSsm(); + + /** create instance using memory from @p parser_mm **/ + static DDefineSsm * make(DArena & parser_mm); + + /** start nested parser for a define-expression, + * on top of parser state machine @p p_psm + **/ + static void start(DArena & parser_mm, + ParserStateMachine * p_psm); + + ///@} /** @defgroup scm-define-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -83,7 +101,14 @@ namespace xo { /** update state for this syntax on incoming token @p tk, * overall parser state in @p p_psm **/ - void on_if_token(const Token & tk, ParserStateMachine * p_psm); + void on_def_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming token @p tk, + * overall parser state in @p p_psm + **/ + void on_if_token(const Token & tk, + ParserStateMachine * p_psm); ///@} diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index f081691a..c0e0d8af 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -56,6 +56,11 @@ namespace xo { **/ std::string_view get_expect_str() const noexcept; + /** update state for this syntax on incoming token @p tk, + * overall parser state in @p p_psm + **/ + void on_def_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/ParserResult.hpp b/include/xo/reader2/ParserResult.hpp index 3aadbdae..e179d4bd 100644 --- a/include/xo/reader2/ParserResult.hpp +++ b/include/xo/reader2/ParserResult.hpp @@ -40,6 +40,10 @@ namespace xo { obj result_expr() const { return result_expr_; } const DString * error_description() const { return error_description_; } + bool is_incomplete() const { return result_type_ == parser_result_type::none; } + bool is_expression() const { return result_type_ == parser_result_type::expression; } + bool is_error() const { return result_type_ == parser_result_type::error; } + private: parser_result_type result_type_ = parser_result_type::none; obj result_expr_; diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 466e07f8..63d761c0 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -53,6 +53,9 @@ namespace xo { /** @defgroup scm-parserstatemachine-bookkeeping bookkeeping methods **/ ///@{ + /** allocator for parsing stack and ssm's **/ + DArena & parser_alloc() noexcept { return parser_alloc_; } + /** establish toplevel @p ssm. Must have empty stack **/ void establish_toplevel_ssm(obj ssm); @@ -75,6 +78,9 @@ namespace xo { **/ void on_token(const Token & tk); + /** update state for incoming define-token @p tk **/ + void on_def_token(const Token & tk); + /** update state for incoming if-token @p tk **/ void on_if_token(const Token & tk); diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index b0f78bff..075fb4fc 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -190,7 +190,7 @@ namespace xo { /** put parser into state for beginning of a translation unit * (i.e. input stream) **/ - void begin_translation_unit(); + void begin_batch_session(); /** include next token @p tk and increment parser state. * diff --git a/include/xo/reader2/SyntaxStateMachine.hpp b/include/xo/reader2/SyntaxStateMachine.hpp index deda9e1d..56a8271b 100644 --- a/include/xo/reader2/SyntaxStateMachine.hpp +++ b/include/xo/reader2/SyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for facet .hpp file: diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index a519b246..a6586263 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -54,6 +54,8 @@ public: virtual std::string_view get_expect_str(Copaque data) const noexcept = 0; // nonconst methods + /** update state machine for incoming define-keyworkd-token @p tk **/ + virtual void on_def_token(Opaque data, const Token & tk, ParserStateMachine * ps_psm) = 0; /** update state machine for incoming if-keyword-token @p tk **/ virtual void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 2d5dd0c3..35efd49e 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -59,6 +59,7 @@ namespace scm { [[noreturn]] std::string_view get_expect_str(Copaque) const noexcept override { _fatal(); } // nonconst methods + [[noreturn]] void on_def_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_if_token(Opaque, const Token &, ParserStateMachine *) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index b1d889b1..c3a540a8 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExprSeqState.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -53,6 +53,8 @@ namespace xo { static std::string_view get_expect_str(const DExprSeqState & self) noexcept; // non-const methods + /** update state machine for incoming define-keyworkd-token @p tk **/ + static void on_def_token(DExprSeqState & self, const Token & tk, ParserStateMachine * ps_psm); /** update state machine for incoming if-keyword-token @p tk **/ static void on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index c3aec83e..ad48c7af 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -50,6 +50,9 @@ namespace scm { } // non-const methods + void on_def_token(Opaque data, const Token & tk, ParserStateMachine * ps_psm) override { + return I::on_def_token(_dcast(data), tk, ps_psm); + } void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_if_token(_dcast(data), tk, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 5f920614..8841e242 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -55,6 +55,9 @@ public: } // non-const methods (still const in router!) + void on_def_token(const Token & tk, ParserStateMachine * ps_psm) { + return O::iface()->on_def_token(O::data(), tk, ps_psm); + } void on_if_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_if_token(O::data(), tk, p_psm); } diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index ff8eb418..290f75cc 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -15,6 +15,7 @@ set(SELF_SRCS ISyntaxStateMachine_DExprSeqState.cpp DDefineSsm.cpp + ISyntaxStateMachine_DDefineSsm.cpp reader2_register_facets.cpp reader2_register_types.cpp diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 609ec0db..87d1af35 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -4,6 +4,8 @@ **/ #include "DDefineSsm.hpp" +#include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" + #ifdef NOT_YET #include "parserstatemachine.hpp" #include "expect_symbol_xs.hpp" @@ -13,6 +15,9 @@ #endif namespace xo { + using xo::facet::with_facet; + using xo::facet::typeseq; + namespace scm { // ----- defexprstatetype ----- @@ -46,16 +51,11 @@ namespace xo { define_xs::make() { return std::make_unique(define_xs(DefineExprAccess::make_empty())); } +#endif - void - define_xs::start(parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - p_psm->push_exprstate(define_xs::make()); - p_psm->top_exprstate().on_def_token(token_type::def(), p_psm); - } + // DDefineSsm::start +#ifdef NOT_YET define_xs::define_xs(rp def_expr) : exprstate(exprstatetype::defexpr), defxs_type_{defexprstatetype::def_0}, @@ -333,6 +333,36 @@ namespace xo { //////////////////////////////////////////////////////////////// + DDefineSsm::DDefineSsm() + : defstate_{defexprstatetype::def_0} + {} + + DDefineSsm * + DDefineSsm::make(DArena & mm) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DDefineSsm)); + + return new (mem) DDefineSsm(); + } + + void + DDefineSsm::start(DArena & mm, + ParserStateMachine * p_psm) + { + //scope log(XO_DEBUG(p_psm->debug_flag())); + + assert(p_psm->stack()); + + DDefineSsm * define_ssm = DDefineSsm::make(mm); + + obj ssm + = with_facet::mkobj(define_ssm); + + p_psm->push_ssm(ssm); + p_psm->on_def_token(Token::def_token()); + } + syntaxstatetype DDefineSsm::ssm_type() const noexcept { @@ -380,6 +410,21 @@ namespace xo { return "?expect"; } + void + DDefineSsm::on_def_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (this->defstate_ == defexprstatetype::def_0) { + this->defstate_ = defexprstatetype::def_1; + + // expect_symbol_xs::start(p_psm->parser_alloc(), p_psm); + } + + p_psm->illegal_input_on_token("DDefineSsm::on_define_token", + tk, + this->get_expect_str()); + } + void DDefineSsm::on_if_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 4d6ae613..2922dd7f 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -4,6 +4,7 @@ **/ #include "DExprSeqState.hpp" +#include "DDefineSsm.hpp" #include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" namespace xo { @@ -73,13 +74,30 @@ namespace xo { return "impossible-DExprSeqState::get_expr_str"; } + void + DExprSeqState::on_def_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + DDefineSsm::start(p_psm->parser_alloc(), p_psm); + + /* keyword 'def' introduces a definition: + * def pi : f64 = 3.14159265 + * def sq(x : f64) -> f64 { (x * x) } + */ + } + void DExprSeqState::on_if_token(const Token & tk, ParserStateMachine * p_psm) { switch (seqtype_) { case exprseqtype::toplevel_interactive: - assert(false); // DfElseState::start(p_psm); + p_psm->illegal_input_on_token("DExprSeqState::on_if_token", + tk, + this->get_expect_str()); + //assert(false); // DfElseState::start(p_psm); break; case exprseqtype::toplevel_batch: p_psm->illegal_input_on_token("DExprSeqState::on_if_token", diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 8c4c0b42..ce85a9e0 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -34,6 +34,12 @@ ISyntaxStateMachine_Any::_valid // nonconst methods +auto +ISyntaxStateMachine_Any::on_def_token(Opaque, const Token &, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_if_token(Opaque, const Token &, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index 87f4f2d8..a3abc520 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExprSeqState.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -28,7 +28,16 @@ namespace xo { } auto - ISyntaxStateMachine_DExprSeqState::on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExprSeqState::on_def_token(DExprSeqState & self, + const Token & tk, + ParserStateMachine * p_psm) -> void + { + self.on_def_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExprSeqState::on_if_token(DExprSeqState & self, + const Token & tk, + ParserStateMachine * p_psm) -> void { self.on_if_token(tk, p_psm); } @@ -36,4 +45,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end ISyntaxStateMachine_DExprSeqState.cpp */ \ No newline at end of file +/* end ISyntaxStateMachine_DExprSeqState.cpp */ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 4756975a..25765466 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -48,8 +48,7 @@ namespace xo { auto alloc = with_facet::mkobj(&parser_alloc_); - this->stack_ = ParserStack::push(nullptr /*stack*/, - alloc, ssm); + this->stack_ = ParserStack::push(nullptr /*stack*/, alloc, ssm); this->parser_alloc_ckp_ = parser_alloc_.checkpoint(); } @@ -96,11 +95,14 @@ namespace xo { } switch (tk.tk_type()) { + case tokentype::tk_def: + this->on_def_token(tk); + break; + case tokentype::tk_if: this->on_if_token(tk); break; - // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_bool: @@ -133,7 +135,6 @@ namespace xo { case tokentype::tk_cmpeq: case tokentype::tk_cmpne: case tokentype::tk_type: - case tokentype::tk_def: case tokentype::tk_lambda: case tokentype::tk_then: case tokentype::tk_else: @@ -141,12 +142,21 @@ namespace xo { case tokentype::tk_in: case tokentype::tk_end: case tokentype::N: - throw std::runtime_error(tostr("NOT IMPLEMENTED", + throw std::runtime_error(tostr("ParserStateMachin::on_token:", + "NOT IMPLEMENTED", xtag("token", tk))); } } + void + ParserStateMachine::on_def_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + stack_->top().on_def_token(tk, this); + } + void ParserStateMachine::on_if_token(const Token & tk) { diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index f9f0b482..47f6918b 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -43,7 +43,7 @@ namespace xo { } void - SchematikaParser::begin_translation_unit() { + SchematikaParser::begin_batch_session() { DExprSeqState::establish_batch(*(psm_.expr_alloc()), &psm_); } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 1f066f3e..b333ff0c 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -62,13 +62,38 @@ namespace xo { SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); - parser.begin_translation_unit(); + parser.begin_batch_session(); // after begin_translation_unit, parser has toplevel exprseq // but is still "at toplevel" in the sense of ready for input REQUIRE(parser.has_incomplete_expr() == false); } + TEST_CASE("SchematikaParser-batch-def", "[reader2][SchematikaParser]") + { + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); + + parser.begin_batch_session(); + + auto & result = parser.on_token(Token::def_token()); + + // define-expressions not properly implemented + + // after begin_interactive_session, parser has toplevel exprseq + // but is still "at toplevel" in the sense of ready for input + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(result.is_error()); + + REQUIRE(result.error_description()); + } + TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]") { ArenaConfig config; @@ -82,11 +107,16 @@ namespace xo { parser.begin_interactive_session(); - parser.on_token(Token::if_token()); + auto & result = parser.on_token(Token::if_token()); // after begin_interactive_session, parser has toplevel exprseq // but is still "at toplevel" in the sense of ready for input REQUIRE(parser.has_incomplete_expr() == false); + + REQUIRE(result.is_error()); + + // illegal input on token + REQUIRE(result.error_description()); } } /*namespace ut*/ From e3be7ed2de57f76f05643f8061c61c8fce237bf1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 19 Jan 2026 00:39:16 -0500 Subject: [PATCH 080/342] xo-reader: + DDefineSsm + utest --- include/xo/tokenizer2/Token.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index 0994e3b8..7ed490cc 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -132,7 +132,7 @@ namespace xo { /** token representing keyword @c type **/ static Token type() { return Token(tokentype::tk_type); } /** token representing keyword @c def **/ - static Token def() { return Token(tokentype::tk_def); } + static Token def_token() { return Token(tokentype::tk_def); } /** token representing keyword @c lambda **/ static Token lambda() { return Token(tokentype::tk_lambda); } /** token representing keyword @c if **/ From 284ed02de6ad75c5141de241a7b9b44bd2ff9c6b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 19 Jan 2026 11:32:39 -0500 Subject: [PATCH 081/342] xo-reader2: + ExpectSymbolSsm + SyntaxStateMachine.on_parsed_symbol --- CMakeLists.txt | 12 ++ doc/README.md | 6 + doc/glossary.rst | 3 + ...ISyntaxStateMachine_DExpectSymbolSsm.json5 | 13 +++ idl/SyntaxStateMachine.json5 | 13 ++- include/xo/reader2/DDefineSsm.hpp | 8 +- include/xo/reader2/DExpectSymbolSsm.hpp | 91 +++++++++++++++ include/xo/reader2/DExprSeqState.hpp | 6 + include/xo/reader2/ParserStack.hpp | 17 ++- include/xo/reader2/ParserStateMachine.hpp | 15 ++- .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 6 +- .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 6 +- .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 68 +++++++++++ .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 6 +- .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 7 +- .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 7 +- include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 3 + src/reader2/DDefineSsm.cpp | 16 ++- src/reader2/DExpectSymbolSsm.cpp | 109 ++++++++++++++++++ src/reader2/DExprSeqState.cpp | 9 ++ src/reader2/ISyntaxStateMachine_Any.cpp | 6 + .../ISyntaxStateMachine_DDefineSsm.cpp | 23 ++-- .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 49 ++++++++ .../ISyntaxStateMachine_DExprSeqState.cpp | 15 +-- src/reader2/ParserStack.cpp | 22 +++- src/reader2/ParserStateMachine.cpp | 49 +++++++- 28 files changed, 537 insertions(+), 52 deletions(-) create mode 100644 doc/README.md create mode 100644 doc/glossary.rst create mode 100644 idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 create mode 100644 include/xo/reader2/DExpectSymbolSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp create mode 100644 src/reader2/DExpectSymbolSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a00bc2c1..17c3aac7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,18 @@ xo_add_genfacetimpl( OUTPUT_CPP_DIR src/reader2 ) +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expectsymbolssm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ExpectSymbolSsm + INPUT idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + # ---------------------------------------------------------------- # shared library diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 00000000..01b5c555 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,6 @@ +diagram for parsing stack. +stack growing down for nested ssm's + +`on_if_token` etc going to same state + +`on_parsed_xxx` going back up the stack diff --git a/doc/glossary.rst b/doc/glossary.rst new file mode 100644 index 00000000..67b04538 --- /dev/null +++ b/doc/glossary.rst @@ -0,0 +1,3 @@ +ssm = syntax state machine +psm = parser state machine +ckp = checkpoint diff --git a/idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 b/idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 new file mode 100644 index 00000000..24b754e4 --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectSymbolSsm", + using_doxygen: true, + repr: "DExpectSymbolSsm", + doc: [ "implement ASyntaxStateMachine for DExpectSymbolSsm" ], +} diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index f2058e9d..2be2a98d 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -45,11 +45,11 @@ nonconst_methods: [ { name: "on_def_token", - doc: ["update state machine for incoming define-keyworkd-token @p tk"], + doc: ["update state machine for incoming define-keyword-token @p tk"], return_type: "void", args: [ {type: "const Token &", name: "tk"}, - {type: "ParserStateMachine *", name: "ps_psm"}, + {type: "ParserStateMachine *", name: "p_psm"}, ], }, { @@ -61,5 +61,14 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_parsed_symbol", + doc: ["update stat machine for incoming parsed symbol @p sym"], + return_type: "void", + args: [ + {type: "std::string_view", name: "sym"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, ], } diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 3a34d0a3..37ccc23d 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -6,7 +6,7 @@ #pragma once #include "ParserStateMachine.hpp" -#include "SyntaxStateMachine.hpp" +//#include "SyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" #include @@ -110,6 +110,12 @@ namespace xo { void on_if_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax after parsing a symbol @p sym; + * overall parser state in @p p_psm + **/ + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); + ///@} private: diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp new file mode 100644 index 00000000..dadd1300 --- /dev/null +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -0,0 +1,91 @@ +/* file DExpectSymbolSsm.hpp + * + * author: Roland Conybeare, Aug 2024 + */ + +#pragma once + +#include "ParserStateMachine.hpp" +//#include "SyntaxStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include + +namespace xo { + namespace scm { + /** @class DExpectSymbolSsm + * @brief state machine to expect + capture a symbol + * + * For example: + * - lhs in a define-expression + **/ + class DExpectSymbolSsm { + public: + using DArena = xo::mm::DArena; + + public: + DExpectSymbolSsm(); + + /** create instance using memory from @p parser_mm **/ + static DExpectSymbolSsm * make(DArena & parser_mm); + + /** start nested parser expecting a symbol, + * on top of parser state machine @p p_psm. + * On success will deliver symbol by invoking + * .on_symbol(sym, p_psm) + * to the state machine on top of the stack + * as of when this start() method invoked + **/ + static void start(DArena & parser_mm, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming token @p tk, + * with overall parser state in @p p_psm + **/ + static void on_symbol_token(const Token & tk, + ParserStateMachine * p_psm); + + /** @defgroup scm-expectsymbol-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** text describing expected/allowed input to this ssm in current state. + * Intended to drive error mesages + **/ + std::string_view get_expect_str() const noexcept; + + /** update state for this syntax on incoming token @p tk, + * overall parser state in @p p_psm + **/ + void on_def_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming token @p tk, + * overall parser state in @p p_psm + **/ + void on_if_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax after parsing a symbol @p sym; + * overall parser state in @p p_psm. + * + * NOTE: + * might not be obvious that this is unreachable. + * DExpectSymbolSsm converts a symbol token, + * and delivers it to parent ssm using this entry point. + * This method would only be called if consecutive + * DExpectSymbolSsm instances on parser stack; + * which scenario never occurs in Schematika syntax + **/ + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); + + + ///@} + + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectSymbolSsm.hpp */ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index c0e0d8af..1b611aaf 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -66,6 +66,12 @@ namespace xo { **/ void on_if_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on parsed symbol @p sym + * from immediately-downstream ssm. + * overall parser state in @p p_psm + **/ + void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm); + ///@} private: diff --git a/include/xo/reader2/ParserStack.hpp b/include/xo/reader2/ParserStack.hpp index 4a87de7f..b63be044 100644 --- a/include/xo/reader2/ParserStack.hpp +++ b/include/xo/reader2/ParserStack.hpp @@ -6,7 +6,7 @@ #pragma once #include "SyntaxStateMachine.hpp" -#include +#include #include namespace xo { @@ -20,22 +20,31 @@ namespace xo { **/ class ParserStack { public: - using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; public: - ParserStack(obj ssm, ParserStack * parent); + ParserStack(DArena::Checkpoint ckp, + obj ssm, + ParserStack * parent); /** create new top of stack for syntax @p ssm, using memory from @p mm. * previous stack given by @p parent **/ static ParserStack * push(ParserStack * stack, - obj mm, + DArena & mm, obj ssm); + /** unwind effect of last call to @ref push **/ + static ParserStack * pop(ParserStack * stack, + DArena & mm); + + DArena::Checkpoint ckp() const noexcept { return ckp_; } obj top() const noexcept { return ssm_; } ParserStack * parent() const noexcept { return parent_; } private: + /** stack pointer: top of stack just before this instance created **/ + DArena::Checkpoint ckp_; /** top of parsing stack: always non-null **/ obj ssm_; /** remainder of parsing stack excluding top **/ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 63d761c0..f5293bff 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -62,6 +62,9 @@ namespace xo { /** push syntax @p ssm onto @ref stack_ **/ void push_ssm(obj ssm); + /** pop syntax state machine from top of @ref stack_ **/ + void pop_ssm(); + /** reset result to none **/ void reset_result(); @@ -73,6 +76,9 @@ namespace xo { /** @defgroup scm-parserstatemachine-inputmethods input methods **/ ///@{ + /** update state to respond to prsed symbol @p sym **/ + void on_parsed_symbol(std::string_view sym); + /** update state to respond to input token @p tk. * record output (if any) in @ref result_ **/ @@ -99,12 +105,19 @@ namespace xo { /** report illegal input from syntax state machine @p ssm_name * recognized on input token @p tk. @p expect_str describes - * expected input in that state + * expected input in current ssm state **/ void illegal_input_on_token(std::string_view ssm_name, const Token & tk, std::string_view expect_str); + /** report illegal input from syntax state machine @p ssm_name + * receiving parsed symbol @p sym. @p expect_str describes + * expected input in current ssm state + **/ + void illegal_input_on_symbol(std::string_view ssm_name, + std::string_view sym, + std::string_view expect_str); ///@} private: diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index a6586263..b181fd8d 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -54,8 +54,10 @@ public: virtual std::string_view get_expect_str(Copaque data) const noexcept = 0; // nonconst methods - /** update state machine for incoming define-keyworkd-token @p tk **/ - virtual void on_def_token(Opaque data, const Token & tk, ParserStateMachine * ps_psm) = 0; + /** update stat machine for incoming parsed symbol @p sym **/ + virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; + /** update state machine for incoming define-keyword-token @p tk **/ + virtual void on_def_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming if-keyword-token @p tk **/ virtual void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 35efd49e..046adacb 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -59,6 +59,7 @@ namespace scm { [[noreturn]] std::string_view get_expect_str(Copaque) const noexcept override { _fatal(); } // nonconst methods + [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_def_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_if_token(Opaque, const Token &, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index adb39c48..cfb38fa7 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -53,8 +53,10 @@ namespace xo { static std::string_view get_expect_str(const DDefineSsm & self) noexcept; // non-const methods - /** update state machine for incoming define-keyworkd-token @p tk **/ - static void on_def_token(DDefineSsm & self, const Token & tk, ParserStateMachine * ps_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** update state machine for incoming define-keyword-token @p tk **/ + static void on_def_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming if-keyword-token @p tk **/ static void on_if_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp new file mode 100644 index 00000000..44cb6de4 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -0,0 +1,68 @@ +/** @file ISyntaxStateMachine_DExpectSymbolSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectSymbolSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectSymbolSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectSymbolSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectSymbolSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectSymbolSsm + **/ + class ISyntaxStateMachine_DExpectSymbolSsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpectsymbolssm-type-traits **/ + ///@{ + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexpectsymbolssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectSymbolSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectSymbolSsm & self) noexcept; + + // non-const methods + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** update state machine for incoming define-keyword-token @p tk **/ + static void on_def_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming if-keyword-token @p tk **/ + static void on_if_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index c3a540a8..4da00f95 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -53,8 +53,10 @@ namespace xo { static std::string_view get_expect_str(const DExprSeqState & self) noexcept; // non-const methods - /** update state machine for incoming define-keyworkd-token @p tk **/ - static void on_def_token(DExprSeqState & self, const Token & tk, ParserStateMachine * ps_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); + /** update state machine for incoming define-keyword-token @p tk **/ + static void on_def_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming if-keyword-token @p tk **/ static void on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index ad48c7af..7de32e25 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -50,8 +50,11 @@ namespace scm { } // non-const methods - void on_def_token(Opaque data, const Token & tk, ParserStateMachine * ps_psm) override { - return I::on_def_token(_dcast(data), tk, ps_psm); + void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) override { + return I::on_parsed_symbol(_dcast(data), sym, p_psm); + } + void on_def_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_def_token(_dcast(data), tk, p_psm); } void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_if_token(_dcast(data), tk, p_psm); diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 8841e242..f35f4e72 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -55,8 +55,11 @@ public: } // non-const methods (still const in router!) - void on_def_token(const Token & tk, ParserStateMachine * ps_psm) { - return O::iface()->on_def_token(O::data(), tk, ps_psm); + void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { + return O::iface()->on_parsed_symbol(O::data(), sym, p_psm); + } + void on_def_token(const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_def_token(O::data(), tk, p_psm); } void on_if_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_if_token(O::data(), tk, p_psm); diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index ae02cad4..bf3e03f1 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -21,6 +21,9 @@ namespace xo { /** toplevel of some translation unit. See @ref DExprSeqState **/ expect_toplevel_expression_sequence, + /** expecting a s symbol. See @ref DExpectSymbolSsm **/ + expect_symbol, + /** handle define-expression. See @ref DDefineSsm **/ defexpr, diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 290f75cc..655ac7e9 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -17,6 +17,9 @@ set(SELF_SRCS DDefineSsm.cpp ISyntaxStateMachine_DDefineSsm.cpp + DExpectSymbolSsm.cpp + ISyntaxStateMachine_DExpectSymbolSsm.cpp + reader2_register_facets.cpp reader2_register_types.cpp ) diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 87d1af35..8ac919e4 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -46,12 +46,7 @@ namespace xo { // ----- define_xs ----- -#ifdef NOT_YET - std::unique_ptr - define_xs::make() { - return std::make_unique(define_xs(DefineExprAccess::make_empty())); - } -#endif + // DDefineSsm::make // DDefineSsm::start @@ -410,6 +405,15 @@ namespace xo { return "?expect"; } + void + DDefineSsm::on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol("DDefineSsm::on_parsed_symbol", + sym, + this->get_expect_str()); + } + void DDefineSsm::on_def_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp new file mode 100644 index 00000000..6afe337c --- /dev/null +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -0,0 +1,109 @@ +/** @file DExpectSymbolSsm.cpp + * + * @author Roland Conybeare, Aug 2024 + **/ + +#include "DExpectSymbolSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp" +#include "SyntaxStateMachine.hpp" +#include "ParserStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include +//#include + +namespace xo { + using xo::facet::with_facet; + using xo::facet::typeseq; + + namespace scm { + DExpectSymbolSsm::DExpectSymbolSsm() + {} + + DExpectSymbolSsm * + DExpectSymbolSsm::make(DArena & mm) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DExpectSymbolSsm)); + + return new (mem) DExpectSymbolSsm(); + } + + void + DExpectSymbolSsm::start(DArena & parser_alloc, + ParserStateMachine * p_psm) + { + DExpectSymbolSsm * sym_ssm + = DExpectSymbolSsm::make(parser_alloc); + + // note: + // relying on [ISyntaxStateMachine_DExpectedSymbolSsm.hpp] + // + obj ssm + = with_facet::mkobj(sym_ssm); + + p_psm->push_ssm(ssm); + } + + syntaxstatetype + DExpectSymbolSsm::ssm_type() const noexcept + { + return syntaxstatetype::expect_symbol; + } + + std::string_view + DExpectSymbolSsm::get_expect_str() const noexcept + { + return "symbol"; + } + + void + DExpectSymbolSsm::on_symbol_token(const Token & tk, + ParserStateMachine * p_psm) + { +#ifdef NOT_YET + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag)); + + log && log(xtag("tk", tk)); + + assert(&p_psm->top_exprstate() == this); +#endif + + /* have to do pop first, before sending symbol to + * the o.g. symbol-requester + */ + p_psm->pop_ssm(); + + p_psm->on_parsed_symbol(std::string_view(tk.text())); + } + + void + DExpectSymbolSsm::on_def_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectSymbolSsm::on_def_token", + tk, + this->get_expect_str()); + } + + void + DExpectSymbolSsm::on_if_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectSymbolSsm::on_if_token", + tk, + this->get_expect_str()); + } + + void + DExpectSymbolSsm::on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol("DExpectSymbolSsm::on_parsed_symbol", + sym, + this->get_expect_str()); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectSymbolSsm.cpp */ diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 2922dd7f..cca208f6 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -109,6 +109,15 @@ namespace xo { break; } } + + void + DExprSeqState::on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol("DExprSeqState::on_parsed_symbol", + sym, + this->get_expect_str()); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index ce85a9e0..2076aa5f 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -34,6 +34,12 @@ ISyntaxStateMachine_Any::_valid // nonconst methods +auto +ISyntaxStateMachine_Any::on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_def_token(Opaque, const Token &, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index bf17c9b5..96020a95 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -16,30 +16,29 @@ namespace xo { namespace scm { auto - ISyntaxStateMachine_DDefineSsm::ssm_type(const DDefineSsm & self) noexcept - -> syntaxstatetype + ISyntaxStateMachine_DDefineSsm::ssm_type(const DDefineSsm & self) noexcept -> syntaxstatetype { return self.ssm_type(); } auto - ISyntaxStateMachine_DDefineSsm::get_expect_str(const DDefineSsm & self) noexcept - -> std::string_view + ISyntaxStateMachine_DDefineSsm::get_expect_str(const DDefineSsm & self) noexcept -> std::string_view { return self.get_expect_str(); } auto - ISyntaxStateMachine_DDefineSsm::on_def_token(DDefineSsm & self, - const Token & tk, - ParserStateMachine * ps_psm) -> void + ISyntaxStateMachine_DDefineSsm::on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { - self.on_def_token(tk, ps_psm); + self.on_parsed_symbol(sym, p_psm); } auto - ISyntaxStateMachine_DDefineSsm::on_if_token(DDefineSsm & self, - const Token & tk, - ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DDefineSsm::on_def_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_def_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::on_if_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_if_token(tk, p_psm); } @@ -47,4 +46,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end ISyntaxStateMachine_DDefineSsm.cpp */ +/* end ISyntaxStateMachine_DDefineSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp new file mode 100644 index 00000000..b2efaab5 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -0,0 +1,49 @@ +/** @file ISyntaxStateMachine_DExpectSymbolSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectSymbolSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectSymbolSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectSymbolSsm::ssm_type(const DExpectSymbolSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectSymbolSsm::get_expect_str(const DExpectSymbolSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExpectSymbolSsm::on_def_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_def_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectSymbolSsm::on_if_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_if_token(tk, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectSymbolSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index a3abc520..2279ea88 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -28,16 +28,17 @@ namespace xo { } auto - ISyntaxStateMachine_DExprSeqState::on_def_token(DExprSeqState & self, - const Token & tk, - ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExprSeqState::on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExprSeqState::on_def_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_def_token(tk, p_psm); } auto - ISyntaxStateMachine_DExprSeqState::on_if_token(DExprSeqState & self, - const Token & tk, - ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExprSeqState::on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_if_token(tk, p_psm); } @@ -45,4 +46,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end ISyntaxStateMachine_DExprSeqState.cpp */ +/* end ISyntaxStateMachine_DExprSeqState.cpp */ \ No newline at end of file diff --git a/src/reader2/ParserStack.cpp b/src/reader2/ParserStack.cpp index 5b416c54..ba39517d 100644 --- a/src/reader2/ParserStack.cpp +++ b/src/reader2/ParserStack.cpp @@ -10,21 +10,35 @@ namespace xo { using xo::facet::typeseq; namespace scm { - ParserStack::ParserStack(obj ssm, + ParserStack::ParserStack(DArena::Checkpoint ckp, + obj ssm, ParserStack * parent) - : ssm_{ssm}, parent_{parent} + : ckp_{ckp}, ssm_{ssm}, parent_{parent} {} ParserStack * ParserStack::push(ParserStack * stack, - obj mm, + DArena & mm, obj ssm) { + DArena::Checkpoint ckp = mm.checkpoint(); + void * mem = mm.alloc(typeseq::id(), sizeof(ParserStack)); - return new (mem) ParserStack(ssm, stack); + return new (mem) ParserStack(ckp, ssm, stack); + } + + ParserStack * + ParserStack::pop(ParserStack * stack, + DArena & mm) + { + assert(stack); + + mm.restore(stack->ckp()); + + return stack->parent(); } } /*namespace scm*/ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 25765466..c05ab217 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -46,9 +46,7 @@ namespace xo { assert(stack_ == nullptr); - auto alloc = with_facet::mkobj(&parser_alloc_); - - this->stack_ = ParserStack::push(nullptr /*stack*/, alloc, ssm); + this->stack_ = ParserStack::push(nullptr /*stack*/, parser_alloc_, ssm); this->parser_alloc_ckp_ = parser_alloc_.checkpoint(); } @@ -59,9 +57,17 @@ namespace xo { // note: using parser_alloc_ for parser stack, since stacklike behavior - auto alloc = with_facet::mkobj(&parser_alloc_); + this->stack_ = ParserStack::push(stack_, parser_alloc_, ssm); + } - this->stack_ = ParserStack::push(stack_, alloc, ssm); + void + ParserStateMachine::pop_ssm() + { + scope log(XO_DEBUG(debug_flag_)); + + assert(this->stack_); + + this->stack_ = ParserStack::pop(stack_, parser_alloc_); } void @@ -81,6 +87,16 @@ namespace xo { this->parser_alloc_.restore(parser_alloc_ckp_); } + void + ParserStateMachine::on_parsed_symbol(std::string_view sym) + { + scope log(XO_DEBUG(debug_flag_), xtag("sym", sym)); + + assert(stack_); + + this->stack_->top().on_parsed_symbol(sym, this); + } + void ParserStateMachine::on_token(const Token & tk) { @@ -194,6 +210,29 @@ namespace xo { this->capture_error(ssm_name, errmsg); } + + void + ParserStateMachine::illegal_input_on_symbol(std::string_view ssm_name, + std::string_view sym, + std::string_view expect_str) + { + // TODO: + // - want to write error message using DArena + // - need something like log_streambuf and/or tostr() that's arena-aware + + auto errmsg_string = tostr("Unexpected symbol for parsing state", + xtag("symbol", sym), + xtag("expecting", expect_str), + xtag("ssm", ssm_name), + xtag("via", "ParserStateMachine::illegal_input_on_symbol")); + + assert(expr_alloc_); + + auto errmsg = DString::from_view(*expr_alloc_, + std::string_view(errmsg_string)); + + this->capture_error(ssm_name, errmsg); + } } /*namespace scm*/ } /*namespace xo*/ From 9d4b50ede4d4b94fd78309ef58cede5b5fd8e603 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 19 Jan 2026 11:33:14 -0500 Subject: [PATCH 082/342] xo-tokenizer2: cosmetic / minor --- src/tokenizer2/Tokenizer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index 4fa98a97..7076a95d 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -595,10 +595,13 @@ namespace xo { tk_text.clear(); } + // TOOD: report tk_text as span, + // but must pin / unpin + /* input.prefix(0): * require caller preserves current input line until it's entirely exhausted */ - return result_type(token_type(tk_type, std::move(tk_text)), + return result_type(Token(tk_type, std::move(tk_text)), p_input_state->current_line().prefix(0)); } /*assemble_token*/ From 844b1519ef7f43ac9eebc74a016d841fb6952db4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 19 Jan 2026 11:33:27 -0500 Subject: [PATCH 083/342] xo-reader2: register DDefineSsm + DExpectSymbolSsm facets --- src/reader2/reader2_register_facets.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index e5b1d157..988f41ab 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -6,6 +6,8 @@ #include "reader2_register_facets.hpp" #include +#include +#include #include #include @@ -22,8 +24,12 @@ namespace xo { scope log(XO_DEBUG(true)); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); log && log(xtag("DExprSeqState.tseq", typeseq::id())); + log && log(xtag("DDefineSsm.tseq", typeseq::id())); + log && log(xtag("DExpectSymbolSsm.tseq", typeseq::id())); return true; } From 19b6caa89d2bc6aa3fa4fe5e2210b1227924c4ab Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 19 Jan 2026 21:25:30 -0500 Subject: [PATCH 084/342] xo-reader2 xo-expresion2: work on define-expressions [WIP] --- idl/SyntaxStateMachine.json5 | 9 +++ include/xo/reader2/DDefineSsm.hpp | 27 +++++++- include/xo/reader2/DExprSeqState.hpp | 5 ++ include/xo/reader2/ParserResult.hpp | 2 + include/xo/reader2/ParserStateMachine.hpp | 17 +++-- include/xo/reader2/SchematikaParser.hpp | 2 +- include/xo/reader2/SyntaxStateMachine.hpp | 2 +- .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 8 ++- .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 5 +- .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 8 ++- .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 8 ++- .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 8 ++- .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 9 ++- .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 9 ++- src/reader2/DDefineSsm.cpp | 69 ++++++++++++++++--- src/reader2/DExprSeqState.cpp | 37 +++++++++- src/reader2/ISyntaxStateMachine_Any.cpp | 8 ++- .../ISyntaxStateMachine_DDefineSsm.cpp | 11 ++- .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 11 ++- .../ISyntaxStateMachine_DExprSeqState.cpp | 11 ++- src/reader2/ParserStateMachine.cpp | 26 +++++-- src/reader2/SchematikaParser.cpp | 6 +- utest/SchematikaParser.test.cpp | 32 ++++++--- 23 files changed, 263 insertions(+), 67 deletions(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 2be2a98d..28811512 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -43,6 +43,15 @@ }, ], nonconst_methods: [ + { + name: "on_symbol_token", + doc: ["operate state machine for incoming symbol-token @p tk"], + return_type: "void", + args: [ + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_def_token", doc: ["update state machine for incoming define-keyword-token @p tk"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 37ccc23d..3bc042c1 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -8,6 +8,8 @@ #include "ParserStateMachine.hpp" //#include "SyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" +#include +#include #include namespace xo { @@ -69,21 +71,29 @@ namespace xo { **/ class DDefineSsm { public: + using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; public: /** @defgroup scm-define-ssm-facet constructors **/ ///@{ - DDefineSsm(); + /** constructor; using @p def_expr for initial expression scaffold **/ + explicit DDefineSsm(DDefineExpr * def_expr); - /** create instance using memory from @p parser_mm **/ - static DDefineSsm * make(DArena & parser_mm); + /** create instance using memory from @p parser_mm. + * Initial expression scaffold @p def_expr + **/ + static DDefineSsm * make(DArena & parser_mm, + DDefineExpr * def_expr); /** start nested parser for a define-expression, * on top of parser state machine @p p_psm + * Use @p parser_mm to allocate syntax state machines, + * and @p expr_mm to allocate expressions **/ static void start(DArena & parser_mm, + obj expr_mm, ParserStateMachine * p_psm); ///@} @@ -98,6 +108,12 @@ namespace xo { **/ std::string_view get_expect_str() const noexcept; + /** operate state machine for this syntax on incoming symbol-token @p tk + * with overall parser state in @p p_psm + **/ + void on_symbol_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming token @p tk, * overall parser state in @p p_psm **/ @@ -121,6 +137,11 @@ namespace xo { private: /** identify define-expression state **/ defexprstatetype defstate_; + + /** scaffolded define-expression. + * This will eventually be the output of this ssm + **/ + obj def_expr_; }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 1b611aaf..bef2bd68 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -56,6 +56,11 @@ namespace xo { **/ std::string_view get_expect_str() const noexcept; + /** operate state machine for this syntax on incoming symbol token @p tk + * with overall parser state in @p p_psm + **/ + void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/ParserResult.hpp b/include/xo/reader2/ParserResult.hpp index e179d4bd..39f9c2d1 100644 --- a/include/xo/reader2/ParserResult.hpp +++ b/include/xo/reader2/ParserResult.hpp @@ -50,6 +50,8 @@ namespace xo { std::string_view error_src_fn_; const DString * error_description_ = nullptr; }; + + } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index f5293bff..5a7a833f 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -6,6 +6,7 @@ #pragma once #include "ParserResult.hpp" +#include #include #include #include @@ -32,14 +33,14 @@ namespace xo { public: ParserStateMachine(const ArenaConfig & config, - obj * expr_alloc); + obj expr_alloc); /** @defgroup scm-parserstatemachine-accessors accessor methods **/ ///@{ bool debug_flag() const noexcept { return debug_flag_; } ParserStack * stack() const noexcept { return stack_; } - obj * expr_alloc() const noexcept { return expr_alloc_; } + obj expr_alloc() const noexcept { return expr_alloc_; } const ParserResult & result() const noexcept { return result_; } /** true iff state machine is currently idle (at top-level) **/ @@ -65,6 +66,9 @@ namespace xo { /** pop syntax state machine from top of @ref stack_ **/ void pop_ssm(); + /** add variable to current local environment (innermost lexical scope) **/ + void upsert_var(DVariable * var); + /** reset result to none **/ void reset_result(); @@ -84,10 +88,13 @@ namespace xo { **/ void on_token(const Token & tk); - /** update state for incoming define-token @p tk **/ + /** operate state machine for incoming symbol-token @p tk **/ + void on_symbol_token(const Token & tk); + + /** operate state machine for incoming define-token @p tk **/ void on_def_token(const Token & tk); - /** update state for incoming if-token @p tk **/ + /** operate state machine for incoming if-token @p tk **/ void on_if_token(const Token & tk); ///@} @@ -153,7 +160,7 @@ namespace xo { * scenario, where top-level Expressions can be discarded * once compiled. **/ - obj * expr_alloc_ = nullptr; + obj expr_alloc_; /** current output from parser **/ ParserResult result_; diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 075fb4fc..2f7d6d95 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -167,7 +167,7 @@ namespace xo { * @p debug_flag true to enable debug logging **/ SchematikaParser(const ArenaConfig & config, - obj * expr_alloc, + obj expr_alloc, bool debug_flag); bool debug_flag() const { return debug_flag_; } diff --git a/include/xo/reader2/SyntaxStateMachine.hpp b/include/xo/reader2/SyntaxStateMachine.hpp index 56a8271b..deda9e1d 100644 --- a/include/xo/reader2/SyntaxStateMachine.hpp +++ b/include/xo/reader2/SyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for facet .hpp file: diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index b181fd8d..4f428be5 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -54,12 +54,14 @@ public: virtual std::string_view get_expect_str(Copaque data) const noexcept = 0; // nonconst methods - /** update stat machine for incoming parsed symbol @p sym **/ - virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; + /** operate state machine for incoming symbol-token @p tk **/ + virtual void on_symbol_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming define-keyword-token @p tk **/ virtual void on_def_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming if-keyword-token @p tk **/ virtual void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; + /** update stat machine for incoming parsed symbol @p sym **/ + virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; ///@} }; /*ASyntaxStateMachine*/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 046adacb..23b90621 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -59,9 +59,10 @@ namespace scm { [[noreturn]] std::string_view get_expect_str(Copaque) const noexcept override { _fatal(); } // nonconst methods - [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; + [[noreturn]] void on_symbol_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_def_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_if_token(Opaque, const Token &, ParserStateMachine *) override; + [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index cfb38fa7..d420ba16 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DDefineSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -53,12 +53,14 @@ namespace xo { static std::string_view get_expect_str(const DDefineSsm & self) noexcept; // non-const methods - /** update stat machine for incoming parsed symbol @p sym **/ - static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming symbol-token @p tk **/ + static void on_symbol_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming define-keyword-token @p tk **/ static void on_def_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming if-keyword-token @p tk **/ static void on_if_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 44cb6de4..ba8eb0b9 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExpectSymbolSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -53,12 +53,14 @@ namespace xo { static std::string_view get_expect_str(const DExpectSymbolSsm & self) noexcept; // non-const methods - /** update stat machine for incoming parsed symbol @p sym **/ - static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming symbol-token @p tk **/ + static void on_symbol_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming define-keyword-token @p tk **/ static void on_def_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming if-keyword-token @p tk **/ static void on_if_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index 4da00f95..c1e61b40 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExprSeqState.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -53,12 +53,14 @@ namespace xo { static std::string_view get_expect_str(const DExprSeqState & self) noexcept; // non-const methods - /** update stat machine for incoming parsed symbol @p sym **/ - static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming symbol-token @p tk **/ + static void on_symbol_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming define-keyword-token @p tk **/ static void on_def_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming if-keyword-token @p tk **/ static void on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 7de32e25..5a8e2fe3 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -50,8 +50,8 @@ namespace scm { } // non-const methods - void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) override { - return I::on_parsed_symbol(_dcast(data), sym, p_psm); + void on_symbol_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_symbol_token(_dcast(data), tk, p_psm); } void on_def_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_def_token(_dcast(data), tk, p_psm); @@ -59,6 +59,9 @@ namespace scm { void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_if_token(_dcast(data), tk, p_psm); } + void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) override { + return I::on_parsed_symbol(_dcast(data), sym, p_psm); + } ///@} diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index f35f4e72..786c83d0 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -55,8 +55,8 @@ public: } // non-const methods (still const in router!) - void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { - return O::iface()->on_parsed_symbol(O::data(), sym, p_psm); + void on_symbol_token(const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_symbol_token(O::data(), tk, p_psm); } void on_def_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_def_token(O::data(), tk, p_psm); @@ -64,6 +64,9 @@ public: void on_if_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_if_token(O::data(), tk, p_psm); } + void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { + return O::iface()->on_parsed_symbol(O::data(), sym, p_psm); + } ///@} /** @defgroup scm-syntaxstatemachine-member-vars **/ diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 8ac919e4..adf9f429 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -1,9 +1,10 @@ -/** @file DDefineSsm.cpp + /** @file DDefineSsm.cpp * * @author Roland Conybeare, Jan 2026 **/ #include "DDefineSsm.hpp" +#include "DExpectSymbolSsm.hpp" #include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" #ifdef NOT_YET @@ -328,28 +329,33 @@ namespace xo { //////////////////////////////////////////////////////////////// - DDefineSsm::DDefineSsm() - : defstate_{defexprstatetype::def_0} + DDefineSsm::DDefineSsm(DDefineExpr * def_expr) + : defstate_{defexprstatetype::def_0}, + def_expr_{def_expr} {} DDefineSsm * - DDefineSsm::make(DArena & mm) + DDefineSsm::make(DArena & mm, + DDefineExpr * def_expr) { void * mem = mm.alloc(typeseq::id(), sizeof(DDefineSsm)); - return new (mem) DDefineSsm(); + return new (mem) DDefineSsm(def_expr); } void DDefineSsm::start(DArena & mm, + obj expr_mm, ParserStateMachine * p_psm) { //scope log(XO_DEBUG(p_psm->debug_flag())); assert(p_psm->stack()); - DDefineSsm * define_ssm = DDefineSsm::make(mm); + DDefineExpr * def_expr = DDefineExpr::make_empty(expr_mm); + + DDefineSsm * define_ssm = DDefineSsm::make(mm, def_expr); obj ssm = with_facet::mkobj(define_ssm); @@ -387,7 +393,7 @@ namespace xo { case defexprstatetype::def_0: case defexprstatetype::n_defexprstatetype: assert(false); // impossible - return nullptr; + return "impossible!?"; case defexprstatetype::def_1: return "symbol"; case defexprstatetype::def_2: @@ -409,11 +415,57 @@ namespace xo { DDefineSsm::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { + if (this->defstate_ == defexprstatetype::def_1) { + this->defstate_ = defexprstatetype::def_2; + + def_expr_.data()->assign_lhs_name(sym); + + // if this is a genuine top-level define (i.e. nesting level = 0), + // then we need to upsert so we can refer to rhs later. + // + // In other contexts (e.g. body-of-lambda) will be rewriting + // { + // def y = foo(x,x); + // bar(y,y); + // } + // into something like + // { + // (lambda (y123) bar(y123,y123))(foo(x,x)); + // } + // + // This works in the body of lambda, because we don't evaluate anything + // until lambda definition is complete. + // + // For interactive top-level defs we want to evaluate as we go, + // so need incremental bindings. + + if (p_psm->is_at_toplevel()) { + /** remember variable binding in current lexical context **/ + p_psm->upsert_var(def_expr_.data()->lhs()); + } + + return; + } + p_psm->illegal_input_on_symbol("DDefineSsm::on_parsed_symbol", sym, this->get_expect_str()); } + void + DDefineSsm::on_symbol_token(const Token & tk, + ParserStateMachine * p_psm) + { + // note: + // in state def_1, DDefineSsm learns symbol via .on_parsed_symbol(). + // symbol token arriving here means encountered symbol while + // in some other, which can't happen for valid Schematika input + + p_psm->illegal_input_on_token("DDefineSssm::on_symbol_token", + tk, + this->get_expect_str()); + } + void DDefineSsm::on_def_token(const Token & tk, ParserStateMachine * p_psm) @@ -421,7 +473,8 @@ namespace xo { if (this->defstate_ == defexprstatetype::def_0) { this->defstate_ = defexprstatetype::def_1; - // expect_symbol_xs::start(p_psm->parser_alloc(), p_psm); + DExpectSymbolSsm::start(p_psm->parser_alloc(), p_psm); + return; } p_psm->illegal_input_on_token("DDefineSsm::on_define_token", diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index cca208f6..4afb9608 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -74,13 +74,48 @@ namespace xo { return "impossible-DExprSeqState::get_expr_str"; } + void + DExprSeqState::on_symbol_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (seqtype_) { + case exprseqtype::toplevel_interactive: + { +#ifdef NOT_YET + obj var = p_psm->lookup_var(tk.text()); + + if (var) { + DProgressSsm::start(var, p_psm); + } else { + p_psm->unknown_variable_error("DExprSeqState::on_symbol_token", + tk, + this->get_expect_str(), + p_psm); + } +#endif + } + break; + case exprseqtype::toplevel_batch: + break; + case exprseqtype::N: + assert(false); // unreachable + break; + } + + p_psm->illegal_input_on_token("DExprSeqState::on_symbol_token", + tk, + this->get_expect_str()); + } + void DExprSeqState::on_def_token(const Token & tk, ParserStateMachine * p_psm) { (void)tk; - DDefineSsm::start(p_psm->parser_alloc(), p_psm); + DDefineSsm::start(p_psm->parser_alloc(), + p_psm->expr_alloc(), + p_psm); /* keyword 'def' introduces a definition: * def pi : f64 = 3.14159265 diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 2076aa5f..44effd57 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -35,7 +35,7 @@ ISyntaxStateMachine_Any::_valid // nonconst methods auto -ISyntaxStateMachine_Any::on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) -> void +ISyntaxStateMachine_Any::on_symbol_token(Opaque, const Token &, ParserStateMachine *) -> void { _fatal(); } @@ -52,6 +52,12 @@ ISyntaxStateMachine_Any::on_if_token(Opaque, const Token &, ParserStateMachine * _fatal(); } +auto +ISyntaxStateMachine_Any::on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) -> void +{ + _fatal(); +} + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index 96020a95..34bd4569 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DDefineSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -28,9 +28,9 @@ namespace xo { } auto - ISyntaxStateMachine_DDefineSsm::on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DDefineSsm::on_symbol_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_symbol(sym, p_psm); + self.on_symbol_token(tk, p_psm); } auto ISyntaxStateMachine_DDefineSsm::on_def_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void @@ -42,6 +42,11 @@ namespace xo { { self.on_if_token(tk, p_psm); } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index b2efaab5..f00b9c2f 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExpectSymbolSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -28,9 +28,9 @@ namespace xo { } auto - ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExpectSymbolSsm::on_symbol_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_symbol(sym, p_psm); + self.on_symbol_token(tk, p_psm); } auto ISyntaxStateMachine_DExpectSymbolSsm::on_def_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void @@ -42,6 +42,11 @@ namespace xo { { self.on_if_token(tk, p_psm); } + auto + ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index 2279ea88..47c06ba3 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExprSeqState.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -28,9 +28,9 @@ namespace xo { } auto - ISyntaxStateMachine_DExprSeqState::on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExprSeqState::on_symbol_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_symbol(sym, p_psm); + self.on_symbol_token(tk, p_psm); } auto ISyntaxStateMachine_DExprSeqState::on_def_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void @@ -42,6 +42,11 @@ namespace xo { { self.on_if_token(tk, p_psm); } + auto + ISyntaxStateMachine_DExprSeqState::on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index c05ab217..2e61be95 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -17,7 +17,7 @@ namespace xo { namespace scm { ParserStateMachine::ParserStateMachine(const ArenaConfig & config, - obj * expr_alloc) + obj expr_alloc) : parser_alloc_{DArena::map(config)}, expr_alloc_{expr_alloc}, debug_flag_{config.debug_flag_} @@ -70,6 +70,13 @@ namespace xo { this->stack_ = ParserStack::pop(stack_, parser_alloc_); } + void + ParserStateMachine::upsert_var(DVariable * var) + { + scope log(XO_DEBUG(true), "stub impl"); + log && log(xtag("var", std::string_view(*(var->name())))); + } + void ParserStateMachine::reset_result() { @@ -111,6 +118,10 @@ namespace xo { } switch (tk.tk_type()) { + case tokentype::tk_symbol: + this->on_symbol_token(tk); + break; + case tokentype::tk_def: this->on_def_token(tk); break; @@ -125,7 +136,6 @@ namespace xo { case tokentype::tk_i64: case tokentype::tk_f64: case tokentype::tk_string: - case tokentype::tk_symbol: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: @@ -165,6 +175,14 @@ namespace xo { } } + void + ParserStateMachine::on_symbol_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + stack_->top().on_symbol_token(tk, this); + } + void ParserStateMachine::on_def_token(const Token & tk) { @@ -205,7 +223,7 @@ namespace xo { assert(expr_alloc_); - auto errmsg = DString::from_view(*expr_alloc_, + auto errmsg = DString::from_view(expr_alloc_, std::string_view(errmsg_string)); this->capture_error(ssm_name, errmsg); @@ -228,7 +246,7 @@ namespace xo { assert(expr_alloc_); - auto errmsg = DString::from_view(*expr_alloc_, + auto errmsg = DString::from_view(expr_alloc_, std::string_view(errmsg_string)); this->capture_error(ssm_name, errmsg); diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 47f6918b..442da75e 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -19,7 +19,7 @@ namespace xo { // ----- SchematikaParser ----- SchematikaParser::SchematikaParser(const ArenaConfig & config, - obj * expr_alloc, + obj expr_alloc, bool debug_flag) : psm_{config, expr_alloc}, debug_flag_{debug_flag} @@ -38,13 +38,13 @@ namespace xo { void SchematikaParser::begin_interactive_session() { - DExprSeqState::establish_interactive(*(psm_.expr_alloc()), &psm_); + DExprSeqState::establish_interactive(psm_.expr_alloc(), &psm_); } void SchematikaParser::begin_batch_session() { - DExprSeqState::establish_batch(*(psm_.expr_alloc()), &psm_); + DExprSeqState::establish_batch(psm_.expr_alloc(), &psm_); } const ParserResult & diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index b333ff0c..6100392a 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -27,7 +27,7 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); - SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, expr_alloc, false /*debug_flag*/); REQUIRE(parser.debug_flag() == false); REQUIRE(parser.is_at_toplevel() == true); @@ -42,7 +42,7 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); - SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, expr_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -60,7 +60,7 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); - SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, expr_alloc, false /*debug_flag*/); parser.begin_batch_session(); @@ -78,20 +78,30 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); - SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, expr_alloc, false /*debug_flag*/); parser.begin_batch_session(); - auto & result = parser.on_token(Token::def_token()); + { + auto & result = parser.on_token(Token::def_token()); + + // after begin_interactive_session, parser has toplevel exprseq + // but is still "at toplevel" in the sense of ready for input + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("foo")); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(result.is_error()); + } // define-expressions not properly implemented - // after begin_interactive_session, parser has toplevel exprseq - // but is still "at toplevel" in the sense of ready for input - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(result.is_error()); - REQUIRE(result.error_description()); + //REQUIRE(result.error_description()); } TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]") @@ -103,7 +113,7 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); - SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, expr_alloc, false /*debug_flag*/); parser.begin_interactive_session(); From 535f48e20260ac410e8d1e2421144d5876708b97 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 19 Jan 2026 23:18:30 -0500 Subject: [PATCH 085/342] xo-reader2: bugfix in DDefineExpr --- utest/SchematikaParser.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 6100392a..194a6d13 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -95,7 +95,7 @@ namespace xo { auto & result = parser.on_token(Token::symbol_token("foo")); REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(result.is_error()); + REQUIRE(result.is_incomplete()); } // define-expressions not properly implemented From 9ab828059b8a0992d9c7c55428c3d9600c1fc8cb Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 19 Jan 2026 23:38:14 -0500 Subject: [PATCH 086/342] xo-reader2: + StringTable in ParserStringTable --- include/xo/reader2/ParserStateMachine.hpp | 7 +++++++ include/xo/reader2/SchematikaParser.hpp | 1 + src/reader2/ParserStateMachine.cpp | 5 ++++- src/reader2/SchematikaParser.cpp | 3 ++- utest/SchematikaParser.test.cpp | 10 +++++----- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 5a7a833f..fb276bd0 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -7,6 +7,7 @@ #include "ParserResult.hpp" #include +#include #include #include #include @@ -30,9 +31,11 @@ namespace xo { using AAllocator = xo::mm::AAllocator; using ArenaConfig = xo::mm::ArenaConfig; using DArena = xo::mm::DArena; + using size_type = std::size_t; public: ParserStateMachine(const ArenaConfig & config, + size_type max_stringtable_capacity, obj expr_alloc); /** @defgroup scm-parserstatemachine-accessors accessor methods **/ @@ -129,6 +132,10 @@ namespace xo { private: + /** Table containing interned strings + symbols. + **/ + StringTable stringtable_; + /** Arena for internal parsing stack. * Must be owned exclusively because destructively * modified as parser completes parsing of each sub-expression diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 2f7d6d95..81115239 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -167,6 +167,7 @@ namespace xo { * @p debug_flag true to enable debug logging **/ SchematikaParser(const ArenaConfig & config, + size_t max_stringtable_capacity, obj expr_alloc, bool debug_flag); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 2e61be95..1766f652 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -17,11 +17,14 @@ namespace xo { namespace scm { ParserStateMachine::ParserStateMachine(const ArenaConfig & config, + size_type max_stringtable_capacity, obj expr_alloc) - : parser_alloc_{DArena::map(config)}, + : stringtable_{max_stringtable_capacity}, + parser_alloc_{DArena::map(config)}, expr_alloc_{expr_alloc}, debug_flag_{config.debug_flag_} { + } bool diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 442da75e..ac2d4520 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -19,9 +19,10 @@ namespace xo { // ----- SchematikaParser ----- SchematikaParser::SchematikaParser(const ArenaConfig & config, + size_t max_stringtable_capacity, obj expr_alloc, bool debug_flag) - : psm_{config, expr_alloc}, + : psm_{config, max_stringtable_capacity, expr_alloc}, debug_flag_{debug_flag} { } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 194a6d13..259336cf 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -27,7 +27,7 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); - SchematikaParser parser(config, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); REQUIRE(parser.debug_flag() == false); REQUIRE(parser.is_at_toplevel() == true); @@ -42,7 +42,7 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); - SchematikaParser parser(config, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -60,7 +60,7 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); - SchematikaParser parser(config, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); parser.begin_batch_session(); @@ -78,7 +78,7 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); - SchematikaParser parser(config, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); parser.begin_batch_session(); @@ -113,7 +113,7 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); - SchematikaParser parser(config, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); parser.begin_interactive_session(); From 6e7524a73089d07fb56c5a5ecea4edfcb4fd28d5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 00:08:51 -0500 Subject: [PATCH 087/342] xo-reader2: intern for DDefineExpr lhs symbol --- include/xo/reader2/ParserStateMachine.hpp | 4 ++++ src/reader2/DDefineSsm.cpp | 7 +++++-- src/reader2/ParserStateMachine.cpp | 6 ++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index fb276bd0..b333dd51 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -69,6 +69,10 @@ namespace xo { /** pop syntax state machine from top of @ref stack_ **/ void pop_ssm(); + /** get unique string copy of @p str. Idempotent for each @p str. + **/ + const DUniqueString * intern_string(std::string_view str); + /** add variable to current local environment (innermost lexical scope) **/ void upsert_var(DVariable * var); diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index adf9f429..eabc1868 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -412,12 +412,15 @@ namespace xo { } void - DDefineSsm::on_parsed_symbol(std::string_view sym, + DDefineSsm::on_parsed_symbol(std::string_view sym_name, ParserStateMachine * p_psm) { if (this->defstate_ == defexprstatetype::def_1) { this->defstate_ = defexprstatetype::def_2; + const DUniqueString * sym + = p_psm->intern_string(sym_name); + def_expr_.data()->assign_lhs_name(sym); // if this is a genuine top-level define (i.e. nesting level = 0), @@ -448,7 +451,7 @@ namespace xo { } p_psm->illegal_input_on_symbol("DDefineSsm::on_parsed_symbol", - sym, + sym_name, this->get_expect_str()); } diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 1766f652..ca8bba8b 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -73,6 +73,12 @@ namespace xo { this->stack_ = ParserStack::pop(stack_, parser_alloc_); } + const DUniqueString * + ParserStateMachine::intern_string(std::string_view str) + { + return stringtable_.intern(str); + } + void ParserStateMachine::upsert_var(DVariable * var) { From a836c72a72f1e89d8c89895cc7a278dc8f64cdfa Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 00:57:34 -0500 Subject: [PATCH 088/342] xo-reader2: + IPrintable+DExprSeqState --- CMakeLists.txt | 12 ++++ idl/IPrintable_DExprSeqState.json5 | 13 ++++ include/xo/reader2/DExprSeqState.hpp | 15 +++++ .../reader2/ssm/IPrintable_DExprSeqState.hpp | 62 +++++++++++++++++++ src/reader2/CMakeLists.txt | 1 + src/reader2/DExprSeqState.cpp | 24 +++++++ src/reader2/IPrintable_DExprSeqState.cpp | 28 +++++++++ 7 files changed, 155 insertions(+) create mode 100644 idl/IPrintable_DExprSeqState.json5 create mode 100644 include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp create mode 100644 src/reader2/IPrintable_DExprSeqState.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 17c3aac7..7017425e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,18 @@ xo_add_genfacetimpl( OUTPUT_CPP_DIR src/reader2 ) +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-exprseqstate + FACET_PKG xo_printable2 + FACET Printable + REPR ExprSeqState + INPUT idl/IPrintable_DExprSeqState.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-definessm diff --git a/idl/IPrintable_DExprSeqState.json5 b/idl/IPrintable_DExprSeqState.json5 new file mode 100644 index 00000000..d0315c58 --- /dev/null +++ b/idl/IPrintable_DExprSeqState.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExprSeqState", + using_doxygen: true, + repr: "DExprSeqState", + doc: [ "implement APrintable for DExprSeqState" ], +} diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index bef2bd68..32eaef0f 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -25,6 +25,13 @@ namespace xo { N }; + const char * exprseqtype_descr(exprseqtype x); + + inline std::ostream & operator<<(std::ostream & os, exprseqtype x) { + os << exprseqtype_descr(x); + return os; + } + /** @class DExprSeqState * @brief state machine for parsing a sequence of expression * @@ -33,6 +40,7 @@ namespace xo { class DExprSeqState { public: using AAllocator = xo::mm::AAllocator; + using ppindentinfo = xo::print::ppindentinfo; public: explicit DExprSeqState(exprseqtype ty); @@ -78,6 +86,13 @@ namespace xo { void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm); ///@} + /** @defgroup scm-exprseq-printable-facet printable facet methods **/ + ///@{ + + /** pretty-printing driver; combine layout+printing **/ + bool pretty(const ppindentinfo & ppii) const; + + ///@} private: /** sequence type. accept rvalue expressions when diff --git a/include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp b/include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp new file mode 100644 index 00000000..87d85fd7 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExprSeqState.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExprSeqState.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExprSeqState.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExprSeqState.hpp" + +namespace xo { namespace scm { class IPrintable_DExprSeqState; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExprSeqState + **/ + class IPrintable_DExprSeqState { + public: + /** @defgroup scm-printable-dexprseqstate-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexprseqstate-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExprSeqState & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 655ac7e9..3a04f430 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -13,6 +13,7 @@ set(SELF_SRCS DExprSeqState.cpp ISyntaxStateMachine_DExprSeqState.cpp + IPrintable_DExprSeqState.cpp DDefineSsm.cpp ISyntaxStateMachine_DDefineSsm.cpp diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 4afb9608..e994bbf1 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -13,6 +13,21 @@ namespace xo { using xo::reflect::typeseq; namespace scm { + const char * + exprseqtype_descr(exprseqtype x) + { + switch (x) { + case exprseqtype::toplevel_interactive: + return "toplevel-interactive"; + case exprseqtype::toplevel_batch: + return "toplevel-batch"; + case exprseqtype::N: + break; + } + + return "exprseqtype?"; + } + DExprSeqState::DExprSeqState(exprseqtype ty) : seqtype_{ty} {} @@ -153,6 +168,15 @@ namespace xo { sym, this->get_expect_str()); } + + bool + DExprSeqState::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct + (ppii, + "DExprSeqState", + refrtag("seqtype", seqtype_)); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/IPrintable_DExprSeqState.cpp b/src/reader2/IPrintable_DExprSeqState.cpp new file mode 100644 index 00000000..f751b963 --- /dev/null +++ b/src/reader2/IPrintable_DExprSeqState.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExprSeqState.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExprSeqState.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExprSeqState.json5] +**/ + +#include "ssm/IPrintable_DExprSeqState.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExprSeqState::pretty(const DExprSeqState & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExprSeqState.cpp */ \ No newline at end of file From 1bca806bf305d06b1c465995087c1ed71119e542 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 01:07:21 -0500 Subject: [PATCH 089/342] xo-reader2: + IPrintable+DExpectSymbolSsm --- CMakeLists.txt | 18 ++++++ idl/IPrintable_DExpectSymbolSsm.json5 | 13 ++++ include/xo/reader2/DExpectSymbolSsm.hpp | 7 +++ .../ssm/IPrintable_DExpectSymbolSsm.hpp | 62 +++++++++++++++++++ src/reader2/CMakeLists.txt | 1 + src/reader2/DExpectSymbolSsm.cpp | 10 +++ src/reader2/IPrintable_DExpectSymbolSsm.cpp | 28 +++++++++ 7 files changed, 139 insertions(+) create mode 100644 idl/IPrintable_DExpectSymbolSsm.json5 create mode 100644 include/xo/reader2/ssm/IPrintable_DExpectSymbolSsm.hpp create mode 100644 src/reader2/IPrintable_DExpectSymbolSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7017425e..85dabbf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,8 @@ xo_add_genfacet( OUTPUT_CPP_DIR src/reader2 ) +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-exprseqstate @@ -56,6 +58,8 @@ xo_add_genfacetimpl( OUTPUT_CPP_DIR src/reader2 ) +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-definessm @@ -68,6 +72,8 @@ xo_add_genfacetimpl( OUTPUT_CPP_DIR src/reader2 ) +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectsymbolssm @@ -80,6 +86,18 @@ xo_add_genfacetimpl( OUTPUT_CPP_DIR src/reader2 ) +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expectsymbolssm + FACET_PKG xo_printable2 + FACET Printable + REPR ExpectSymbolSsm + INPUT idl/IPrintable_DExpectSymbolSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + # ---------------------------------------------------------------- # shared library diff --git a/idl/IPrintable_DExpectSymbolSsm.json5 b/idl/IPrintable_DExpectSymbolSsm.json5 new file mode 100644 index 00000000..1d662986 --- /dev/null +++ b/idl/IPrintable_DExpectSymbolSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectSymbolSsm", + using_doxygen: true, + repr: "DExpectSymbolSsm", + doc: [ "implement APrintable for DExpectSymbolSsm" ], +} diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index dadd1300..2ecc556d 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -8,6 +8,7 @@ #include "ParserStateMachine.hpp" //#include "SyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" +#include #include namespace xo { @@ -21,6 +22,7 @@ namespace xo { class DExpectSymbolSsm { public: using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; public: DExpectSymbolSsm(); @@ -83,7 +85,12 @@ namespace xo { ///@} + /** @defgroup scm-expectsymbol-printable-facet printable facet methods **/ + ///@{ + bool pretty(const ppindentinfo & ppii) const; + + ///@} }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/ssm/IPrintable_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectSymbolSsm.hpp new file mode 100644 index 00000000..6e63383b --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DExpectSymbolSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectSymbolSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectSymbolSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectSymbolSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectSymbolSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectSymbolSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectSymbolSsm + **/ + class IPrintable_DExpectSymbolSsm { + public: + /** @defgroup scm-printable-dexpectsymbolssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpectsymbolssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectSymbolSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 3a04f430..0ad81a49 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -20,6 +20,7 @@ set(SELF_SRCS DExpectSymbolSsm.cpp ISyntaxStateMachine_DExpectSymbolSsm.cpp + IPrintable_DExpectSymbolSsm.cpp reader2_register_facets.cpp reader2_register_types.cpp diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 6afe337c..c859528f 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -103,6 +103,16 @@ namespace xo { sym, this->get_expect_str()); } + + bool + DExpectSymbolSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct + (ppii, + "DExpectSymbolSsm" + //refrtag("member", member_) + ); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/IPrintable_DExpectSymbolSsm.cpp b/src/reader2/IPrintable_DExpectSymbolSsm.cpp new file mode 100644 index 00000000..2cef62a7 --- /dev/null +++ b/src/reader2/IPrintable_DExpectSymbolSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectSymbolSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectSymbolSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectSymbolSsm.json5] +**/ + +#include "ssm/IPrintable_DExpectSymbolSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectSymbolSsm::pretty(const DExpectSymbolSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectSymbolSsm.cpp */ \ No newline at end of file From 4e490e697316c05cd588f11c652211985d2f715e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 01:09:56 -0500 Subject: [PATCH 090/342] xo-reader2: register printable facets --- src/reader2/reader2_register_facets.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 988f41ab..67754bb6 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -6,14 +6,20 @@ #include "reader2_register_facets.hpp" #include +#include + #include + #include +#include #include +#include #include #include namespace xo { + using xo::print::APrintable; using xo::facet::FacetRegistry; using xo::facet::typeseq; @@ -24,8 +30,12 @@ namespace xo { scope log(XO_DEBUG(true)); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); log && log(xtag("DExprSeqState.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); From 0a7e8468ae4fb258369907061df5ca9be3fbbe63 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 01:19:47 -0500 Subject: [PATCH 091/342] xo-reader2: + IPrintable+DDefineSsm --- CMakeLists.txt | 12 ++++ idl/IPrintable_DDefineSsm.json5 | 13 ++++ include/xo/reader2/DDefineSsm.hpp | 7 +++ .../xo/reader2/ssm/IPrintable_DDefineSsm.hpp | 62 +++++++++++++++++++ src/reader2/CMakeLists.txt | 1 + src/reader2/DDefineSsm.cpp | 8 +++ src/reader2/IPrintable_DDefineSsm.cpp | 28 +++++++++ src/reader2/reader2_register_facets.cpp | 2 + 8 files changed, 133 insertions(+) create mode 100644 idl/IPrintable_DDefineSsm.json5 create mode 100644 include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp create mode 100644 src/reader2/IPrintable_DDefineSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 85dabbf3..e2ee946b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,18 @@ xo_add_genfacetimpl( OUTPUT_CPP_DIR src/reader2 ) +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-definessm + FACET_PKG xo_printable2 + FACET Printable + REPR DefineSsm + INPUT idl/IPrintable_DDefineSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + # ---------------------------------------------------------------- # note: manual target; generated code committed to git diff --git a/idl/IPrintable_DDefineSsm.json5 b/idl/IPrintable_DDefineSsm.json5 new file mode 100644 index 00000000..e79017f8 --- /dev/null +++ b/idl/IPrintable_DDefineSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DDefineSsm", + using_doxygen: true, + repr: "DDefineSsm", + doc: [ "implement APrintable for DDefineSsm" ], +} diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 3bc042c1..b8444cbe 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -73,6 +73,7 @@ namespace xo { public: using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; public: /** @defgroup scm-define-ssm-facet constructors **/ @@ -133,6 +134,12 @@ namespace xo { ParserStateMachine * p_psm); ///@} + /** @defgroup scm-define-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} private: /** identify define-expression state **/ diff --git a/include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp b/include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp new file mode 100644 index 00000000..dd80b443 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DDefineSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DDefineSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DDefineSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DDefineSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DDefineSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DDefineSsm + **/ + class IPrintable_DDefineSsm { + public: + /** @defgroup scm-printable-ddefinessm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-ddefinessm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DDefineSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 0ad81a49..6b17e3d3 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -17,6 +17,7 @@ set(SELF_SRCS DDefineSsm.cpp ISyntaxStateMachine_DDefineSsm.cpp + IPrintable_DDefineSsm.cpp DExpectSymbolSsm.cpp ISyntaxStateMachine_DExpectSymbolSsm.cpp diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index eabc1868..3ae20286 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -494,6 +494,14 @@ namespace xo { this->get_expect_str()); } + bool + DDefineSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct + (ppii, + "DDefineSsm", + refrtag("defstate", defstate_)); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/IPrintable_DDefineSsm.cpp b/src/reader2/IPrintable_DDefineSsm.cpp new file mode 100644 index 00000000..c3aa2edd --- /dev/null +++ b/src/reader2/IPrintable_DDefineSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DDefineSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DDefineSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DDefineSsm.json5] +**/ + +#include "ssm/IPrintable_DDefineSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DDefineSsm::pretty(const DDefineSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DDefineSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 67754bb6..ee838864 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -33,6 +34,7 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); FacetRegistry::register_impl(); From 3bdbb61eba776645be3d4db7f45c547b1895559f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 12:40:26 -0500 Subject: [PATCH 092/342] xo-reader2: + pretty-printing for ParserResult + use in utest --- include/xo/reader2/ParserResult.hpp | 50 ++++++++++++++++++++++ src/reader2/ParserResult.cpp | 66 +++++++++++++++++++++++++++++ utest/SchematikaParser.test.cpp | 6 ++- 3 files changed, 121 insertions(+), 1 deletion(-) diff --git a/include/xo/reader2/ParserResult.hpp b/include/xo/reader2/ParserResult.hpp index 39f9c2d1..45064d32 100644 --- a/include/xo/reader2/ParserResult.hpp +++ b/include/xo/reader2/ParserResult.hpp @@ -7,6 +7,7 @@ #include #include +#include #include namespace xo { @@ -21,7 +22,18 @@ namespace xo { N }; + /** @return string representation for enum @p x **/ + const char * parser_result_type_descr(parser_result_type x); + + inline std::ostream & operator<<(std::ostream & os, parser_result_type x) { + os << parser_result_type_descr(x); + return os; + } + class ParserResult { + public: + using ppindentinfo = xo::print::ppindentinfo; + public: ParserResult() = default; ParserResult(parser_result_type type, @@ -44,15 +56,53 @@ namespace xo { bool is_expression() const { return result_type_ == parser_result_type::expression; } bool is_error() const { return result_type_ == parser_result_type::error; } + /** ordinary not-pretty printer **/ + void print(std::ostream & os) const; + /** pretty-printing support **/ + bool pretty(const ppindentinfo & ppii) const; + private: + /** none|expression|error_description + * + * @text + * result_type | error_src_function | error_description + * -------------+--------------------+------------------- + * none | nullptr | empty + * expression | nullptr | empty + * error | non-null | non-empty + * @endtext + **/ parser_result_type result_type_ = parser_result_type::none; + /** non-null iff @ref result_type_ is expression **/ obj result_expr_; + /** non-null iff @ref result_type_ is error. + * In which case gives parsing function detecting this error + **/ std::string_view error_src_fn_; + /** non-null iff @ref result_type_ is error + * Human-targeted error description. + **/ const DString * error_description_ = nullptr; }; + inline std::ostream & operator<<(std::ostream & os, const ParserResult & x) { + x.print(os); + return os; + } } /*namespace scm*/ + + namespace print { + /** pretty printer in relies on this specialization + * to handle ParserResult instances + **/ + template <> + struct ppdetail { + static inline bool print_pretty(const ppindentinfo & ppii, const xo::scm::ParserResult & x) { + return x.pretty(ppii); + } + }; + } } /*namespace xo*/ /* end ParserResult.hpp */ diff --git a/src/reader2/ParserResult.cpp b/src/reader2/ParserResult.cpp index 28553228..312538b1 100644 --- a/src/reader2/ParserResult.cpp +++ b/src/reader2/ParserResult.cpp @@ -4,9 +4,28 @@ **/ #include "ParserResult.hpp" +#include +#include namespace xo { + using xo::print::APrintable; + using xo::facet::FacetRegistry; + namespace scm { + + const char * + parser_result_type_descr(parser_result_type x) + { + switch (x) { + case parser_result_type::none: return "none"; + case parser_result_type::expression: return "expression"; + case parser_result_type::error: return "error"; + case parser_result_type::N: break; + } + + return "parser_result_type?"; + } + ParserResult::ParserResult(parser_result_type type, obj expr, std::string_view error_src_fn, @@ -26,6 +45,53 @@ namespace xo { ssm_name, errmsg); } + + void + ParserResult::print(std::ostream & os) const + { + os << ""; + } + + bool + ParserResult::pretty(const ppindentinfo & ppii) const + { + switch (result_type_) { + case parser_result_type::none: + return ppii.pps()->pretty_struct + (ppii, + "ParserResult", + refrtag("type", result_type_)); + case parser_result_type::expression: + { + auto expr = FacetRegistry::instance().variant(result_expr_); + + return ppii.pps()->pretty_struct + (ppii, + "ParserResult", + refrtag("type", result_type_), + refrtag("expr", expr)); + } + break; + case parser_result_type::error: + return ppii.pps()->pretty_struct + (ppii, + "ParserResult", + refrtag("type", result_type_), + refrtag("src_fn", error_src_fn_), + refrtag("error", error_description_)); + case parser_result_type::N: + assert(false); + break; + } + + return false; + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 259336cf..e2a9023e 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -71,6 +71,9 @@ namespace xo { TEST_CASE("SchematikaParser-batch-def", "[reader2][SchematikaParser]") { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + ArenaConfig config; config.name_ = "test-arena"; config.size_ = 16 * 1024; @@ -96,11 +99,12 @@ namespace xo { REQUIRE(parser.has_incomplete_expr() == true); REQUIRE(result.is_incomplete()); + + log && log(xtag("result", result)); } // define-expressions not properly implemented - //REQUIRE(result.error_description()); } From eca64875fde98267050799257fa5db51bdb097b1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 15:06:58 -0500 Subject: [PATCH 093/342] xo-reader2 xo-expression2: pprint for DDefineExpr + DVariable --- include/xo/reader2/ParserStack.hpp | 32 ++++++++++++++++ include/xo/reader2/ParserStateMachine.hpp | 3 +- include/xo/reader2/SchematikaParser.hpp | 28 ++++++++++++-- src/reader2/DDefineSsm.cpp | 9 ++++- src/reader2/ParserStack.cpp | 46 +++++++++++++++++++++++ src/reader2/SchematikaParser.cpp | 22 +++++++++++ utest/SchematikaParser.test.cpp | 9 +++++ 7 files changed, 144 insertions(+), 5 deletions(-) diff --git a/include/xo/reader2/ParserStack.hpp b/include/xo/reader2/ParserStack.hpp index b63be044..936c57e5 100644 --- a/include/xo/reader2/ParserStack.hpp +++ b/include/xo/reader2/ParserStack.hpp @@ -8,6 +8,7 @@ #include "SyntaxStateMachine.hpp" #include #include +#include namespace xo { namespace scm { @@ -21,6 +22,7 @@ namespace xo { class ParserStack { public: using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; public: ParserStack(DArena::Checkpoint ckp, @@ -42,6 +44,11 @@ namespace xo { obj top() const noexcept { return ssm_; } ParserStack * parent() const noexcept { return parent_; } + /** regular printing **/ + void print(std::ostream & os) const; + /** pretty-printer support **/ + bool pretty(const ppindentinfo & ppii) const; + private: /** stack pointer: top of stack just before this instance created **/ DArena::Checkpoint ckp_; @@ -51,7 +58,32 @@ namespace xo { ParserStack * parent_ = nullptr; }; + inline std::ostream & operator<< (std::ostream & os, const ParserStack * x) { + if (x) { + x->print(os); + } else { + os << "nullptr"; + } + return os; + } + } /*namespace scm*/ + + namespace print { + /** pretty printer in relies on this specialization + * to handle ParserResult instances + **/ + template <> + struct ppdetail { + static inline bool print_pretty(const ppindentinfo & ppii, const xo::scm::ParserStack * p) { + if (p) + return p->pretty(ppii); + else + return ppii.pps()->print_upto("nullptr"); + } + }; + } + } /*namespace xo*/ /* end ParserStack.hpp */ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index b333dd51..fbef2393 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -19,7 +19,8 @@ namespace xo { // class ASyntaxStateMachine; - // note: load-bearing to forward-declare ParserStack, + // note: it's load-bearing here to forward-declare ParserStack, + // see ParserStack.hpp for impl // because ASyntaxStateMachine.hpp includes ParserStateMachine.hpp; // before obj is defined. class ParserStack; diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 81115239..300980fb 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -153,9 +153,10 @@ namespace xo { **/ class SchematikaParser { public: + using token_type = Token; using ArenaConfig = xo::mm::ArenaConfig; using AAllocator = xo::mm::AAllocator; - using token_type = Token; + using ppindentinfo = xo::print::ppindentinfo; public: /** create parser in initial state; @@ -216,6 +217,8 @@ namespace xo { /** print human-readable representation on stream @p os **/ void print(std::ostream & os) const; + /** pretty-printer support **/ + bool pretty(const ppindentinfo & ppii) const; private: /** state machine **/ @@ -227,12 +230,31 @@ namespace xo { inline std::ostream & operator<< (std::ostream & os, - const SchematikaParser & x) { - x.print(os); + const SchematikaParser * x) { + if (x) { + x->print(os); + } else { + os << "nullptr"; + } return os; } } /*namespace scm*/ + + namespace print { + /** pretty printer in relies on this specialization + * to handle ParserResult instances + **/ + template <> + struct ppdetail { + static inline bool print_pretty(const ppindentinfo & ppii, const xo::scm::SchematikaParser* p) { + if (p) + return p->pretty(ppii); + else + return ppii.pps()->print_upto("nullptr"); + } + }; + } } /*namespace xo*/ /* end SchematikaParser.hpp */ diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 3ae20286..c1e3f6a9 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -6,6 +6,9 @@ #include "DDefineSsm.hpp" #include "DExpectSymbolSsm.hpp" #include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" +#include "ssm/IPrintable_DDefineSsm.hpp" +#include +#include #ifdef NOT_YET #include "parserstatemachine.hpp" @@ -16,6 +19,7 @@ #endif namespace xo { + using xo::print::APrintable; using xo::facet::with_facet; using xo::facet::typeseq; @@ -497,10 +501,13 @@ namespace xo { bool DDefineSsm::pretty(const ppindentinfo & ppii) const { + auto expr = with_facet::mkobj(def_expr_.data()); + return ppii.pps()->pretty_struct (ppii, "DDefineSsm", - refrtag("defstate", defstate_)); + refrtag("defstate", defstate_), + refrtag("def_expr", expr)); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ParserStack.cpp b/src/reader2/ParserStack.cpp index ba39517d..91d8bca9 100644 --- a/src/reader2/ParserStack.cpp +++ b/src/reader2/ParserStack.cpp @@ -5,8 +5,12 @@ #include "ParserStack.hpp" #include "SyntaxStateMachine.hpp" +#include +#include namespace xo { + using xo::print::APrintable; + using xo::facet::FacetRegistry; using xo::facet::typeseq; namespace scm { @@ -41,6 +45,48 @@ namespace xo { return stack->parent(); } + void + ParserStack::print(std::ostream & os) const + { + os << ""; + os << xtag("ssm", "*placeholder*"); + os << xtag("parent", "*placeholder*"); + os << ">"; + } + + bool + ParserStack::pretty(const ppindentinfo & ppii) const + { + auto * pps = ppii.pps(); + + /* always use multiple lines */ + + if (ppii.upto()) + return false; + + pps->write(" (frame->top()); + + pps->newline_pretty_tag(ppii.ci1(), buf, ssm); + + ++i_frame; + frame = frame->parent_; + } + + pps->write(">"); + + return false; + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index ac2d4520..d243de51 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -86,6 +86,28 @@ namespace xo { << xtag("has_stack", (psm_.stack() != nullptr)) << ">" << std::endl; } + + bool + SchematikaParser::pretty(const ppindentinfo & ppii) const { + auto * pps = ppii.pps(); + + if (ppii.upto()) + return false; + + // TODO: consider printing: + // psm.stringtable_ + // psm.parser_alloc_ + // psm.parser_alloc_ckp_ + // psm.expr_alloc_ + // psm.result_ + // psm.debug_flag_ + // + + return pps->pretty_struct + (ppii, + "SchematikaParser", + refrtag("stack", psm_.stack())); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index e2a9023e..8cccfd7b 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -4,6 +4,7 @@ **/ #include +#include #include #include @@ -17,6 +18,8 @@ namespace xo { using xo::mm::DArena; using xo::facet::with_facet; + static InitEvidence s_init = (InitSubsys::require()); + namespace ut { TEST_CASE("SchematikaParser-ctor", "[reader2][SchematikaParser]") { @@ -92,6 +95,10 @@ namespace xo { // but is still "at toplevel" in the sense of ready for input REQUIRE(parser.has_incomplete_expr() == true); REQUIRE(result.is_incomplete()); + + log && log("after def token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); } { @@ -100,6 +107,8 @@ namespace xo { REQUIRE(parser.has_incomplete_expr() == true); REQUIRE(result.is_incomplete()); + log && log("after lhs symbol token:"); + log && log(xtag("parser", &parser)); log && log(xtag("result", result)); } From 4c84f8c198aabcb60c9274865ed7ece1c554c341 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 22:13:01 -0500 Subject: [PATCH 094/342] xo-reader2 xo-object2: regenerate facets from idl --- CMakeLists.txt | 2 ++ idl/SyntaxStateMachine.json5 | 9 +++++++++ include/xo/reader2/DDefineSsm.hpp | 6 ++++++ include/xo/reader2/DExpectSymbolSsm.hpp | 6 ++++++ include/xo/reader2/DExprSeqState.hpp | 5 +++++ src/reader2/DDefineSsm.cpp | 9 +++++++++ src/reader2/DExpectSymbolSsm.cpp | 9 +++++++++ src/reader2/DExprSeqState.cpp | 9 +++++++++ 8 files changed, 55 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e2ee946b..ac780154 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,8 @@ xo_add_genfacetimpl( OUTPUT_CPP_DIR src/reader2 ) +xo_add_genfacet_all(xo-reader2-genfacet-all) + # ---------------------------------------------------------------- # shared library diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 28811512..f1b74111 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -70,6 +70,15 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_colon_token", + doc: ["update state machine for incoming colon-token @p tk"], + return_type: "void", + args: [ + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_parsed_symbol", doc: ["update stat machine for incoming parsed symbol @p sym"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index b8444cbe..468d1a22 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -127,6 +127,12 @@ namespace xo { void on_if_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming colon token @p tk, + * overall parser state in @p p_psm + **/ + void on_colon_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing a symbol @p sym; * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 2ecc556d..1854486e 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -69,6 +69,12 @@ namespace xo { void on_if_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming colon token @p tk, + * overall parser state in @p p_psm + **/ + void on_colon_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing a symbol @p sym; * overall parser state in @p p_psm. * diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 32eaef0f..90c69c5f 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -79,6 +79,11 @@ namespace xo { **/ void on_if_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming colon token @p tk, + * overall parser state in @p p_psm + **/ + void on_colon_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on parsed symbol @p sym * from immediately-downstream ssm. * overall parser state in @p p_psm diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index c1e3f6a9..13b99028 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -498,6 +498,15 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_colon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DDefineSsm::on_colon_token", + tk, + this->get_expect_str()); + } + bool DDefineSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index c859528f..1eccc454 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -95,6 +95,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_colon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectSymbolSsm::on_colon_token", + tk, + this->get_expect_str()); + } + void DExpectSymbolSsm::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index e994bbf1..6744c77d 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -160,6 +160,15 @@ namespace xo { } } + void + DExprSeqState::on_colon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExprSeqState::on_colon_token", + tk, + this->get_expect_str()); + } + void DExprSeqState::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) From 021625d562d382a9058191d9e959a5e01b69fdb4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 22:15:32 -0500 Subject: [PATCH 095/342] xo-reader2: regen ssm facet files + on_colon_token --- include/xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 ++ include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp | 2 +- include/xo/reader2/ssm/IPrintable_DExpectSymbolSsm.hpp | 2 +- include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp | 2 +- include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 ++ .../xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 ++ .../xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 ++ include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 +++ include/xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 +++ src/reader2/IPrintable_DDefineSsm.cpp | 2 +- src/reader2/IPrintable_DExpectSymbolSsm.cpp | 2 +- src/reader2/IPrintable_DExprSeqState.cpp | 2 +- src/reader2/ISyntaxStateMachine_Any.cpp | 6 ++++++ src/reader2/ISyntaxStateMachine_DDefineSsm.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DExprSeqState.cpp | 5 +++++ 17 files changed, 42 insertions(+), 6 deletions(-) diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index 4f428be5..f3ccb709 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -60,6 +60,8 @@ public: virtual void on_def_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming if-keyword-token @p tk **/ virtual void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; + /** update state machine for incoming colon-token @p tk **/ + virtual void on_colon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update stat machine for incoming parsed symbol @p sym **/ virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; ///@} diff --git a/include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp b/include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp index dd80b443..44b3165f 100644 --- a/include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DDefineSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/IPrintable_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectSymbolSsm.hpp index 6e63383b..f0dc79b6 100644 --- a/include/xo/reader2/ssm/IPrintable_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/IPrintable_DExpectSymbolSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExpectSymbolSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp b/include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp index 87d85fd7..6d542a07 100644 --- a/include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExprSeqState.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 23b90621..03ab1fa7 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -62,6 +62,7 @@ namespace scm { [[noreturn]] void on_symbol_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_def_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_if_token(Opaque, const Token &, ParserStateMachine *) override; + [[noreturn]] void on_colon_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index d420ba16..85d6d70b 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -59,6 +59,8 @@ namespace xo { static void on_def_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming if-keyword-token @p tk **/ static void on_if_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming colon-token @p tk **/ + static void on_colon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index ba8eb0b9..75125e5c 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -59,6 +59,8 @@ namespace xo { static void on_def_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming if-keyword-token @p tk **/ static void on_if_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming colon-token @p tk **/ + static void on_colon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index c1e61b40..e0689f69 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -59,6 +59,8 @@ namespace xo { static void on_def_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming if-keyword-token @p tk **/ static void on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming colon-token @p tk **/ + static void on_colon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 5a8e2fe3..ac6975ba 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -59,6 +59,9 @@ namespace scm { void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_if_token(_dcast(data), tk, p_psm); } + void on_colon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_colon_token(_dcast(data), tk, p_psm); + } void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) override { return I::on_parsed_symbol(_dcast(data), sym, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 786c83d0..78bbfb18 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -64,6 +64,9 @@ public: void on_if_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_if_token(O::data(), tk, p_psm); } + void on_colon_token(const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_colon_token(O::data(), tk, p_psm); + } void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { return O::iface()->on_parsed_symbol(O::data(), sym, p_psm); } diff --git a/src/reader2/IPrintable_DDefineSsm.cpp b/src/reader2/IPrintable_DDefineSsm.cpp index c3aa2edd..bb3c2096 100644 --- a/src/reader2/IPrintable_DDefineSsm.cpp +++ b/src/reader2/IPrintable_DDefineSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DDefineSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/src/reader2/IPrintable_DExpectSymbolSsm.cpp b/src/reader2/IPrintable_DExpectSymbolSsm.cpp index 2cef62a7..e58d15f9 100644 --- a/src/reader2/IPrintable_DExpectSymbolSsm.cpp +++ b/src/reader2/IPrintable_DExpectSymbolSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExpectSymbolSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/src/reader2/IPrintable_DExprSeqState.cpp b/src/reader2/IPrintable_DExprSeqState.cpp index f751b963..71997ede 100644 --- a/src/reader2/IPrintable_DExprSeqState.cpp +++ b/src/reader2/IPrintable_DExprSeqState.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExprSeqState.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 44effd57..edac8279 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -52,6 +52,12 @@ ISyntaxStateMachine_Any::on_if_token(Opaque, const Token &, ParserStateMachine * _fatal(); } +auto +ISyntaxStateMachine_Any::on_colon_token(Opaque, const Token &, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index 34bd4569..425032e3 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_if_token(tk, p_psm); } auto + ISyntaxStateMachine_DDefineSsm::on_colon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_colon_token(tk, p_psm); + } + auto ISyntaxStateMachine_DDefineSsm::on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index f00b9c2f..2188d50d 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_if_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectSymbolSsm::on_colon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_colon_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index 47c06ba3..7ad8fb50 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_if_token(tk, p_psm); } auto + ISyntaxStateMachine_DExprSeqState::on_colon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_colon_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExprSeqState::on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); From 0d8d928def31c4388a0e67b3e67712b470bd236d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 22:22:45 -0500 Subject: [PATCH 096/342] xo-reader2: DefineSsm handles colon token after lhs var example: def foo : f64 = 3.14; --- include/xo/reader2/ParserStateMachine.hpp | 3 +++ src/reader2/DDefineSsm.cpp | 9 ++++++++- src/reader2/ParserStateMachine.cpp | 13 ++++++++++++- utest/SchematikaParser.test.cpp | 11 +++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index fbef2393..31b664c0 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -105,6 +105,9 @@ namespace xo { /** operate state machine for incoming if-token @p tk **/ void on_if_token(const Token & tk); + /** operate state machine for incoming colon-token @p tk **/ + void on_colon_token(const Token & tk); + ///@} /** @defgroup scm-parserstatemachine-error-entrypoints error entry points **/ diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 13b99028..8941a20d 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -477,7 +477,7 @@ namespace xo { DDefineSsm::on_def_token(const Token & tk, ParserStateMachine * p_psm) { - if (this->defstate_ == defexprstatetype::def_0) { + if (defstate_ == defexprstatetype::def_0) { this->defstate_ = defexprstatetype::def_1; DExpectSymbolSsm::start(p_psm->parser_alloc(), p_psm); @@ -502,6 +502,13 @@ namespace xo { DDefineSsm::on_colon_token(const Token & tk, ParserStateMachine * p_psm) { + if (defstate_ == defexprstatetype::def_2) { + this->defstate_ = defexprstatetype::def_3; + + // expect_type_xs::start(p_psm); + return; + } + p_psm->illegal_input_on_token("DDefineSsm::on_colon_token", tk, this->get_expect_str()); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index ca8bba8b..5c9cc413 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -139,6 +139,10 @@ namespace xo { this->on_if_token(tk); break; + case tokentype::tk_colon: + this->on_colon_token(tk); + break; + // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_bool: @@ -157,7 +161,6 @@ namespace xo { case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: - case tokentype::tk_colon: case tokentype::tk_doublecolon: case tokentype::tk_semicolon: case tokentype::tk_singleassign: @@ -208,6 +211,14 @@ namespace xo { stack_->top().on_if_token(tk, this); } + void + ParserStateMachine::on_colon_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + stack_->top().on_colon_token(tk, this); + } + void ParserStateMachine::capture_error(std::string_view ssm_name, const DString * errmsg) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 8cccfd7b..4e4b778f 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -112,6 +112,17 @@ namespace xo { log && log(xtag("result", result)); } + { + auto & result = parser.on_token(Token::colon_token()); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(result.is_incomplete()); + + log && log("after colon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + } + // define-expressions not properly implemented //REQUIRE(result.error_description()); From 7fadf9662e807c984b4a365d5a3ed6475a7edb11 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 22:22:45 -0500 Subject: [PATCH 097/342] xo-reader2: DefineSsm handles colon token after lhs var example: def foo : f64 = 3.14; --- include/xo/tokenizer2/Token.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index 7ed490cc..fc448106 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -108,7 +108,7 @@ namespace xo { /** token representing comma @c "," **/ static Token comma() { return Token(tokentype::tk_comma); } /** token representing colon @c ":" **/ - static Token colon() { return Token(tokentype::tk_colon); } + static Token colon_token() { return Token(tokentype::tk_colon); } /** token representing double-colo @c "::" **/ static Token doublecolon() { return Token(tokentype::tk_doublecolon); } /** token representing semicolon @c ";" **/ From c87975ab187ba458d361b508456b16a372e3608f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 20 Jan 2026 22:39:01 -0500 Subject: [PATCH 098/342] xo-reader2: + DExpectTypeSsm [WIP] [NOBUILD] --- include/xo/reader2/DExpectTypeSsm.hpp | 64 ++++++++++++++++++++++++++ include/xo/reader2/syntaxstatetype.hpp | 3 ++ src/reader2/DExpectTypeSsm.cpp | 44 ++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 include/xo/reader2/DExpectTypeSsm.hpp create mode 100644 src/reader2/DExpectTypeSsm.cpp diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp new file mode 100644 index 00000000..84654f83 --- /dev/null +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -0,0 +1,64 @@ +/** @file expect_type_xs.hpp + * + * @author Roland Conybeare, Aug 2024 + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" + +namespace xo { + namespace scm { + /** @class DExpectTypeSsm + * @brief syntax state-machine for accepting a Schemtika typename-expression + * + * Jan 2026 + * Placeholder implementation at present. + * Only types are a handful of baked-in values + * + * @pre + * + * @endpre + **/ + class DExpectTypeSsm { + public: + DExpectTypeSsm(); + + static DExpectTypeSsm * make(DArena & parser_mm); + + static void start(DArena & parser_mm, + //obj expr_mm, + ParserStateMachine * p_psm); + + virtual const char * get_expect_str() const override; + + virtual void on_symbol_token(const token_type & tk, + parserstatemachine * p_psm) override; + + /** @defgroup scm-expecttype-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** text describing expected/allowed input to this ssm in current state. + * Intended to drive error messages. + **/ + std::string_view get_expect_str() const noexcept; + + /** operate state machien for this syntax on incoming symbol-token @p tk + * with overall parser state in @p p_psm + **/ + void on_symbol_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + + private: + static std::unique_ptr make(); + }; + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end expect_type_xs.hpp */ diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index bf3e03f1..8cb48938 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -24,6 +24,9 @@ namespace xo { /** expecting a s symbol. See @ref DExpectSymbolSsm **/ expect_symbol, + /** expecting a type. See @ref DExpectTypeSsm **/ + expect_type, + /** handle define-expression. See @ref DDefineSsm **/ defexpr, diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp new file mode 100644 index 00000000..b034ae23 --- /dev/null +++ b/src/reader2/DExpectTypeSsm.cpp @@ -0,0 +1,44 @@ +/** @file DExpectTypeSsm.cpp + * + * @author Roland Conybeare, Aug 2024 + **/ + +#include "DExpectTypeSsm.hpp" + +namespace xo { + namespace scm { + DExpectTypeSsm::DExpectTypeSsm() + {} + + DExpectTypeSsm * + DExpectTypeSsm::make(DArena & mm) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DArena)); + + return new (mem) DExpectTypeSsm(); + } + + void + DExpectTypeSsm::start(DArena & mm, + //obj expr_mm, + PArserStateMachine * p_psm) + { + DExpectTypeSsm * expect_type_ssm = DExpectTypeSsm::make(mm); + + auto ssm + = with_facet::mkobj(expect_type_ssm); + + p_psm->push_ssm(ssm); + } + + syntaxstatetype + DExpectTypeSsm::ssm_type() const noexcept + { + return syntaxstatetype::expect_type; + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectTypeSsm.cpp */ From 7b62bd7f5cfacf83beab374446fd5b46e65b5fb5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 21 Jan 2026 01:24:17 -0500 Subject: [PATCH 099/342] xo-reader2: + DExpectTypeSsm + extend DDefineSsm [WIP] --- CMakeLists.txt | 28 +++++ idl/IPrintable_DExpectTypeSsm.json5 | 13 +++ idl/ISyntaxStateMachine_DExpectTypeSsm.json5 | 13 +++ include/xo/reader2/DExpectTypeSsm.hpp | 48 +++++++-- .../reader2/ssm/IPrintable_DExpectTypeSsm.hpp | 62 +++++++++++ .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 72 +++++++++++++ src/reader2/CMakeLists.txt | 4 + src/reader2/DDefineSsm.cpp | 5 +- src/reader2/DExpectTypeSsm.cpp | 102 +++++++++++++++++- src/reader2/IPrintable_DExpectTypeSsm.cpp | 28 +++++ .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 59 ++++++++++ src/reader2/reader2_register_facets.cpp | 7 ++ utest/SchematikaParser.test.cpp | 11 ++ 13 files changed, 442 insertions(+), 10 deletions(-) create mode 100644 idl/IPrintable_DExpectTypeSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DExpectTypeSsm.json5 create mode 100644 include/xo/reader2/ssm/IPrintable_DExpectTypeSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp create mode 100644 src/reader2/IPrintable_DExpectTypeSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ac780154..d8c82e1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,34 @@ xo_add_genfacetimpl( OUTPUT_CPP_DIR src/reader2 ) +# ---------------------------------------------------------------- + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expecttypessm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ExpectTypeSsm + INPUT idl/ISyntaxStateMachine_DExpectTypeSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expecttypessm + FACET_PKG xo_printable2 + FACET Printable + REPR ExpectTypeSsm + INPUT idl/IPrintable_DExpectTypeSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-reader2-genfacet-all) # ---------------------------------------------------------------- diff --git a/idl/IPrintable_DExpectTypeSsm.json5 b/idl/IPrintable_DExpectTypeSsm.json5 new file mode 100644 index 00000000..1a4ddca2 --- /dev/null +++ b/idl/IPrintable_DExpectTypeSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectTypeSsm", + using_doxygen: true, + repr: "DExpectTypeSsm", + doc: [ "implement APrintable for DExpectTypeSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DExpectTypeSsm.json5 b/idl/ISyntaxStateMachine_DExpectTypeSsm.json5 new file mode 100644 index 00000000..d46aaff4 --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectTypeSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectTypeSsm", + using_doxygen: true, + repr: "DExpectTypeSsm", + doc: [ "implement ASyntaxStateMachine for DExpectTypeSsm" ], +} \ No newline at end of file diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 84654f83..aebec716 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -6,6 +6,7 @@ #pragma once #include "SyntaxStateMachine.hpp" +#include namespace xo { namespace scm { @@ -21,6 +22,10 @@ namespace xo { * @endpre **/ class DExpectTypeSsm { + public: + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; + public: DExpectTypeSsm(); @@ -30,11 +35,6 @@ namespace xo { //obj expr_mm, ParserStateMachine * p_psm); - virtual const char * get_expect_str() const override; - - virtual void on_symbol_token(const token_type & tk, - parserstatemachine * p_psm) override; - /** @defgroup scm-expecttype-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -52,13 +52,45 @@ namespace xo { void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); + /** operate state machine for this syntax on incoming define-token @p tk + * with overall parser state in @p p_psm + **/ + void on_def_token(const Token & tk, + ParserStateMachine * p_psm); + + /** operate state machine for this syntax on incoming if-token @p tk + * with overall parser state in @p p_psm + **/ + void on_if_token(const Token & tk, + ParserStateMachine * p_psm); + + /** operate state machine for this syntax on incoming colon-token @p tk + * with overall parser state in @p p_psm + **/ + void on_colon_token(const Token & tk, + ParserStateMachine * p_psm); + + /** Never called. + * Operate state machine for this syntax after symbol + * emitted from nested ssm. + * Impossible path for DExpectTypeSsm until such time as it relies + * on nested ssms. Currently using on_symbol_token + * entry point instead. + **/ + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expecttype-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + ///@} - private: - static std::unique_ptr make(); }; } /*namespace scm*/ } /*namespace xo*/ -/* end expect_type_xs.hpp */ +/* end DExpectTypeSsm.hpp */ diff --git a/include/xo/reader2/ssm/IPrintable_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectTypeSsm.hpp new file mode 100644 index 00000000..271df307 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DExpectTypeSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectTypeSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectTypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectTypeSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectTypeSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectTypeSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectTypeSsm + **/ + class IPrintable_DExpectTypeSsm { + public: + /** @defgroup scm-printable-dexpecttypessm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpecttypessm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectTypeSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp new file mode 100644 index 00000000..c56f21d5 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -0,0 +1,72 @@ +/** @file ISyntaxStateMachine_DExpectTypeSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectTypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectTypeSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectTypeSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectTypeSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectTypeSsm + **/ + class ISyntaxStateMachine_DExpectTypeSsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpecttypessm-type-traits **/ + ///@{ + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexpecttypessm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectTypeSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectTypeSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming symbol-token @p tk **/ + static void on_symbol_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming define-keyword-token @p tk **/ + static void on_def_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming if-keyword-token @p tk **/ + static void on_if_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming colon-token @p tk **/ + static void on_colon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 6b17e3d3..b09f015a 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -23,6 +23,10 @@ set(SELF_SRCS ISyntaxStateMachine_DExpectSymbolSsm.cpp IPrintable_DExpectSymbolSsm.cpp + DExpectTypeSsm.cpp + ISyntaxStateMachine_DExpectTypeSsm.cpp + IPrintable_DExpectTypeSsm.cpp + reader2_register_facets.cpp reader2_register_types.cpp ) diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 8941a20d..98a9fa4a 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -5,6 +5,7 @@ #include "DDefineSsm.hpp" #include "DExpectSymbolSsm.hpp" +#include "DExpectTypeSsm.hpp" #include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" #include "ssm/IPrintable_DDefineSsm.hpp" #include @@ -505,7 +506,9 @@ namespace xo { if (defstate_ == defexprstatetype::def_2) { this->defstate_ = defexprstatetype::def_3; - // expect_type_xs::start(p_psm); + DExpectTypeSsm::start(p_psm->parser_alloc(), + p_psm); + return; } diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index b034ae23..ce38473e 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -4,8 +4,20 @@ **/ #include "DExpectTypeSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp" +#include "SyntaxStateMachine.hpp" +#include +#include +#include +#include +#include namespace xo { + using xo::facet::with_facet; + using xo::reflect::Reflect; + using xo::reflect::TypeDescr; + using xo::reflect::typeseq; + namespace scm { DExpectTypeSsm::DExpectTypeSsm() {} @@ -22,7 +34,7 @@ namespace xo { void DExpectTypeSsm::start(DArena & mm, //obj expr_mm, - PArserStateMachine * p_psm) + ParserStateMachine * p_psm) { DExpectTypeSsm * expect_type_ssm = DExpectTypeSsm::make(mm); @@ -38,6 +50,94 @@ namespace xo { return syntaxstatetype::expect_type; } + std::string_view + DExpectTypeSsm::get_expect_str() const noexcept + { + return "typename"; + } + + void + DExpectTypeSsm::on_def_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectTypeSsm", + tk, + this->get_expect_str()); + } + + void + DExpectTypeSsm::on_if_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DxpectTypeSsm", + tk, + this->get_expect_str()); + } + + void + DExpectTypeSsm::on_colon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DxpectTypeSsm", + tk, + this->get_expect_str()); + } + + void + DExpectTypeSsm::on_symbol_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(true)); + + TypeDescr td = nullptr; + + /* TODO: replace with typetable lookup */ + + if (tk.text() == "bool") + td = Reflect::require(); + else if (tk.text() == "str") + td = Reflect::require(); + else if (tk.text() == "f64") + td = Reflect::require(); + else if(tk.text() == "f32") + td = Reflect::require(); + else if(tk.text() == "i16") + td = Reflect::require(); + else if(tk.text() == "i32") + td = Reflect::require(); + else if(tk.text() == "i64") + td = Reflect::require(); + + if (!td) { + p_psm->illegal_input_on_token("DExpectTypeSsm", + tk, + this->get_expect_str()); + } + + p_psm->pop_ssm(); + + log && log("STUB: missing on_typedescr() call"); + + //p_psm->on_typedescr(td); + } + + void + DExpectTypeSsm::on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol("ExpectTypeSsm", + sym, + this->get_expect_str()); + } + + bool + DExpectTypeSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct + (ppii, + "DExpectTypeSsm"); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/IPrintable_DExpectTypeSsm.cpp b/src/reader2/IPrintable_DExpectTypeSsm.cpp new file mode 100644 index 00000000..c82d726e --- /dev/null +++ b/src/reader2/IPrintable_DExpectTypeSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectTypeSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectTypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectTypeSsm.json5] +**/ + +#include "ssm/IPrintable_DExpectTypeSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectTypeSsm::pretty(const DExpectTypeSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectTypeSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp new file mode 100644 index 00000000..c520aea8 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -0,0 +1,59 @@ +/** @file ISyntaxStateMachine_DExpectTypeSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectTypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectTypeSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectTypeSsm::ssm_type(const DExpectTypeSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectTypeSsm::get_expect_str(const DExpectTypeSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectTypeSsm::on_symbol_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_symbol_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectTypeSsm::on_def_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_def_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectTypeSsm::on_if_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_if_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectTypeSsm::on_colon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_colon_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectTypeSsm::on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectTypeSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index ee838864..a393eead 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -14,6 +14,9 @@ #include #include +#include +#include + #include #include #include @@ -39,9 +42,13 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + log && log(xtag("DExprSeqState.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); log && log(xtag("DExpectSymbolSsm.tseq", typeseq::id())); + log && log(xtag("DExpectTypeSsm.tseq", typeseq::id())); return true; } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 4e4b778f..af9b8303 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -123,6 +123,17 @@ namespace xo { log && log(xtag("result", result)); } + { + auto & result = parser.on_token(Token::symbol_token("f64")); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(result.is_incomplete()); + + log && log("after typename symbol token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + } + // define-expressions not properly implemented //REQUIRE(result.error_description()); From 7d33440ecbab01f2a4a817ddba4e24c40340bd30 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 21 Jan 2026 12:14:35 -0500 Subject: [PATCH 100/342] xo-reader2: handle parsed typedescr + use in DDefineSsm --- idl/SyntaxStateMachine.json5 | 11 ++++++ include/xo/reader2/DDefineSsm.hpp | 7 ++++ include/xo/reader2/DExpectSymbolSsm.hpp | 39 +++++++++++-------- include/xo/reader2/DExpectTypeSsm.hpp | 11 +++++- include/xo/reader2/DExprSeqState.hpp | 7 ++++ include/xo/reader2/ParserStateMachine.hpp | 20 +++++++++- .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 5 +++ .../reader2/ssm/IPrintable_DExpectTypeSsm.hpp | 2 +- .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 2 + .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 3 ++ .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 3 ++ .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 5 ++- .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 3 ++ .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 5 +++ .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 4 ++ src/reader2/DDefineSsm.cpp | 28 ++++++++++++- src/reader2/DExpectSymbolSsm.cpp | 27 ++++++++----- src/reader2/DExpectTypeSsm.cpp | 14 +++++-- src/reader2/DExprSeqState.cpp | 9 +++++ src/reader2/IPrintable_DExpectTypeSsm.cpp | 2 +- src/reader2/ISyntaxStateMachine_Any.cpp | 6 +++ .../ISyntaxStateMachine_DDefineSsm.cpp | 5 +++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 +++ .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 7 +++- .../ISyntaxStateMachine_DExprSeqState.cpp | 5 +++ src/reader2/ParserStateMachine.cpp | 33 ++++++++++++++++ 26 files changed, 231 insertions(+), 37 deletions(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index f1b74111..c207022f 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -5,6 +5,7 @@ "\"ParserStateMachine.hpp\"", "\"syntaxstatetype.hpp\"", "", + "", ], // extra includes in SyntaxStateMachine.hpp, if any user_hpp_includes: [], @@ -20,6 +21,7 @@ "Assistant to schematika parser dedicated to particular syntax" ], types: [ + { name: "TypeDescr", doc: [ "reflected c++ type" ], definition: "xo::reflect::TypeDescr" }, // { name: string, doc: [ string ], definition: string }, ], const_methods: [ @@ -88,5 +90,14 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_parsed_typedescr", + doc: ["operate state machine for incoming type description @p td"], + return_type: "void", + args: [ + {type: "TypeDescr", name: "td"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, ], } diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 468d1a22..d9aea54f 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -71,6 +71,7 @@ namespace xo { **/ class DDefineSsm { public: + using TypeDescr = xo::reflect::TypeDescr; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -139,6 +140,12 @@ namespace xo { void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm); + /** update state for this syntax after parsing a type-description @p td, + * overall parser state in @p p_psm + **/ + void on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-define-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 1854486e..7421c0f7 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -22,6 +22,7 @@ namespace xo { class DExpectSymbolSsm { public: using DArena = xo::mm::DArena; + using TypeDescr = xo::reflect::TypeDescr; using ppindentinfo = xo::print::ppindentinfo; public: @@ -57,8 +58,29 @@ namespace xo { **/ std::string_view get_expect_str() const noexcept; + /** update state for this syntax after parsing a symbol @p sym; + * overall parser state in @p p_psm. + * + * NOTE: + * might not be obvious that this is unreachable. + * DExpectSymbolSsm converts a symbol token, + * and delivers it to parent ssm using this entry point. + * This method would only be called if consecutive + * DExpectSymbolSsm instances on parser stack; + * which scenario never occurs in Schematika syntax + **/ + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); + + /** update state for this syntax after parsing a type-description @p td + * in nested state machine. + * (provided to satisfy ASyntaxStateMachine api. not reachable) + **/ + void on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming token @p tk, - * overall parser state in @p p_psm + * overall parser state in @p p_psm. **/ void on_def_token(const Token & tk, ParserStateMachine * p_psm); @@ -75,21 +97,6 @@ namespace xo { void on_colon_token(const Token & tk, ParserStateMachine * p_psm); - /** update state for this syntax after parsing a symbol @p sym; - * overall parser state in @p p_psm. - * - * NOTE: - * might not be obvious that this is unreachable. - * DExpectSymbolSsm converts a symbol token, - * and delivers it to parent ssm using this entry point. - * This method would only be called if consecutive - * DExpectSymbolSsm instances on parser stack; - * which scenario never occurs in Schematika syntax - **/ - void on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm); - - ///@} /** @defgroup scm-expectsymbol-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index aebec716..f98b8767 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -23,6 +23,7 @@ namespace xo { **/ class DExpectTypeSsm { public: + using TypeDescr = xo::reflect::TypeDescr; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -70,7 +71,7 @@ namespace xo { void on_colon_token(const Token & tk, ParserStateMachine * p_psm); - /** Never called. + /** (Never called). * Operate state machine for this syntax after symbol * emitted from nested ssm. * Impossible path for DExpectTypeSsm until such time as it relies @@ -80,6 +81,14 @@ namespace xo { void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for this syntax on receiving type-description + * from nested parser. + * Currently (jan 2026) impossible path for DExpectTypeSsm. + * Active path is via on_symbol_token() + **/ + void on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expecttype-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 90c69c5f..942afedd 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -39,6 +39,7 @@ namespace xo { **/ class DExprSeqState { public: + using TypeDescr = xo::reflect::TypeDescr; using AAllocator = xo::mm::AAllocator; using ppindentinfo = xo::print::ppindentinfo; @@ -90,6 +91,12 @@ namespace xo { **/ void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm); + /** update state for this syntax on parsed type-description @p td + * from nested ssm. + * overall parser state in @p p_psm + **/ + void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + ///@} /** @defgroup scm-exprseq-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 31b664c0..e17ff39d 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -29,6 +29,7 @@ namespace xo { **/ class ParserStateMachine { public: + using TypeDescr = xo::reflect::TypeDescr; using AAllocator = xo::mm::AAllocator; using ArenaConfig = xo::mm::ArenaConfig; using DArena = xo::mm::DArena; @@ -88,9 +89,16 @@ namespace xo { /** @defgroup scm-parserstatemachine-inputmethods input methods **/ ///@{ - /** update state to respond to prsed symbol @p sym **/ + /** update state to respond to parsed symbol @p sym + * (from nested parsing state) + **/ void on_parsed_symbol(std::string_view sym); + /** update state to respond to parsed type-description @p td + * (from nested parsing state) + **/ + void on_parsed_typedescr(TypeDescr td); + /** update state to respond to input token @p tk. * record output (if any) in @ref result_ **/ @@ -109,7 +117,6 @@ namespace xo { void on_colon_token(const Token & tk); ///@} - /** @defgroup scm-parserstatemachine-error-entrypoints error entry points **/ ///@{ @@ -136,6 +143,15 @@ namespace xo { void illegal_input_on_symbol(std::string_view ssm_name, std::string_view sym, std::string_view expect_str); + + /** report illegal input arriving in syntax state machine (ssm) @p ssm_name + * receiving assembled type-description @p td. + * @p expect_str sketches expected input in current ssm state + **/ + void illegal_input_on_typedescr(std::string_view ssm_name, + TypeDescr td, + std::string_view expect_str); + ///@} private: diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index f3ccb709..6aefa1f7 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -17,6 +17,7 @@ #include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" #include +#include #include #include #include @@ -41,6 +42,8 @@ public: using typeseq = xo::facet::typeseq; using Copaque = const void *; using Opaque = void *; + /** reflected c++ type **/ + using TypeDescr = xo::reflect::TypeDescr; ///@} /** @defgroup scm-syntaxstatemachine-methods **/ @@ -64,6 +67,8 @@ public: virtual void on_colon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update stat machine for incoming parsed symbol @p sym **/ virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; + /** operate state machine for incoming type description @p td **/ + virtual void on_parsed_typedescr(Opaque data, TypeDescr td, ParserStateMachine * p_psm) = 0; ///@} }; /*ASyntaxStateMachine*/ diff --git a/include/xo/reader2/ssm/IPrintable_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectTypeSsm.hpp index 271df307..7b7785e9 100644 --- a/include/xo/reader2/ssm/IPrintable_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/IPrintable_DExpectTypeSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExpectTypeSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 03ab1fa7..1a6705d2 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -44,6 +44,7 @@ namespace scm { /** integer identifying a type **/ using typeseq = xo::facet::typeseq; + using TypeDescr = ASyntaxStateMachine::TypeDescr; ///@} /** @defgroup scm-syntaxstatemachine-any-methods **/ @@ -64,6 +65,7 @@ namespace scm { [[noreturn]] void on_if_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_colon_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; + [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index 85d6d70b..65627a03 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -41,6 +41,7 @@ namespace xo { public: /** @defgroup scm-syntaxstatemachine-ddefinessm-type-traits **/ ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -63,6 +64,8 @@ namespace xo { static void on_colon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 75125e5c..91ff08b6 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -41,6 +41,7 @@ namespace xo { public: /** @defgroup scm-syntaxstatemachine-dexpectsymbolssm-type-traits **/ ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -63,6 +64,8 @@ namespace xo { static void on_colon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectSymbolSsm & self, TypeDescr td, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index c56f21d5..64622261 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExpectTypeSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -41,6 +41,7 @@ namespace xo { public: /** @defgroup scm-syntaxstatemachine-dexpecttypessm-type-traits **/ ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -63,6 +64,8 @@ namespace xo { static void on_colon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectTypeSsm & self, TypeDescr td, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index e0689f69..64fd4ed7 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -41,6 +41,7 @@ namespace xo { public: /** @defgroup scm-syntaxstatemachine-dexprseqstate-type-traits **/ ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -63,6 +64,8 @@ namespace xo { static void on_colon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExprSeqState & self, TypeDescr td, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index ac6975ba..7b2c721f 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -16,6 +16,7 @@ #include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" #include +#include namespace xo { namespace scm { @@ -30,6 +31,7 @@ namespace scm { using Impl = ISyntaxStateMachine_DRepr; /** integer identifying a type **/ using typeseq = ASyntaxStateMachine::typeseq; + using TypeDescr = ASyntaxStateMachine::TypeDescr; ///@} /** @defgroup scm-syntaxstatemachine-xfer-methods **/ @@ -65,6 +67,9 @@ namespace scm { void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) override { return I::on_parsed_symbol(_dcast(data), sym, p_psm); } + void on_parsed_typedescr(Opaque data, TypeDescr td, ParserStateMachine * p_psm) override { + return I::on_parsed_typedescr(_dcast(data), td, p_psm); + } ///@} diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 78bbfb18..4a63e377 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -31,6 +31,7 @@ public: using ObjectType = Object; using DataPtr = Object::DataPtr; using typeseq = xo::reflect::typeseq; + using TypeDescr = ASyntaxStateMachine::TypeDescr; ///@} /** @defgroup scm-syntaxstatemachine-router-ctors **/ @@ -70,6 +71,9 @@ public: void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { return O::iface()->on_parsed_symbol(O::data(), sym, p_psm); } + void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm) { + return O::iface()->on_parsed_typedescr(O::data(), td, p_psm); + } ///@} /** @defgroup scm-syntaxstatemachine-member-vars **/ diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 98a9fa4a..21435a83 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -420,7 +420,7 @@ namespace xo { DDefineSsm::on_parsed_symbol(std::string_view sym_name, ParserStateMachine * p_psm) { - if (this->defstate_ == defexprstatetype::def_1) { + if (defstate_ == defexprstatetype::def_1) { this->defstate_ = defexprstatetype::def_2; const DUniqueString * sym @@ -460,6 +460,32 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(true), xtag("td", td)); + + if (defstate_ == defexprstatetype::def_3) { + this->defstate_ = defexprstatetype::def_4; + + // note: not present in x0-reader/ version + def_expr_.assign_valuetype(td); + +#ifdef NOT_YET + this->cvt_expr_ = ConvertExpr::make(td, nullptr); + def_expr_->assign_rhs(cvt_expr_); +#endif + log && log("STUB: ConvertExpr not implemented, TypeDescr not captured"); + + return; + } + + p_psm->illegal_input_on_typedescr("DDefineSsm::on_parsed_typedescr", + td, + this->get_expect_str()); + } + void DDefineSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 1eccc454..877c6a50 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -56,6 +56,24 @@ namespace xo { return "symbol"; } + void + DExpectSymbolSsm::on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol("DExpectSymbolSsm::on_parsed_symbol", + sym, + this->get_expect_str()); + } + + void + DExpectSymbolSsm::on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_typedescr("DExpectSymbolSsm::on_parsed_typedescr", + td, + this->get_expect_str()); + } + void DExpectSymbolSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) @@ -104,15 +122,6 @@ namespace xo { this->get_expect_str()); } - void - DExpectSymbolSsm::on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_symbol("DExpectSymbolSsm::on_parsed_symbol", - sym, - this->get_expect_str()); - } - bool DExpectSymbolSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index ce38473e..62ccdf22 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -115,10 +115,7 @@ namespace xo { } p_psm->pop_ssm(); - - log && log("STUB: missing on_typedescr() call"); - - //p_psm->on_typedescr(td); + p_psm->on_parsed_typedescr(td); } void @@ -130,6 +127,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectTypeSsm::on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_typedescr("ExpectTypeSsm", + td, + this->get_expect_str()); + } + bool DExpectTypeSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 6744c77d..6f9d877a 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -178,6 +178,15 @@ namespace xo { this->get_expect_str()); } + void + DExprSeqState::on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_typedescr("DExprSeqState::on_parsed_typedescr", + td, + this->get_expect_str()); + } + bool DExprSeqState::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/IPrintable_DExpectTypeSsm.cpp b/src/reader2/IPrintable_DExpectTypeSsm.cpp index c82d726e..3fc75136 100644 --- a/src/reader2/IPrintable_DExpectTypeSsm.cpp +++ b/src/reader2/IPrintable_DExpectTypeSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExpectTypeSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index edac8279..24775dfd 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -64,6 +64,12 @@ ISyntaxStateMachine_Any::on_parsed_symbol(Opaque, std::string_view, ParserStateM _fatal(); } +auto +ISyntaxStateMachine_Any::on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) -> void +{ + _fatal(); +} + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index 425032e3..8cc9c858 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -52,6 +52,11 @@ namespace xo { { self.on_parsed_symbol(sym, p_psm); } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 2188d50d..e4716ef8 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -52,6 +52,11 @@ namespace xo { { self.on_parsed_symbol(sym, p_psm); } + auto + ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_typedescr(DExpectSymbolSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index c520aea8..893cb0dd 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExpectTypeSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -52,6 +52,11 @@ namespace xo { { self.on_parsed_symbol(sym, p_psm); } + auto + ISyntaxStateMachine_DExpectTypeSsm::on_parsed_typedescr(DExpectTypeSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index 7ad8fb50..911e825e 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -52,6 +52,11 @@ namespace xo { { self.on_parsed_symbol(sym, p_psm); } + auto + ISyntaxStateMachine_DExprSeqState::on_parsed_typedescr(DExprSeqState & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 5c9cc413..79f23eb5 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -113,6 +113,16 @@ namespace xo { this->stack_->top().on_parsed_symbol(sym, this); } + void + ParserStateMachine::on_parsed_typedescr(TypeDescr td) + { + scope log(XO_DEBUG(debug_flag_), xtag("td", td)); + + assert(stack_); + + this->stack_->top().on_parsed_typedescr(td, this); + } + void ParserStateMachine::on_token(const Token & tk) { @@ -271,6 +281,29 @@ namespace xo { this->capture_error(ssm_name, errmsg); } + + void + ParserStateMachine::illegal_input_on_typedescr(std::string_view ssm_name, + TypeDescr td, + std::string_view expect_str) + { + // TODO: + // - want to write error message using DArena + // - need something like log_streambuf and/or tostr() that's arena-aware + + auto errmsg_string = tostr("Unexpected type-description for parsing state", + xtag("td", td), + xtag("expecting", expect_str), + xtag("ssm", ssm_name), + xtag("via", "ParserStateMachine::illegal_input_on_typedescr")); + + assert(expr_alloc_); + + auto errmsg = DString::from_view(expr_alloc_, + std::string_view(errmsg_string)); + + this->capture_error(ssm_name, errmsg); + } } /*namespace scm*/ } /*namespace xo*/ From a3f5b129558c2cd4f1a5ef751a377e4e19767004 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 21 Jan 2026 12:59:06 -0500 Subject: [PATCH 101/342] xo-reader2: scaffold on_singleassign_token() in PSM --- idl/SyntaxStateMachine.json5 | 9 ++++++++ include/xo/reader2/DDefineSsm.hpp | 6 +++++ include/xo/reader2/DExpectSymbolSsm.hpp | 6 +++++ include/xo/reader2/DExpectTypeSsm.hpp | 6 +++++ include/xo/reader2/DExprSeqState.hpp | 5 +++++ include/xo/reader2/ParserStateMachine.hpp | 3 +++ .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 ++ .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 ++ .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 +++ .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 +++ src/reader2/DDefineSsm.cpp | 22 +++++++++++++++++++ src/reader2/DExpectSymbolSsm.cpp | 9 ++++++++ src/reader2/DExpectTypeSsm.cpp | 9 ++++++++ src/reader2/DExprSeqState.cpp | 9 ++++++++ src/reader2/ISyntaxStateMachine_Any.cpp | 6 +++++ .../ISyntaxStateMachine_DDefineSsm.cpp | 5 +++++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 +++++ .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 +++++ .../ISyntaxStateMachine_DExprSeqState.cpp | 5 +++++ src/reader2/ParserStateMachine.cpp | 13 ++++++++++- 24 files changed, 139 insertions(+), 1 deletion(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index c207022f..2fcbd796 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -81,6 +81,15 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_singleassign_token", + doc: ["update state machine for incoming singleassign-token @p tk"], + return_type: "void", + args: [ + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_parsed_symbol", doc: ["update stat machine for incoming parsed symbol @p sym"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index d9aea54f..5308f77a 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -134,6 +134,12 @@ namespace xo { void on_colon_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming singleassign token @p tk, + * overall parser state in @p p_psm + **/ + void on_singleassign_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing a symbol @p sym; * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 7421c0f7..7bbcec91 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -97,6 +97,12 @@ namespace xo { void on_colon_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming singleassign token @p tk, + * overall parser state in @p p_psm + **/ + void on_singleassign_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expectsymbol-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index f98b8767..c5d8ef5b 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -71,6 +71,12 @@ namespace xo { void on_colon_token(const Token & tk, ParserStateMachine * p_psm); + /** operate state machine for this syntax on incoming singleassign-token @p tk + * with overall parser state in @p p_psm + **/ + void on_singleassign_token(const Token & tk, + ParserStateMachine * p_psm); + /** (Never called). * Operate state machine for this syntax after symbol * emitted from nested ssm. diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 942afedd..01fdfc16 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -85,6 +85,11 @@ namespace xo { **/ void on_colon_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming single-assign token @p tk, + * overall parser state in @p p_psm + **/ + void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on parsed symbol @p sym * from immediately-downstream ssm. * overall parser state in @p p_psm diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index e17ff39d..bcd8f557 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -116,6 +116,9 @@ namespace xo { /** operate state machine for incoming colon-token @p tk **/ void on_colon_token(const Token & tk); + /** operate state machine for incoming singleassign-token @p tk **/ + void on_singleassign_token(const Token & tk); + ///@} /** @defgroup scm-parserstatemachine-error-entrypoints error entry points **/ ///@{ diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index 6aefa1f7..f8f23f2a 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -65,6 +65,8 @@ public: virtual void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming colon-token @p tk **/ virtual void on_colon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; + /** update state machine for incoming singleassign-token @p tk **/ + virtual void on_singleassign_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update stat machine for incoming parsed symbol @p sym **/ virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 1a6705d2..51e5cff0 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -64,6 +64,7 @@ namespace scm { [[noreturn]] void on_def_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_if_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_colon_token(Opaque, const Token &, ParserStateMachine *) override; + [[noreturn]] void on_singleassign_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index 65627a03..dd2bdc29 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_if_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming colon-token @p tk **/ static void on_colon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming singleassign-token @p tk **/ + static void on_singleassign_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 91ff08b6..114208f6 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_if_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming colon-token @p tk **/ static void on_colon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming singleassign-token @p tk **/ + static void on_singleassign_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index 64622261..7bf0d312 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_if_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming colon-token @p tk **/ static void on_colon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming singleassign-token @p tk **/ + static void on_singleassign_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index 64fd4ed7..73e8a1cc 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming colon-token @p tk **/ static void on_colon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming singleassign-token @p tk **/ + static void on_singleassign_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 7b2c721f..d86e9763 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -64,6 +64,9 @@ namespace scm { void on_colon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_colon_token(_dcast(data), tk, p_psm); } + void on_singleassign_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_singleassign_token(_dcast(data), tk, p_psm); + } void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) override { return I::on_parsed_symbol(_dcast(data), sym, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 4a63e377..921da301 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -68,6 +68,9 @@ public: void on_colon_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_colon_token(O::data(), tk, p_psm); } + void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_singleassign_token(O::data(), tk, p_psm); + } void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { return O::iface()->on_parsed_symbol(O::data(), sym, p_psm); } diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 21435a83..78667376 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -543,6 +543,28 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_singleassign_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(true), xtag("defstate", defstate_)); + + if ((defstate_ == defexprstatetype::def_2) + || (defstate_ == defexprstatetype::def_4)) + { + this->defstate_ = defexprstatetype::def_5; + + // TODO: DExpectExprSsm::start(...) + log && log("STUB: DExpectExprSsm not implemented"); + + return; + } + + p_psm->illegal_input_on_token("DDefineSsm::on_singleassign_token", + tk, + this->get_expect_str()); + } + bool DDefineSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 877c6a50..e9b93cc5 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -122,6 +122,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_singleassign_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectSymbolSsm::on_singleassign_token", + tk, + this->get_expect_str()); + } + bool DExpectSymbolSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 62ccdf22..b40916a9 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -83,6 +83,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectTypeSsm::on_singleassign_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectTypeSsm::on_singleassign_token", + tk, + this->get_expect_str()); + } + void DExpectTypeSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 6f9d877a..75e711cd 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -169,6 +169,15 @@ namespace xo { this->get_expect_str()); } + void + DExprSeqState::on_singleassign_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExprSeqState::on_singleassign_token", + tk, + this->get_expect_str()); + } + void DExprSeqState::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 24775dfd..fb9e7a53 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -58,6 +58,12 @@ ISyntaxStateMachine_Any::on_colon_token(Opaque, const Token &, ParserStateMachin _fatal(); } +auto +ISyntaxStateMachine_Any::on_singleassign_token(Opaque, const Token &, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index 8cc9c858..ae2d6601 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_colon_token(tk, p_psm); } auto + ISyntaxStateMachine_DDefineSsm::on_singleassign_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_singleassign_token(tk, p_psm); + } + auto ISyntaxStateMachine_DDefineSsm::on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index e4716ef8..5eb40180 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_colon_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectSymbolSsm::on_singleassign_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_singleassign_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 893cb0dd..d8621b20 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_colon_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectTypeSsm::on_singleassign_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_singleassign_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectTypeSsm::on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index 911e825e..d81e066c 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_colon_token(tk, p_psm); } auto + ISyntaxStateMachine_DExprSeqState::on_singleassign_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_singleassign_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExprSeqState::on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 79f23eb5..b74de542 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -153,6 +153,10 @@ namespace xo { this->on_colon_token(tk); break; + case tokentype::tk_singleassign: + this->on_singleassign_token(tk); + break; + // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_bool: @@ -173,7 +177,6 @@ namespace xo { case tokentype::tk_comma: case tokentype::tk_doublecolon: case tokentype::tk_semicolon: - case tokentype::tk_singleassign: case tokentype::tk_assign: case tokentype::tk_yields: case tokentype::tk_plus: @@ -229,6 +232,14 @@ namespace xo { stack_->top().on_colon_token(tk, this); } + void + ParserStateMachine::on_singleassign_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + stack_->top().on_singleassign_token(tk, this); + } + void ParserStateMachine::capture_error(std::string_view ssm_name, const DString * errmsg) From b738afac9deee9eb074695b38202bf8724f92489 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 21 Jan 2026 12:59:06 -0500 Subject: [PATCH 102/342] xo-reader2: scaffold on_singleassign_token() in PSM --- include/xo/tokenizer2/Token.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index fc448106..d47b311d 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -101,7 +101,7 @@ namespace xo { static Token rightbracket() { return Token(tokentype::tk_rightbracket); } /** token representing left brace @c "{" **/ static Token leftbrace() { return Token(tokentype::tk_leftbrace); } - /** token representing right brace @c "}' **/ + /** token representing right brace @c "}" **/ static Token rightbrace() { return Token(tokentype::tk_rightbrace); } /** token representing period @c "." **/ static Token dot() { return Token(tokentype::tk_dot); } @@ -113,8 +113,8 @@ namespace xo { static Token doublecolon() { return Token(tokentype::tk_doublecolon); } /** token representing semicolon @c ";" **/ static Token semicolon() { return Token(tokentype::tk_semicolon); } - /** token representing single-assignment @c "=" **/ - static Token singleassign() { return Token(tokentype::tk_singleassign); } + /** token representing single-assignment @c "=" (editor bait: equal_token) **/ + static Token singleassign_token() { return Token(tokentype::tk_singleassign); } /** token representing unrestricted assignment @c ":=" **/ static Token assign_token() { return Token(tokentype::tk_assign); } /** token representing indirection @c "->" **/ From c60aeda12a7da0b1c1d07fb37c8dccca2876ef97 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 21 Jan 2026 17:35:01 -0500 Subject: [PATCH 103/342] xo-reader2: DefineSsm: respond to = token --- include/xo/reader2/DDefineSsm.hpp | 7 +++++ include/xo/reader2/ParserStateMachine.hpp | 3 ++ include/xo/reader2/SchematikaParser.hpp | 16 +++++++++++ src/reader2/CMakeLists.txt | 1 + src/reader2/ParserStateMachine.cpp | 6 ++++ src/reader2/SchematikaParser.cpp | 18 +++++++++--- src/reader2/syntaxstatetype.cpp | 34 +++++++++++++++++++++++ utest/SchematikaParser.test.cpp | 24 ++++++++++++++++ 8 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 src/reader2/syntaxstatetype.cpp diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 5308f77a..ed17a1b2 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -98,6 +98,13 @@ namespace xo { obj expr_mm, ParserStateMachine * p_psm); + ///@} + /** @defgroup scm-definessm-access-methods **/ + ///@{ + + /** identify define-expression state **/ + defexprstatetype defstate() const noexcept { return defstate_; } + ///@} /** @defgroup scm-define-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index bcd8f557..7e3bcabb 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -54,6 +54,9 @@ namespace xo { /** true iff state machine currently has incomplete expression **/ bool has_incomplete_expr() const noexcept; + /** top of parser stack **/ + obj top_ssm() const; + ///@} /** @defgroup scm-parserstatemachine-bookkeeping bookkeeping methods **/ diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 300980fb..aecc3c9a 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -172,6 +172,9 @@ namespace xo { obj expr_alloc, bool debug_flag); + /** scm-schematikaparser-access-methods **/ + ///@{ + bool debug_flag() const { return debug_flag_; } /** true if parser is at top-level, @@ -185,6 +188,13 @@ namespace xo { **/ bool has_incomplete_expr() const; + /** top of parser stack **/ + obj top_ssm() const; + + ///@} + /** scm-schematikaparser-general-methods **/ + ///@{ + /** put parser into state for beginning an interactive session. **/ void begin_interactive_session(); @@ -215,11 +225,17 @@ namespace xo { **/ void reset_to_idle_toplevel(); + ///@} + /** scm-schematikaparser-pretty-methods **/ + ///@{ + /** print human-readable representation on stream @p os **/ void print(std::ostream & os) const; /** pretty-printer support **/ bool pretty(const ppindentinfo & ppii) const; + ///@} + private: /** state machine **/ ParserStateMachine psm_; diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index b09f015a..5ce73d67 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -9,6 +9,7 @@ set(SELF_SRCS ParserStack.cpp ParserResult.cpp + syntaxstatetype.cpp ISyntaxStateMachine_Any.cpp DExprSeqState.cpp diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index b74de542..dbed93d9 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -42,6 +42,12 @@ namespace xo { return !(this->is_at_toplevel()); } + obj + ParserStateMachine::top_ssm() const + { + return this->stack_->top(); + } + void ParserStateMachine::establish_toplevel_ssm(obj ssm) { diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index d243de51..fea573c7 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -28,23 +28,33 @@ namespace xo { } bool - SchematikaParser::is_at_toplevel() const { + SchematikaParser::is_at_toplevel() const + { return psm_.is_at_toplevel(); } bool - SchematikaParser::has_incomplete_expr() const { + SchematikaParser::has_incomplete_expr() const + { return !(this->is_at_toplevel()); } + obj + SchematikaParser::top_ssm() const + { + return psm_.top_ssm(); + } + void - SchematikaParser::begin_interactive_session() { + SchematikaParser::begin_interactive_session() + { DExprSeqState::establish_interactive(psm_.expr_alloc(), &psm_); } void - SchematikaParser::begin_batch_session() { + SchematikaParser::begin_batch_session() + { DExprSeqState::establish_batch(psm_.expr_alloc(), &psm_); } diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp new file mode 100644 index 00000000..cf8a9784 --- /dev/null +++ b/src/reader2/syntaxstatetype.cpp @@ -0,0 +1,34 @@ +/** @file syntaxstatetype.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "syntaxstatetype.hpp" + +namespace xo { + namespace scm { + + const char * + syntaxstatetype_descr(syntaxstatetype x) { + switch (x) { + case syntaxstatetype::invalid: + break; + case syntaxstatetype::expect_toplevel_expression_sequence: + return "expect-toplevel-expression-sequence"; + case syntaxstatetype::expect_symbol: + return "expect-symbol"; + case syntaxstatetype::expect_type: + return "expect-type"; + case syntaxstatetype::defexpr: + return "defexpr"; + case syntaxstatetype::N: + break; + } + + return "syntaxstatetype?"; + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end syntaxstatetype.cpp */ diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index af9b8303..203f2eaa 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -4,12 +4,18 @@ **/ #include +#include +#include #include #include #include namespace xo { using xo::scm::SchematikaParser; + using xo::scm::ASyntaxStateMachine; + using xo::scm::syntaxstatetype; + using xo::scm::DDefineSsm; + using xo::scm::defexprstatetype; using xo::scm::ParserResult; using xo::scm::parser_result_type; using xo::scm::Token; @@ -134,6 +140,24 @@ namespace xo { log && log(xtag("result", result)); } + { + auto & result = parser.on_token(Token::singleassign_token()); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(result.is_incomplete()); + + log && log("after typename symbol token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + auto def_ssm + = obj::from(parser.top_ssm()); + + REQUIRE(def_ssm); + REQUIRE(def_ssm.data()->ssm_type() == syntaxstatetype::defexpr); + REQUIRE(def_ssm.data()->defstate() == defexprstatetype::def_5); + } + // define-expressions not properly implemented //REQUIRE(result.error_description()); From 124d848a57f52fe673b621ebb55f66677d4297f3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 21 Jan 2026 18:39:53 -0500 Subject: [PATCH 104/342] xo-reader2: skeleton DExpectExprSsm.* --- include/xo/reader2/DExpectExprSsm.hpp | 113 ++++++++++ src/reader2/CMakeLists.txt | 2 + src/reader2/DExpectExprSsm.cpp | 301 ++++++++++++++++++++++++++ 3 files changed, 416 insertions(+) create mode 100644 include/xo/reader2/DExpectExprSsm.hpp create mode 100644 src/reader2/DExpectExprSsm.cpp diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp new file mode 100644 index 00000000..788f04e8 --- /dev/null +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -0,0 +1,113 @@ +/** @file DExpectExprSsm.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "ParserStateMachine.hpp" +#include "syntaxstatetype.hpp" +//#include +#include +#include + +namespace xo { + namespace scm { + + class DExpectExprSsm { + public: + using TypeDescr = xo::reflect::TypeDescr; + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; + + public: + explicit DExpectExprSsm(bool allow_defs, + bool cxl_on_rightparen); + + static DExpectExprSsm * make(DArena & parser_mm, + bool allow_defs, + bool cxl_on_rightparen); + + static void start(DArena & parser_mm, + bool allow_defs, + bool cxl_on_rightparen, + ParserStateMachine * p_psm); + + /** @defgroup scm-expectexpr-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** text describing expected/allowed input to this ssm in current state. + * Intended to drive error mesages + **/ + std::string_view get_expect_str() const noexcept; + + /** operate state machine for this syntax on incoming symbol-token @p tk + * with overall parser state in @p p_psm + **/ + void on_symbol_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming token @p tk, + * overall parser state in @p p_psm + **/ + void on_def_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming token @p tk, + * overall parser state in @p p_psm + **/ + void on_if_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming colon token @p tk, + * overall parser state in @p p_psm + **/ + void on_colon_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming singleassign token @p tk, + * overall parser state in @p p_psm + **/ + void on_singleassign_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax after parsing a symbol @p sym; + * overall parser state in @p p_psm + **/ + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); + + /** update state for this syntax after parsing a type-description @p td, + * overall parser state in @p p_psm + **/ + void on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-define-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + /** if true: allow a define-expression here; otherwise reject **/ + bool allow_defs_ = false; + /** if true: expecting either: + * 1a. expression + * 1b. right brace '}', in which case no expression + * if false: expecting only: + * 2a. expression + **/ + bool cxl_on_rightbrace_ = false; + + + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectExprSsm.hpp */ diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 5ce73d67..661aae2e 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -28,6 +28,8 @@ set(SELF_SRCS ISyntaxStateMachine_DExpectTypeSsm.cpp IPrintable_DExpectTypeSsm.cpp + DExpectExprSsm.cpp + reader2_register_facets.cpp reader2_register_types.cpp ) diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp new file mode 100644 index 00000000..696aa790 --- /dev/null +++ b/src/reader2/DExpectExprSsm.cpp @@ -0,0 +1,301 @@ +/** @file DExpectExprSsm.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DExpectExprSsm.hpp" +#include "ParserStateMachine.hpp" + +#ifdef NOT_YET +#include "exprstatestack.hpp" +#include "define_xs.hpp" +#include "lambda_xs.hpp" +#include "if_else_xs.hpp" +#include "paren_xs.hpp" +#include "sequence_xs.hpp" +#include "progress_xs.hpp" +#include "xo/expression/Lambda.hpp" +#include "xo/expression/Constant.hpp" +#include "xo/expression/pretty_expression.hpp" +#endif + +namespace xo { +#ifdef NOT_YET + using xo::scm::Constant; +#endif + + namespace scm { + +#ifdef NOT_YET + std::unique_ptr + expect_expr_xs::make(bool allow_defs, + bool cxl_on_rightbrace) + { + return std::make_unique(expect_expr_xs(allow_defs, + cxl_on_rightbrace)); + + } + + void + expect_expr_xs::start(bool allow_defs, + bool cxl_on_rightbrace, + parserstatemachine * p_psm) + { + p_psm->push_exprstate(expect_expr_xs::make(allow_defs, + cxl_on_rightbrace)); + } + + void + expect_expr_xs::start(parserstatemachine * p_psm) { + start(false /*!allow_defs*/, + false /*!cxl_on_rightbrace*/, + p_psm); + } + + expect_expr_xs::expect_expr_xs(bool allow_defs, + bool cxl_on_rightbrace) + : exprstate(exprstatetype::expect_rhs_expression), + allow_defs_{allow_defs}, + cxl_on_rightbrace_{cxl_on_rightbrace} + {} + + const char * + expect_expr_xs::get_expect_str() const + { + if (allow_defs_) { + return "def|lambda|lparen|lbrace|literal|var"; + } else { + return "lambda|lparen|lbrace|literal|var"; + } + } + + void + expect_expr_xs::on_def_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + if (allow_defs_) { + define_xs::start(p_psm); + } else { + exprstate::on_def_token(tk, p_psm); + } + } + + void + expect_expr_xs::on_lambda_token(const token_type & /*tk*/, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + //constexpr const char * self_name = "exprstate::on_leftparen"; + + lambda_xs::start(p_psm); + } + + void + expect_expr_xs::on_if_token(const token_type & /*tk*/, + parserstatemachine * p_psm) + { + if_else_xs::start(p_psm); + } + + void + expect_expr_xs::on_leftparen_token(const token_type & /*tk*/, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + //constexpr const char * self_name = "exprstate::on_leftparen"; + + /* push lparen_0 to remember to look for subsequent rightparen. */ + paren_xs::start(p_psm); + } + + void + expect_expr_xs::on_leftbrace_token(const token_type & /*tk*/, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + /* push lparen_0 to remember to look for subsequent rightparen. */ + sequence_xs::start(p_psm); + } + + void + expect_expr_xs::on_rightbrace_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + if (cxl_on_rightbrace_) { + auto self = p_psm->pop_exprstate(); + + /* do not call .on_expr(), since '}' cancelled */ + + p_psm->on_rightbrace_token(tk); + } else { + exprstate::on_rightbrace_token(tk, p_psm); + } + } + + void + expect_expr_xs::on_symbol_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log(xtag("tk", tk)); + + constexpr const char * c_self_name = "expect_expr_xs::on_symbol_token"; + + /* various possibilities when looking for rhs expression: + * + * x := y // (1) + * x := f(a) // (2) + * x := f(a,b) // (3) + * + * need lookahead token following symbol to distinguish + * between (1) (symbol completes rhs expression) + * and {(2), (3)} (symbol is function call) + */ + + bp var = p_psm->lookup_var(tk.text()); + + if (!var) { + this->unknown_variable_error(c_self_name, tk, p_psm); + return; + } + + /* e.g. + * def pi = 3.14159265; + * def mypi = pi; + * ^ + * def pi2 = pi * 2; + * ^ + * def y = foo(pi2); + * ^ + */ + progress_xs::start(var.promote(), p_psm); + + #ifdef NOT_YET + p_stack->push_exprstate(exprstate(exprstatetype::expr_progress, + Variable::make(name, type))); +#endif + +#ifdef LATER + p_psm->pop_exprstate(); + p_psm->top_exprstate().on_symbol(tk.text(), + p_stack, p_emit_expr); +#endif + return; + } + + void + expect_expr_xs::on_bool_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + progress_xs::start + (Constant::make(tk.bool_value()), + p_psm); + } + + void + expect_expr_xs::on_i64_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), + xtag("tk", tk), + xtag("do", "push progress xs w/ tk value")); + + progress_xs::start + (Constant::make(tk.i64_value()), + p_psm); + } + + void + expect_expr_xs::on_f64_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + //constexpr const char * self_name = "exprstate::on_f64_token"; + + /* e.g. + * def pi = 3.14159265; + * \---tk---/ + */ + progress_xs::start + (Constant::make(tk.f64_value()), + p_psm); + } + + void + expect_expr_xs::on_string_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + /* e.g. + * def msg = "hello, world"; + * \----tk----/ + */ + progress_xs::start + (Constant::make(tk.text()), + p_psm); + } + + void + expect_expr_xs::on_expr(bp expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log(xtag("exstype", this->exs_type_), + xtag("expr", expr.promote())); + log && log("pop expect_expr_xs, forward to parent"); + + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->on_expr(expr); + } /*on_expr*/ + + void + expect_expr_xs::on_expr_with_semicolon(bp expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log(xtag("exstype", this->exs_type_), + xtag("expr", expr.promote())); + log && log("pop expect_expr_xs, forward to parent"); + + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->on_expr_with_semicolon(expr); + } /*on_expr_with_semicolon*/ + + void + expect_expr_xs::print(std::ostream & os) const { + os << ""; + } + + bool + expect_expr_xs::pretty_print(const xo::print::ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, "expect_expr_xs", + refrtag("allow_defs", allow_defs_), + refrtag("cxl_on_rightbrace", cxl_on_rightbrace_)); + } +#endif + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectExprSsm.cpp */ From 55149f08901b71b5387a18daa6167edace16681c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 22 Jan 2026 10:54:36 -0500 Subject: [PATCH 105/342] xo-reader2: + DExpectExprSsm + use from DDefineSsm --- CMakeLists.txt | 26 ++++ idl/IPrintable_DExpectExprSsm.json5 | 13 ++ idl/ISyntaxStateMachine_DExpectExprSsm.json5 | 13 ++ include/xo/reader2/DExpectExprSsm.hpp | 9 ++ .../reader2/ssm/IPrintable_DExpectExprSsm.hpp | 62 ++++++++ .../ISyntaxStateMachine_DExpectExprSsm.hpp | 77 ++++++++++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 2 + src/reader2/DDefineSsm.cpp | 6 +- src/reader2/DExpectExprSsm.cpp | 137 +++++++++++++++--- src/reader2/IPrintable_DExpectExprSsm.cpp | 28 ++++ .../ISyntaxStateMachine_DExpectExprSsm.cpp | 69 +++++++++ src/reader2/reader2_register_facets.cpp | 7 + src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 35 ++++- 15 files changed, 465 insertions(+), 24 deletions(-) create mode 100644 idl/IPrintable_DExpectExprSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DExpectExprSsm.json5 create mode 100644 include/xo/reader2/ssm/IPrintable_DExpectExprSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp create mode 100644 src/reader2/IPrintable_DExpectExprSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d8c82e1d..11ce1f07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,6 +138,32 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expectexprssm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ExpectExprSsm + INPUT idl/ISyntaxStateMachine_DExpectExprSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expectexprssm + FACET_PKG xo_printable2 + FACET Printable + REPR ExpectExprSsm + INPUT idl/IPrintable_DExpectExprSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-reader2-genfacet-all) # ---------------------------------------------------------------- diff --git a/idl/IPrintable_DExpectExprSsm.json5 b/idl/IPrintable_DExpectExprSsm.json5 new file mode 100644 index 00000000..72d19cd7 --- /dev/null +++ b/idl/IPrintable_DExpectExprSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectExprSsm", + using_doxygen: true, + repr: "DExpectExprSsm", + doc: [ "implement APrintable for DExpectExprSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DExpectExprSsm.json5 b/idl/ISyntaxStateMachine_DExpectExprSsm.json5 new file mode 100644 index 00000000..068ac481 --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectExprSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectExprSsm", + using_doxygen: true, + repr: "DExpectExprSsm", + doc: [ "implement ASyntaxStateMachine for DExpectExprSsm" ], +} \ No newline at end of file diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 788f04e8..07456d76 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -32,7 +32,16 @@ namespace xo { bool allow_defs, bool cxl_on_rightparen, ParserStateMachine * p_psm); + static void start(DArena & parser_mm, + ParserStateMachine * p_psm); + /** @defgroup scm-expectexpr-access-methods access methods **/ + ///@{ + + bool allow_defs() const noexcept { return allow_defs_; } + bool cxl_on_rightbrace() const noexcept { return cxl_on_rightbrace_; } + + ///@} /** @defgroup scm-expectexpr-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/include/xo/reader2/ssm/IPrintable_DExpectExprSsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectExprSsm.hpp new file mode 100644 index 00000000..c3f9abc0 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DExpectExprSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectExprSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectExprSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectExprSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectExprSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectExprSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectExprSsm + **/ + class IPrintable_DExpectExprSsm { + public: + /** @defgroup scm-printable-dexpectexprssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpectexprssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectExprSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp new file mode 100644 index 00000000..5921f615 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -0,0 +1,77 @@ +/** @file ISyntaxStateMachine_DExpectExprSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectExprSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectExprSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectExprSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectExprSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectExprSsm + **/ + class ISyntaxStateMachine_DExpectExprSsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpectexprssm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexpectexprssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectExprSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectExprSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming symbol-token @p tk **/ + static void on_symbol_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming define-keyword-token @p tk **/ + static void on_def_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming if-keyword-token @p tk **/ + static void on_if_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming colon-token @p tk **/ + static void on_colon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming singleassign-token @p tk **/ + static void on_singleassign_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectExprSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectExprSsm & self, TypeDescr td, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 8cb48938..312ec07c 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -27,6 +27,9 @@ namespace xo { /** expecting a type. See @ref DExpectTypeSsm **/ expect_type, + /** expecting a rhs expression. See @ref DExpectExprSsm **/ + expect_rhs_expression, + /** handle define-expression. See @ref DDefineSsm **/ defexpr, diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 661aae2e..ecf8f297 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -29,6 +29,8 @@ set(SELF_SRCS IPrintable_DExpectTypeSsm.cpp DExpectExprSsm.cpp + ISyntaxStateMachine_DExpectExprSsm.cpp + IPrintable_DExpectExprSsm.cpp reader2_register_facets.cpp reader2_register_types.cpp diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 78667376..ea0d976a 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -6,6 +6,7 @@ #include "DDefineSsm.hpp" #include "DExpectSymbolSsm.hpp" #include "DExpectTypeSsm.hpp" +#include "DExpectExprSsm.hpp" #include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" #include "ssm/IPrintable_DDefineSsm.hpp" #include @@ -554,9 +555,8 @@ namespace xo { { this->defstate_ = defexprstatetype::def_5; - // TODO: DExpectExprSsm::start(...) - log && log("STUB: DExpectExprSsm not implemented"); - + DExpectExprSsm::start(p_psm->parser_alloc(), + p_psm); return; } diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 696aa790..235f4b19 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -5,6 +5,10 @@ #include "DExpectExprSsm.hpp" #include "ParserStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" +#include "syntaxstatetype.hpp" +#include #ifdef NOT_YET #include "exprstatestack.hpp" @@ -24,43 +28,64 @@ namespace xo { using xo::scm::Constant; #endif + using xo::reflect::typeseq; + using xo::facet::with_facet; + namespace scm { -#ifdef NOT_YET - std::unique_ptr - expect_expr_xs::make(bool allow_defs, + DExpectExprSsm::DExpectExprSsm(bool allow_defs, + bool cxl_on_rightbrace) + : allow_defs_{allow_defs}, + cxl_on_rightbrace_{cxl_on_rightbrace} + { + } + + DExpectExprSsm * + DExpectExprSsm::make(DArena & mm, + bool allow_defs, bool cxl_on_rightbrace) { - return std::make_unique(expect_expr_xs(allow_defs, - cxl_on_rightbrace)); + void * mem = mm.alloc(typeseq::id(), + sizeof(DExpectExprSsm)); + return new (mem) DExpectExprSsm(allow_defs, + cxl_on_rightbrace); } void - expect_expr_xs::start(bool allow_defs, + DExpectExprSsm::start(DArena & mm, + bool allow_defs, bool cxl_on_rightbrace, - parserstatemachine * p_psm) + ParserStateMachine * p_psm) { - p_psm->push_exprstate(expect_expr_xs::make(allow_defs, - cxl_on_rightbrace)); + DExpectExprSsm * exp_expr + = DExpectExprSsm::make(mm, + allow_defs, + cxl_on_rightbrace); + obj ssm + = with_facet::mkobj(exp_expr); + + p_psm->push_ssm(ssm); } void - expect_expr_xs::start(parserstatemachine * p_psm) { - start(false /*!allow_defs*/, + DExpectExprSsm::start(DArena & mm, + ParserStateMachine * p_psm) + { + start(mm, + false /*!allow_defs*/, false /*!cxl_on_rightbrace*/, p_psm); } - expect_expr_xs::expect_expr_xs(bool allow_defs, - bool cxl_on_rightbrace) - : exprstate(exprstatetype::expect_rhs_expression), - allow_defs_{allow_defs}, - cxl_on_rightbrace_{cxl_on_rightbrace} - {} + syntaxstatetype + DExpectExprSsm::ssm_type() const noexcept + { + return syntaxstatetype::expect_rhs_expression; + } - const char * - expect_expr_xs::get_expect_str() const + std::string_view + DExpectExprSsm::get_expect_str() const noexcept { if (allow_defs_) { return "def|lambda|lparen|lbrace|literal|var"; @@ -69,6 +94,80 @@ namespace xo { } } + void + DExpectExprSsm::on_symbol_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectExprSsm", + tk, + this->get_expect_str()); + } + + void + DExpectExprSsm::on_def_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectExprSsm", + tk, + this->get_expect_str()); + } + + void + DExpectExprSsm::on_if_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectExprSsm", + tk, + this->get_expect_str()); + } + + void + DExpectExprSsm::on_colon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectExprSsm", + tk, + this->get_expect_str()); + } + + void + DExpectExprSsm::on_singleassign_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectExprSsm", + tk, + this->get_expect_str()); + } + + void + DExpectExprSsm::on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol("DExpectExprSsm", + sym, + this->get_expect_str()); + } + + void + DExpectExprSsm::on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_typedescr("DExpectExprSsm", + td, + this->get_expect_str()); + } + + bool + DExpectExprSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct + (ppii, + "DExpectExprSsm", + refrtag("allow_defs", allow_defs_), + refrtag("cxl_on_rightbrace", cxl_on_rightbrace_)); + } + +#ifdef NOT_YET void expect_expr_xs::on_def_token(const token_type & tk, parserstatemachine * p_psm) diff --git a/src/reader2/IPrintable_DExpectExprSsm.cpp b/src/reader2/IPrintable_DExpectExprSsm.cpp new file mode 100644 index 00000000..2b656fb2 --- /dev/null +++ b/src/reader2/IPrintable_DExpectExprSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectExprSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectExprSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectExprSsm.json5] +**/ + +#include "ssm/IPrintable_DExpectExprSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectExprSsm::pretty(const DExpectExprSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectExprSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp new file mode 100644 index 00000000..de751479 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -0,0 +1,69 @@ +/** @file ISyntaxStateMachine_DExpectExprSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectExprSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectExprSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectExprSsm::ssm_type(const DExpectExprSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectExprSsm::get_expect_str(const DExpectExprSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectExprSsm::on_symbol_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_symbol_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectExprSsm::on_def_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_def_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectExprSsm::on_if_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_if_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectExprSsm::on_colon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_colon_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectExprSsm::on_singleassign_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_singleassign_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectExprSsm::on_parsed_symbol(DExpectExprSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExpectExprSsm::on_parsed_typedescr(DExpectExprSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectExprSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index a393eead..cdade07b 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -17,6 +17,9 @@ #include #include +#include +#include + #include #include #include @@ -45,10 +48,14 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + log && log(xtag("DExprSeqState.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); log && log(xtag("DExpectSymbolSsm.tseq", typeseq::id())); log && log(xtag("DExpectTypeSsm.tseq", typeseq::id())); + log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); return true; } diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index cf8a9784..ac09b92e 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -19,6 +19,8 @@ namespace xo { return "expect-symbol"; case syntaxstatetype::expect_type: return "expect-type"; + case syntaxstatetype::expect_rhs_expression: + return "expect-rhs-expression"; case syntaxstatetype::defexpr: return "defexpr"; case syntaxstatetype::N: diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 203f2eaa..e0f813e4 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include #include @@ -15,10 +17,12 @@ namespace xo { using xo::scm::ASyntaxStateMachine; using xo::scm::syntaxstatetype; using xo::scm::DDefineSsm; + using xo::scm::DExpectExprSsm; using xo::scm::defexprstatetype; - using xo::scm::ParserResult; - using xo::scm::parser_result_type; + //using xo::scm::ParserResult; + //using xo::scm::parser_result_type; using xo::scm::Token; + using xo::scm::DString; using xo::mm::ArenaConfig; using xo::mm::AAllocator; using xo::mm::DArena; @@ -150,12 +154,39 @@ namespace xo { log && log(xtag("parser", &parser)); log && log(xtag("result", result)); + auto exp_ssm + = obj::from(parser.top_ssm()); + + REQUIRE(exp_ssm); + REQUIRE(exp_ssm.data()->ssm_type() == syntaxstatetype::expect_rhs_expression); + REQUIRE(exp_ssm.data()->allow_defs() == false); + REQUIRE(exp_ssm.data()->cxl_on_rightbrace() == false); + } + +#ifdef NOT_YET + { + // future-proofing for Token only holding a string_view + const DString * str = DString::from_cstr(expr_alloc, "3.141593"); + + auto & result = parser.on_token(Token::f64_token(std::string(*str))); + + REQUIRE(parser.has_incomplete_expr() == true); + + log && log("after typename symbol token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + } +#endif + + { +#ifdef NOT_YET auto def_ssm = obj::from(parser.top_ssm()); REQUIRE(def_ssm); REQUIRE(def_ssm.data()->ssm_type() == syntaxstatetype::defexpr); REQUIRE(def_ssm.data()->defstate() == defexprstatetype::def_5); +#endif } // define-expressions not properly implemented From d30412779c5125c7c7ba0e9b791bcf111c179a4e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 22 Jan 2026 15:18:35 -0500 Subject: [PATCH 106/342] xo-reader2: + on_f64_token() + handle in DDefineSsm+DProgressSsm --- CMakeLists.txt | 26 + idl/IPrintable_DProgressSsm.json5 | 13 + idl/ISyntaxStateMachine_DProgressSsm.json5 | 13 + idl/SyntaxStateMachine.json5 | 9 + include/xo/reader2/DDefineSsm.hpp | 6 + include/xo/reader2/DExpectExprSsm.hpp | 6 + include/xo/reader2/DExpectSymbolSsm.hpp | 6 + include/xo/reader2/DExpectTypeSsm.hpp | 6 + include/xo/reader2/DExprSeqState.hpp | 5 + include/xo/reader2/DProgressSsm.hpp | 220 +++++ include/xo/reader2/ParserStateMachine.hpp | 3 + .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 + .../reader2/ssm/IPrintable_DExpectExprSsm.hpp | 2 +- .../reader2/ssm/IPrintable_DProgressSsm.hpp | 62 ++ .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 + .../ISyntaxStateMachine_DExpectExprSsm.hpp | 4 +- .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 + .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 + .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 + .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 79 ++ .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 + .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 + include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 4 + src/reader2/DDefineSsm.cpp | 9 + src/reader2/DExpectExprSsm.cpp | 31 + src/reader2/DExpectSymbolSsm.cpp | 9 + src/reader2/DExpectTypeSsm.cpp | 9 + src/reader2/DExprSeqState.cpp | 9 + src/reader2/DProgressSsm.cpp | 932 ++++++++++++++++++ src/reader2/IPrintable_DExpectExprSsm.cpp | 2 +- src/reader2/IPrintable_DProgressSsm.cpp | 28 + src/reader2/ISyntaxStateMachine_Any.cpp | 6 + .../ISyntaxStateMachine_DDefineSsm.cpp | 5 + .../ISyntaxStateMachine_DExpectExprSsm.cpp | 7 +- .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 + .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 + .../ISyntaxStateMachine_DExprSeqState.cpp | 5 + .../ISyntaxStateMachine_DProgressSsm.cpp | 74 ++ src/reader2/ParserStateMachine.cpp | 13 +- src/reader2/reader2_register_facets.cpp | 7 + src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 4 +- 44 files changed, 1638 insertions(+), 8 deletions(-) create mode 100644 idl/IPrintable_DProgressSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DProgressSsm.json5 create mode 100644 include/xo/reader2/DProgressSsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DProgressSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp create mode 100644 src/reader2/DProgressSsm.cpp create mode 100644 src/reader2/IPrintable_DProgressSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DProgressSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 11ce1f07..bc35b6a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -164,6 +164,32 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-progressssm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ProgressSsm + INPUT idl/ISyntaxStateMachine_DProgressSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-progressssm + FACET_PKG xo_printable2 + FACET Printable + REPR ProgressSsm + INPUT idl/IPrintable_DProgressSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-reader2-genfacet-all) # ---------------------------------------------------------------- diff --git a/idl/IPrintable_DProgressSsm.json5 b/idl/IPrintable_DProgressSsm.json5 new file mode 100644 index 00000000..cc5a8dda --- /dev/null +++ b/idl/IPrintable_DProgressSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DProgressSsm", + using_doxygen: true, + repr: "DProgressSsm", + doc: [ "implement APrintable for DProgressSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DProgressSsm.json5 b/idl/ISyntaxStateMachine_DProgressSsm.json5 new file mode 100644 index 00000000..807e5ec3 --- /dev/null +++ b/idl/ISyntaxStateMachine_DProgressSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DProgressSsm", + using_doxygen: true, + repr: "DProgressSsm", + doc: [ "implement ASyntaxStateMachine for DProgressSsm" ], +} diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 2fcbd796..291108b3 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -90,6 +90,15 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_f64_token", + doc: ["update state machine for incoming f64-token @p tk"], + return_type: "void", + args: [ + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_parsed_symbol", doc: ["update stat machine for incoming parsed symbol @p sym"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index ed17a1b2..5718606d 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -147,6 +147,12 @@ namespace xo { void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_f64_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing a symbol @p sym; * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 07456d76..36ae3c47 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -83,6 +83,12 @@ namespace xo { void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_f64_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing a symbol @p sym; * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 7bbcec91..6584d1e4 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -103,6 +103,12 @@ namespace xo { void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_f64_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expectsymbol-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index c5d8ef5b..6f88615c 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -77,6 +77,12 @@ namespace xo { void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_f64_token(const Token & tk, + ParserStateMachine * p_psm); + /** (Never called). * Operate state machine for this syntax after symbol * emitted from nested ssm. diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 01fdfc16..1c62ced6 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -90,6 +90,11 @@ namespace xo { **/ void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on parsed symbol @p sym * from immediately-downstream ssm. * overall parser state in @p p_psm diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp new file mode 100644 index 00000000..0e22726c --- /dev/null +++ b/include/xo/reader2/DProgressSsm.hpp @@ -0,0 +1,220 @@ +/** @file DProgressSsm.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "ParserStateMachine.hpp" +#include "syntaxstatetype.hpp" +//#include +#include + +#ifdef NOT_YET +#include "exprstate.hpp" +#include "xo/reflect/TypeDescr.hpp" +#include +//#include +#endif + +namespace xo { + namespace scm { + /** represent an infix operator. + * + * See @ref progress_xs::assemble_expr() for translation + * to Expression + **/ + enum class optype { + invalid = -1, + + /** op:= **/ + op_assign, + + /** op< **/ + op_less, + /** op<= **/ + op_less_equal, + /** op== **/ + op_equal, + /** op!= **/ + op_not_equal, + /** op> **/ + op_great, + /** op>= **/ + op_great_equal, + + /** op+ **/ + op_add, + /** op- **/ + op_subtract, + + /** op* **/ + op_multiply, + /** op/ **/ + op_divide, + + n_optype + }; + + extern const char * + optype_descr(optype x); + + /** report operator precedence. + * lowest operator precedence is 1 + **/ + extern int + precedence(optype x); + + inline std::ostream & + operator<< (std::ostream & os, optype x) { + os << optype_descr(x); + return os; + } + + /** @class DProgressSsm + * @brief syntax state machine for parsing a schematica rhs-value-expression + * + * Handles an expression that produces a value, for example appearing on the + * right-hand side of a definition. + * + * Deals with: + * 1. infix operators including operator precedence. + * 2. generates argument-type-specific arithmetic expressions, + * for example using ``Apply::make_add2_f64()`` when adding floating-point numbers + * + * One reason for this to exist is to simulate one-token lookahead. + * To look at but not consume a token T, can push a progress_xs instance P, + * then send T to P. + **/ + class DProgressSsm { + public: + using TypeDescr = xo::reflect::TypeDescr; + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; + + public: + DProgressSsm(obj lhs, optype op); + + static DProgressSsm * make(DArena & parser_mm, + obj lhs, + optype op); + + static void start(DArena & parser_mm, + obj valex, + ParserStateMachine * p_psm); + +#ifdef NOT_YET + static void start(rp valex, + optype optype, + parserstatemachine * p_psm); +#endif + + syntaxstatetype ssm_type() const noexcept; + +#ifdef NOT_YET + bool admits_f64() const; + + void apply_type_error(const char * self_name, + optype op, + bp expr1, + bp expr2, + parserstatemachine * p_psm) const; +#endif + + std::string_view get_expect_str() const noexcept; + +#ifdef NOT_YET + void on_expr(bp expr, + parserstatemachine * p_psm) override; + void on_expr_with_semicolon(bp expr, + parserstatemachine * p_psm) override; +#endif + void on_symbol_token(const Token & tk, + ParserStateMachine * p_psm); + void on_def_token(const Token & tk, + ParserStateMachine * p_psm); + void on_if_token(const Token & tk, + ParserStateMachine * p_psm); + void on_colon_token(const Token & tk, + ParserStateMachine * p_psm); + void on_singleassign_token(const Token & tk, + ParserStateMachine * p_psm); + void on_f64_token(const Token & tk, + ParserStateMachine * p_psm); + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); + void on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm); + + ///@{ + + /** @defgroup scm-progressssm-printable-facet printable facet methods **/ + bool pretty(const ppindentinfo & ppii) const; + +#ifdef NOT_YET + void on_comma_token(const token_type & tk, + parserstatemachine * p_psm) final override; + void on_typedescr(TypeDescr td, + parserstatemachine * p_psm) override; + + void on_semicolon_token(const token_type & tk, + parserstatemachine * p_psm) override; + void on_assign_token(const token_type & tk, + parserstatemachine * p_psm) final override; + void on_leftparen_token(const token_type & tk, + parserstatemachine * p_psm) override; + void on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) override; + void on_rightbrace_token(const token_type & tk, + parserstatemachine * p_psm) override; + void on_then_token(const token_type & tk, + parserstatemachine * p_psm) override; + void on_else_token(const token_type & tk, + parserstatemachine * p_psm) override; + + /* entry point for an infix operator token */ + void on_operator_token(const token_type & tk, + parserstatemachine * p_psm) final override; + + void on_bool_token(const token_type & tk, + parserstatemachine * p_psm) override; + + void on_i64_token(const token_type & tk, + parserstatemachine * p_psm) override; + + + void print(std::ostream & os) const override; + + private: + /** assemble expression representing + * value of + * @code + * f(lhs_, rhs_) + * @endcode + * + * where f determined by @ref op_type_ + **/ + obj assemble_expr(ParserStateMachine * p_psm); +#endif + + private: + /** populate an expression here, may be followed by an operator **/ + obj lhs_; + + /** infix operator, if supplied **/ + optype op_type_ = optype::invalid; + + /** populate an expression here, following infix operator */ + obj rhs_; + }; + } /*namespace scm*/ + +#ifndef ppdetail_atomic + namespace print { + PPDETAIL_ATOMIC(xo::scm::optype); + } +#endif +} /*namespace xo*/ + + +/* end DProgressSsm.hpp */ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 7e3bcabb..8a019e8c 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -122,6 +122,9 @@ namespace xo { /** operate state machine for incoming singleassign-token @p tk **/ void on_singleassign_token(const Token & tk); + /** operate state machine for incoming f64-token @p tk **/ + void on_f64_token(const Token & tk); + ///@} /** @defgroup scm-parserstatemachine-error-entrypoints error entry points **/ ///@{ diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index f8f23f2a..8eba08fe 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -67,6 +67,8 @@ public: virtual void on_colon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming singleassign-token @p tk **/ virtual void on_singleassign_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; + /** update state machine for incoming f64-token @p tk **/ + virtual void on_f64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update stat machine for incoming parsed symbol @p sym **/ virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/IPrintable_DExpectExprSsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectExprSsm.hpp index c3f9abc0..add5e046 100644 --- a/include/xo/reader2/ssm/IPrintable_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/IPrintable_DExpectExprSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExpectExprSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/IPrintable_DProgressSsm.hpp b/include/xo/reader2/ssm/IPrintable_DProgressSsm.hpp new file mode 100644 index 00000000..f9417bba --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DProgressSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DProgressSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DProgressSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DProgressSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DProgressSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DProgressSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DProgressSsm + **/ + class IPrintable_DProgressSsm { + public: + /** @defgroup scm-printable-dprogressssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dprogressssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DProgressSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 51e5cff0..86c180dd 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -65,6 +65,7 @@ namespace scm { [[noreturn]] void on_if_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_colon_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_singleassign_token(Opaque, const Token &, ParserStateMachine *) override; + [[noreturn]] void on_f64_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index dd2bdc29..06035486 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -64,6 +64,8 @@ namespace xo { static void on_colon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming singleassign-token @p tk **/ static void on_singleassign_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming f64-token @p tk **/ + static void on_f64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 5921f615..ec80e8c8 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExpectExprSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -64,6 +64,8 @@ namespace xo { static void on_colon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming singleassign-token @p tk **/ static void on_singleassign_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming f64-token @p tk **/ + static void on_f64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectExprSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 114208f6..b76b4d61 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -64,6 +64,8 @@ namespace xo { static void on_colon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming singleassign-token @p tk **/ static void on_singleassign_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming f64-token @p tk **/ + static void on_f64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index 7bf0d312..16c37fac 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -64,6 +64,8 @@ namespace xo { static void on_colon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming singleassign-token @p tk **/ static void on_singleassign_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming f64-token @p tk **/ + static void on_f64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index 73e8a1cc..59bf00b4 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -64,6 +64,8 @@ namespace xo { static void on_colon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming singleassign-token @p tk **/ static void on_singleassign_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming f64-token @p tk **/ + static void on_f64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp new file mode 100644 index 00000000..4c4fade2 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -0,0 +1,79 @@ +/** @file ISyntaxStateMachine_DProgressSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DProgressSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DProgressSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DProgressSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DProgressSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DProgressSsm + **/ + class ISyntaxStateMachine_DProgressSsm { + public: + /** @defgroup scm-syntaxstatemachine-dprogressssm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dprogressssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DProgressSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DProgressSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming symbol-token @p tk **/ + static void on_symbol_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming define-keyword-token @p tk **/ + static void on_def_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming if-keyword-token @p tk **/ + static void on_if_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming colon-token @p tk **/ + static void on_colon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming singleassign-token @p tk **/ + static void on_singleassign_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming f64-token @p tk **/ + static void on_f64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DProgressSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DProgressSsm & self, TypeDescr td, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index d86e9763..ef37f26d 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -67,6 +67,9 @@ namespace scm { void on_singleassign_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_singleassign_token(_dcast(data), tk, p_psm); } + void on_f64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_f64_token(_dcast(data), tk, p_psm); + } void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) override { return I::on_parsed_symbol(_dcast(data), sym, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 921da301..3c933117 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -71,6 +71,9 @@ public: void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_singleassign_token(O::data(), tk, p_psm); } + void on_f64_token(const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_f64_token(O::data(), tk, p_psm); + } void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { return O::iface()->on_parsed_symbol(O::data(), sym, p_psm); } diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 312ec07c..d7340b25 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -33,6 +33,9 @@ namespace xo { /** handle define-expression. See @ref DDefineSsm **/ defexpr, + /** rhs expression. state exists to achieve 1-token lookahead **/ + progress, + /** comes lasts, counts number of valid enums **/ N }; diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index ecf8f297..232174ef 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -32,6 +32,10 @@ set(SELF_SRCS ISyntaxStateMachine_DExpectExprSsm.cpp IPrintable_DExpectExprSsm.cpp + DProgressSsm.cpp + ISyntaxStateMachine_DProgressSsm.cpp + IPrintable_DProgressSsm.cpp + reader2_register_facets.cpp reader2_register_types.cpp ) diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index ea0d976a..5ba71d93 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -565,6 +565,15 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_f64_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DDefineSsm::on_f64_token", + tk, + this->get_expect_str()); + } + bool DDefineSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 235f4b19..abb5d076 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -7,7 +7,13 @@ #include "ParserStateMachine.hpp" #include "SyntaxStateMachine.hpp" #include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" +#include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" #include "syntaxstatetype.hpp" +#include +#include +#include +#include +#include #include #ifdef NOT_YET @@ -27,6 +33,8 @@ namespace xo { #ifdef NOT_YET using xo::scm::Constant; #endif + using xo::scm::DFloat; + using xo::mm::AGCObject; using xo::reflect::typeseq; using xo::facet::with_facet; @@ -139,6 +147,29 @@ namespace xo { this->get_expect_str()); } + void + DExpectExprSsm::on_f64_token(const Token & tk, + ParserStateMachine * p_psm) + { + auto f64o = DFloat::box(p_psm->expr_alloc(), + tk.f64_value()); + + auto expr = with_facet::mkobj(DConstant::make(p_psm->expr_alloc(), f64o)); + + // DProgressSsm responsible for resolving cases like + // 1.9, + // 1.9; + // 1.9 + 2; + // 1.9 + 2 .. // could be followed by infix + // 1.9 + 2 * 3; + // 1.9 + 2 * 3 .. // could be followed by infix + // 1.9 * (2 + 3) + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); + } + void DExpectExprSsm::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index e9b93cc5..6915ced4 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -131,6 +131,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_f64_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectSymbolSsm::on_f64_token", + tk, + this->get_expect_str()); + } + bool DExpectSymbolSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index b40916a9..44bdbdb0 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -92,6 +92,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectTypeSsm::on_f64_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectTypeSsm", + tk, + this->get_expect_str()); + } + void DExpectTypeSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 75e711cd..354f06fb 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -178,6 +178,15 @@ namespace xo { this->get_expect_str()); } + void + DExprSeqState::on_f64_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExprSeqState::on_f64_token", + tk, + this->get_expect_str()); + } + void DExprSeqState::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp new file mode 100644 index 00000000..a811dda9 --- /dev/null +++ b/src/reader2/DProgressSsm.cpp @@ -0,0 +1,932 @@ +/** @file DProgressSsm.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DProgressSsm.hpp" +#include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" +#include + +#ifdef NOT_YET +#include "apply_xs.hpp" +#include "exprstatestack.hpp" +#include "expect_expr_xs.hpp" +#include "parserstatemachine.hpp" +#include "pretty_exprstatestack.hpp" +#include "xo/expression/AssignExpr.hpp" +#include "xo/expression/Apply.hpp" +#include "xo/expression/pretty_expression.hpp" +#endif + +namespace xo { +#ifdef NOT_YET + using xo::scm::Expression; + using xo::scm::AssignExpr; + using xo::scm::Variable; + using xo::scm::Apply; +#endif + using xo::facet::with_facet; + using xo::reflect::typeseq; + + namespace scm { + const char * + optype_descr(optype x) { + switch (x) { + case optype::invalid: + return "?optype"; + case optype::op_assign: + return "op:="; + case optype::op_less: + return "op<"; + case optype::op_less_equal: + return "op<="; + case optype::op_equal: + return "op=="; + case optype::op_not_equal: + return "op!="; + case optype::op_great: + return "op>"; + case optype::op_great_equal: + return "op>="; + case optype::op_add: + return "op+"; + case optype::op_subtract: + return "op-"; + case optype::op_multiply: + return "op*"; + case optype::op_divide: + return "op/"; + case optype::n_optype: + break; + } + return "???"; + } + + int + precedence(optype x) { + switch (x) { + case optype::invalid: + case optype::n_optype: + return 0; + + case optype::op_assign: + return 1; + + case optype::op_less: + case optype::op_less_equal: + case optype::op_equal: + case optype::op_not_equal: + case optype::op_great: + case optype::op_great_equal: + return 2; + + case optype::op_add: + case optype::op_subtract: + return 3; + + case optype::op_multiply: + case optype::op_divide: + return 4; + } + + return 0; + } + + DProgressSsm * + DProgressSsm::make(DArena & mm, + obj lhs, + optype op) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DProgressSsm)); + + return new (mem) DProgressSsm(lhs, op); + + //return std::make_unique(progress_xs(std::move(valex), op)); + } + + void + DProgressSsm::start(DArena & parser_mm, + obj valex, + ParserStateMachine * p_psm) + { + DProgressSsm * progress_ssm + = DProgressSsm::make(parser_mm, valex, optype::invalid); + + obj ssm + = with_facet::mkobj(progress_ssm); + + p_psm->push_ssm(ssm); + } + +#ifdef NOT_YET + void + progress_xs::start(rp valex, optype op, parserstatemachine * p_psm) { + p_psm->push_exprstate(progress_xs::make(valex, op)); + } + +#endif + + DProgressSsm::DProgressSsm(obj valex, + optype op) + : lhs_{valex}, + op_type_{op} + {} + + syntaxstatetype + DProgressSsm::ssm_type() const noexcept + { + return syntaxstatetype::progress; + } + +#ifdef NOT_YET + bool + progress_xs::admits_f64() const { return false; } +#endif + + std::string_view + DProgressSsm::get_expect_str() const noexcept { + if (op_type_ == optype::invalid) { + return "oper|semicolon|rightparen"; + } else { + return "expr|leftparen"; + } + } + + void + DProgressSsm::on_symbol_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DProgressSsm::on_symbol_token", + tk, + this->get_expect_str()); + } + + void + DProgressSsm::on_def_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DProgressSsm::on_def_token", + tk, + this->get_expect_str()); + } + + void + DProgressSsm::on_if_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DProgressSsm::on_if_token", + tk, + this->get_expect_str()); + } + + void + DProgressSsm::on_colon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DProgressSsm::on_colon_token", + tk, + this->get_expect_str()); + } + + void + DProgressSsm::on_singleassign_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DProgressSsm::on_singleassign_token", + tk, + this->get_expect_str()); + } + + void + DProgressSsm::on_f64_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DProgressSsm::on_f64_token", + tk, + this->get_expect_str()); + } + + void + DProgressSsm::on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol("DProgressSsm::on_parsed_symbol", + sym, + this->get_expect_str()); + } + + void + DProgressSsm::on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_typedescr("DProgressSsm::on_parsed_typedescr", + td, + this->get_expect_str()); + } + +#ifdef NOT_YET + void + progress_xs::apply_type_error(const char * self_name, + optype op, + bp expr1, + bp expr2, + parserstatemachine * p_psm) const + { + std::string errmsg = tostr("incompatible argument types T1,T2 to op", + xtag("op", op), + xtag("T1", expr1->valuetype()), + xtag("T2", expr2->valuetype())); + + p_psm->on_error(self_name, std::move(errmsg)); + } + + rp + progress_xs::assemble_expr(parserstatemachine * p_psm) { + /* need to defer building Apply incase expr followed by higher-precedence operator: + * consider input like + * 3.14 + 2.0 * ... + */ + + constexpr const char * c_self_name = "progress_xs::assemble_expr"; + + if ((op_type_ != optype::invalid) && (rhs_.get() == nullptr)) { + std::string errmsg = tostr("expected expression on rhs of operator op", + xtag("lhs", lhs_), + xtag("op", op_type_)); + + p_psm->on_error(c_self_name, errmsg); + } + + /* consecutive expressions not legal, e.g: + * 3.14 6.28 + * but expressions surrounding an infix operators is: + * 3.14 / 6.28 + */ + switch (op_type_) { + case optype::invalid: + return this->lhs_; + + case optype::op_assign: + { + bp lhs = Variable::from(this->lhs_); + + if (!lhs) { + throw std::runtime_error + (tostr("progress_xs::assemble_expr", + " expect variable on lhs of assignment operator :=", + xtag("lhs", lhs_), + xtag("rhs", rhs_))); + } + + return AssignExpr::make(lhs.promote(), + this->rhs_); + } + + case optype::op_equal: + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_eq_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + + case optype::op_not_equal: + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_ne_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + + case optype::op_less: + // TODO: floating-point less-than + + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_lt_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + + case optype::op_less_equal: + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_le_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + + case optype::op_great: + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_gt_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + + case optype::op_great_equal: + // TODO: upconvert integer->double + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_ge_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + + assert(false); + + case optype::op_add: + // TODO: upconvert integer->double + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_add2_i64(lhs_, rhs_); + } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { + return Apply::make_add2_f64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + case optype::op_subtract: + // TODO: upconvert integer->double + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_sub2_i64(lhs_, rhs_); + } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { + return Apply::make_sub2_f64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + + case optype::op_multiply: + // TODO: upconvert integer->double + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_mul2_i64(lhs_, rhs_); + } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { + return Apply::make_mul2_f64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + + break; + + case optype::op_divide: + // TODO: upconvert integer->double + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_div2_i64(lhs_, rhs_); + } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { + return Apply::make_div2_f64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + + case optype::n_optype: + /* unreachable */ + assert(false); + return nullptr; + } + + return nullptr; + } + + void + progress_xs::on_expr(bp expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("expr", expr)); + + /* note: previous token probably an operator, + * handled from progress_xs::on_operator_token(), + * which pushes expect_expr_xs::expect_rhs_expression() + */ + + constexpr const char * c_self_name = "progress_xs::on_expr"; + const char * exp = get_expect_str(); + + if (lhs_) { + if (op_type_ == optype::invalid) { + /* two consecutive expression without an operator */ + this->illegal_input_on_expr(c_self_name, expr, exp, p_psm); + } + +#ifdef NOT_QUITE + assert(result.get()); + + /* this expression complete.. */ + std::unique_ptr self = p_psm->pop_exprstate(); + + /* ..but more operators could follow, so don't commit yet */ + p_stack->push_exprstate(progress_xs::make(result)); +#endif + + this->rhs_ = expr.promote(); + } else { + /* control here on input like + * add(1,2)... + * + * add(1,2) needs to be handled inside a progress_xs + * instance because may be followed by an operator: + * add(1,2) + ... + */ + this->lhs_ = expr.promote(); + } + } + + void + progress_xs::on_expr_with_semicolon(bp expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log(xtag("lhs", lhs_), xtag("op", op_type_), xtag("expr", expr)); + + constexpr const char * c_self_name = "progress_xs::on_expr_with_semicolon"; + const char * exp = get_expect_str(); + + if (op_type_ == optype::invalid) { + this->illegal_input_on_expr(c_self_name, expr, exp, p_psm); + } + + this->rhs_ = expr.promote(); + + // FORBIDDEN, because .on_semicolon_token() destroys *this before returning + // this->on_semicolon_token(token_type::semicolon(), p_psm); + // INSTEAD, spell out the body + + rp expr2 = this->assemble_expr(p_psm); + + if (expr2) { + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->on_expr_with_semicolon(expr2); + } + } +#endif + +#ifdef NOT_YET + void + progress_xs::on_comma_token(const token_type & tk, + parserstatemachine * p_psm) + { + /* note: implementation parllels .on_semicolon_token(), .on_rightparen_token() */ + + scope log(XO_DEBUG(p_psm->debug_flag())); + + constexpr const char * self_name = "progress::xs::on_comma_token"; + + auto & xs_stack = p_psm->xs_stack_; + + /* stack may be something like + * + * applyexpr + * expect_expr_xs + * progress_xs + * <-- comma + * + * 1. comma completes expression-in-progress + */ + + /* comma confirms stack expression */ + rp expr = this->assemble_expr(p_psm); + + std::unique_ptr self = p_psm->pop_exprstate(); + + if (xs_stack.empty()) { + throw std::runtime_error(tostr(self_name, + ": expected non-empty parsing state")); + } + + log && log(xtag("stack", &xs_stack)); + + p_psm->top_exprstate().on_expr(expr, p_psm); + + /* now deliver comma */ + p_psm->top_exprstate().on_comma_token(tk, p_psm); + } + + void + progress_xs::on_typedescr(TypeDescr /*td*/, + parserstatemachine * /*p_psm*/) + { + /* unreachable */ + assert(false); + } + + void + progress_xs::on_semicolon_token(const token_type & /*tk*/, + parserstatemachine * p_psm) + { + /* note: implementation parallels .on_rightparen_token() */ + + scope log(XO_DEBUG(p_psm->debug_flag())); + + rp expr = this->assemble_expr(p_psm); + + log && log(xtag("assembled-expr", expr)); + + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->on_expr_with_semicolon(expr); + + /* control here on input like: + * (1.234; + * + * a. '(' sets up stack [lparen_0:expect_rhs_expression] + * (see exprstate::on_leftparen()) + * b. 1.234 pushes (in case operators) [lparen_0:expect_rhs_expression:expr_progress] + * (see exprstate::on_f64()) + * c. semicolon completes expr_progress [lparen_0:expect_rhs_expression] + * deliver expresssion to expect_rhs_expression.on_expr_with_semicolon() + * (see exprstate::on_expr_with_semicolon()) + * d. expr_rhs_expression forwards expression to [lparen_0] + * e. lparen_0 would advance to [lparen_1], but rejects semicolon + */ + } + + void + progress_xs::on_assign_token(const token_type & tk, + parserstatemachine * p_psm) + { + this->on_operator_token(tk, p_psm); + } + + /* editor bait: on_lparen */ + void + progress_xs::on_leftparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + /* input like: + * 'foo(' -> expect function call. might continue 'foo(a,b,c)' + * 'foo+(' -> expect parenthesized expression. might continue 'foo+(bar/2)' + */ + + if (op_type_ == optype::invalid) { + /* start function call */ + assert(rhs_.get() == nullptr); + + rp fn_expr = lhs_; + + /* reset this progress_xs back to empty state; + * apply_xs will be responsible for lhs_. + */ + lhs_ = nullptr; + +#ifdef OBSOLETE + /* don't unwind! want to handle input like + * f(x,y)+g(z) + */ + /* unwind this progress_xs + replace with function call */ + std::unique_ptr self = p_psm->pop_exprstate(); +#endif + + apply_xs::start(fn_expr, p_psm); + + /* control will reenter progress_xs via .on_expr() */ + return; + } + + constexpr const char * c_self_name = "exprstate::on_leftparen"; + const char * exp = get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + + void + progress_xs::on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + /* note: implementation parallels .on_semicolon_token() */ + + scope log(XO_DEBUG(p_psm->debug_flag())); + + constexpr const char * self_name = "progress_xs::on_rightparen"; + + auto & xs_stack = p_psm->xs_stack_; + + /* stack may be something like: + * + * lparen_0 + * expect_expr_xs + * expr_progress + * <-- rightparen + * + * 1. rightparen completes expression-in-progress + * 2. rightparen must then match innermost waiting lparen_0 + */ + + /* right paren confirms stack expression */ + rp expr = this->assemble_expr(p_psm); + + log && log(xtag("expr", expr), + xtag("do", "pop self + send {expr, rparen} -> parent")); + + std::unique_ptr self = p_psm->pop_exprstate(); + + if (xs_stack.empty()) { + throw std::runtime_error(tostr(self_name, + ": expected non-empty parsing stack")); + } + + log && log(xtag("stack", &xs_stack)); + + p_psm->top_exprstate().on_expr(expr, p_psm); + + /* now deliver rightparen */ + p_psm->top_exprstate().on_rightparen_token(tk, p_psm); + } + + void + progress_xs::on_then_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + rp expr = this->assemble_expr(p_psm); + + log && log(xtag("assembled-expr", expr)); + + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->on_expr(expr); + p_psm->on_then_token(tk); + + /* control here on input like: + * + * if a > b then.. + * + */ + } + + void + progress_xs::on_else_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + rp expr = this->assemble_expr(p_psm); + + log && log(xtag("assembled-expr", expr)); + + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->on_expr(expr); + p_psm->on_else_token(tk); + + /* control here on input like: + * + * if a > b then c else.. + */ + } + + void + progress_xs::on_rightbrace_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + rp expr = this->assemble_expr(p_psm); + + log && log(xtag("assembled-expr", expr)); + + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->on_expr(expr); + p_psm->on_rightbrace_token(tk); + + /* control here on input like: + * + * { n * n } + */ + } + + namespace { + optype + tk2op(const tokentype & tktype) { + switch (tktype) { + case tokentype::tk_assign: + return optype::op_assign; + case tokentype::tk_plus: + return optype::op_add; + case tokentype::tk_minus: + return optype::op_subtract; + case tokentype::tk_star: + return optype::op_multiply; + case tokentype::tk_slash: + return optype::op_divide; + case tokentype::tk_cmpeq: + return optype::op_equal; + case tokentype::tk_cmpne: + return optype::op_not_equal; + case tokentype::tk_leftangle: + return optype::op_less; + case tokentype::tk_lessequal: + return optype::op_less_equal; + case tokentype::tk_rightangle: + return optype::op_great; + case tokentype::tk_greatequal: + return optype::op_great_equal; + default: + assert(false); + return optype::invalid; + } + return optype::invalid; + } + } + + void + progress_xs::on_operator_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + constexpr const char * c_self_name = "progress_xs::on_operator_token"; + + if (op_type_ == optype::invalid) { + this->op_type_ = tk2op(tk.tk_type()); + + /* infix operator must be followed by non-empty expression */ + expect_expr_xs::start(p_psm); + } else if (rhs_) { + /* already have complete expression stashed. + * behavior depends on operator precedence for tk with stored operator + * this->op_type_ + */ + optype op2 = tk2op(tk.tk_type()); + + if (precedence(op2) <= precedence(this->op_type_)) { + /* e.g. + * 6.2 * 4.9 + ... + * + * in stack: + * 1. progress_xs lhs=6.2, op=*, rhs=4.9 + * + * out stack + * 1. progress_xs lhs=apply(*,6.2,4.9), op=+ + */ + + /* 1. instantiate expression for *this */ + auto expr = this->assemble_expr(p_psm); + + /* 2. remove from stack */ + std::unique_ptr self = p_psm->pop_exprstate(); + + /* 3. replace with new progress_xs: */ + progress_xs::start(expr, op2, p_psm); + + /* infix operator must be followed by non-empty expression */ + expect_expr_xs::start(p_psm); + } else { + /* e.g. + * 6.2 + 4.9 * ... + * + * in stack: + * 1. progress_xs lhs=6.2, op=+, rhs=4.9 + * + * out stack: + * 1. progress_xs lhs=6.2, op=+ + * 2. expect_rhs_expression + * 3. progress_xs lhs=4.9, op=* + * 4. expect_rhs_expression + */ + + std::unique_ptr self = p_psm->pop_exprstate(); + + /* 1. replace with nested incomplete infix exprs */ + progress_xs::start(lhs_, op_type_, p_psm); + expect_expr_xs::start(p_psm); + progress_xs::start(rhs_, op2, p_psm); + expect_expr_xs::start(p_psm); + } + + } else { + throw std::runtime_error(tostr(c_self_name, + ": expected expression following operator", + xtag("tk", tk))); + } + } + + void + progress_xs::on_bool_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + constexpr const char * c_self_name = "progress_xs::on_bool_token"; + const char * exp = get_expect_str(); + + if (this->op_type_ == optype::invalid) { + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } else { + exprstate::on_bool_token(tk, p_psm); + } + } + + void + progress_xs::on_i64_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + constexpr const char * c_self_name = "progress_xs::on_i64_token"; + const char * exp = get_expect_str(); + + if (this->op_type_ == optype::invalid) { + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } else { + exprstate::on_i64_token(tk, p_psm); + } + } + + void + progress_xs::print(std::ostream & os) const { + os << ""; + } + + bool + progress_xs::pretty_print(const xo::print::ppindentinfo & ppii) const + { + if (ppii.upto()) { + return (ppii.pps()->print_upto("print_upto(refrtag("lhs", lhs_)) : true) + && (op_type_ != optype::invalid ? ppii.pps()->print_upto(refrtag("op", op_type_)) : true) + && (rhs_ ? ppii.pps()->print_upto(refrtag("rhs", rhs_)) : true) + && ppii.pps()->print_upto(">")); + } else { + ppii.pps()->write("pretty(refrtag("lhs", lhs_)); + if (op_type_ != optype::invalid) + ppii.pps()->pretty(refrtag("op", op_type_)); + if (rhs_) + ppii.pps()->pretty(refrtag("rhs", rhs_)); + ppii.pps()->write(">"); + return false; + } + } + +#endif + bool + DProgressSsm::pretty(const xo::print::ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct + (ppii, + "DProgressSsm", + refrtag("lhs", lhs_), + refrtag("op", op_type_), + refrtag("rhs", rhs_)); + +#ifdef NOPE + if (ppii.upto()) { + return (ppii.pps()->print_upto("print_upto(refrtag("lhs", lhs_)) : true) + && (op_type_ != optype::invalid ? ppii.pps()->print_upto(refrtag("op", op_type_)) : true) + && (rhs_ ? ppii.pps()->print_upto(refrtag("rhs", rhs_)) : true) + && ppii.pps()->print_upto(">")); + } else { + ppii.pps()->write("pretty(refrtag("lhs", lhs_)); + if (op_type_ != optype::invalid) + ppii.pps()->pretty(refrtag("op", op_type_)); + if (rhs_) + ppii.pps()->pretty(refrtag("rhs", rhs_)); + ppii.pps()->write(">"); + return false; + } +#endif + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DProgressSsm.cpp */ diff --git a/src/reader2/IPrintable_DExpectExprSsm.cpp b/src/reader2/IPrintable_DExpectExprSsm.cpp index 2b656fb2..bfeaccd1 100644 --- a/src/reader2/IPrintable_DExpectExprSsm.cpp +++ b/src/reader2/IPrintable_DExpectExprSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExpectExprSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/src/reader2/IPrintable_DProgressSsm.cpp b/src/reader2/IPrintable_DProgressSsm.cpp new file mode 100644 index 00000000..c72399c9 --- /dev/null +++ b/src/reader2/IPrintable_DProgressSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DProgressSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DProgressSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DProgressSsm.json5] +**/ + +#include "ssm/IPrintable_DProgressSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DProgressSsm::pretty(const DProgressSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DProgressSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index fb9e7a53..0e95dd2d 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -64,6 +64,12 @@ ISyntaxStateMachine_Any::on_singleassign_token(Opaque, const Token &, ParserStat _fatal(); } +auto +ISyntaxStateMachine_Any::on_f64_token(Opaque, const Token &, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index ae2d6601..a758178e 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -53,6 +53,11 @@ namespace xo { self.on_singleassign_token(tk, p_psm); } auto + ISyntaxStateMachine_DDefineSsm::on_f64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_f64_token(tk, p_psm); + } + auto ISyntaxStateMachine_DDefineSsm::on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index de751479..426e4c40 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExpectExprSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -53,6 +53,11 @@ namespace xo { self.on_singleassign_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectExprSsm::on_f64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_f64_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectExprSsm::on_parsed_symbol(DExpectExprSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 5eb40180..586f492f 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -53,6 +53,11 @@ namespace xo { self.on_singleassign_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectSymbolSsm::on_f64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_f64_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index d8621b20..f0360bbf 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -53,6 +53,11 @@ namespace xo { self.on_singleassign_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectTypeSsm::on_f64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_f64_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectTypeSsm::on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index d81e066c..98a3009f 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -53,6 +53,11 @@ namespace xo { self.on_singleassign_token(tk, p_psm); } auto + ISyntaxStateMachine_DExprSeqState::on_f64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_f64_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExprSeqState::on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp new file mode 100644 index 00000000..901dba21 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -0,0 +1,74 @@ +/** @file ISyntaxStateMachine_DProgressSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DProgressSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DProgressSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DProgressSsm::ssm_type(const DProgressSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DProgressSsm::get_expect_str(const DProgressSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DProgressSsm::on_symbol_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_symbol_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DProgressSsm::on_def_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_def_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DProgressSsm::on_if_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_if_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DProgressSsm::on_colon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_colon_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DProgressSsm::on_singleassign_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_singleassign_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DProgressSsm::on_f64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_f64_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DProgressSsm::on_parsed_symbol(DProgressSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DProgressSsm::on_parsed_typedescr(DProgressSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DProgressSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index dbed93d9..33e3a6c2 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -163,11 +163,14 @@ namespace xo { this->on_singleassign_token(tk); break; + case tokentype::tk_f64: + this->on_f64_token(tk); + break; + // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_bool: case tokentype::tk_i64: - case tokentype::tk_f64: case tokentype::tk_string: case tokentype::tk_leftparen: case tokentype::tk_rightparen: @@ -246,6 +249,14 @@ namespace xo { stack_->top().on_singleassign_token(tk, this); } + void + ParserStateMachine::on_f64_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + stack_->top().on_f64_token(tk, this); + } + void ParserStateMachine::capture_error(std::string_view ssm_name, const DString * errmsg) diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index cdade07b..ab0ebe43 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -20,6 +20,9 @@ #include #include +#include +#include + #include #include #include @@ -51,11 +54,15 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + log && log(xtag("DExprSeqState.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); log && log(xtag("DExpectSymbolSsm.tseq", typeseq::id())); log && log(xtag("DExpectTypeSsm.tseq", typeseq::id())); log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); + log && log(xtag("DProgressSsm.tseq", typeseq::id())); return true; } diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index ac09b92e..716c3d7d 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -23,6 +23,8 @@ namespace xo { return "expect-rhs-expression"; case syntaxstatetype::defexpr: return "defexpr"; + case syntaxstatetype::progress: + return "progress"; case syntaxstatetype::N: break; } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index e0f813e4..e70f449b 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -163,7 +163,6 @@ namespace xo { REQUIRE(exp_ssm.data()->cxl_on_rightbrace() == false); } -#ifdef NOT_YET { // future-proofing for Token only holding a string_view const DString * str = DString::from_cstr(expr_alloc, "3.141593"); @@ -172,11 +171,10 @@ namespace xo { REQUIRE(parser.has_incomplete_expr() == true); - log && log("after typename symbol token:"); + log && log("after f64 token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); } -#endif { #ifdef NOT_YET From 523929038843d22064d88824da5b7779576ea0ff Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 22 Jan 2026 15:32:12 -0500 Subject: [PATCH 107/342] xo-reader2: + on_semicolon_token() method in SyntaxStateMachine --- idl/SyntaxStateMachine.json5 | 9 +++++++++ include/xo/reader2/DDefineSsm.hpp | 6 ++++++ include/xo/reader2/DExpectExprSsm.hpp | 6 ++++++ include/xo/reader2/DExpectSymbolSsm.hpp | 6 ++++++ include/xo/reader2/DExpectTypeSsm.hpp | 6 ++++++ include/xo/reader2/DExprSeqState.hpp | 5 +++++ include/xo/reader2/DProgressSsm.hpp | 2 ++ include/xo/reader2/ParserStateMachine.hpp | 3 +++ include/xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 ++ include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExpectExprSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 2 ++ include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 +++ include/xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 +++ src/reader2/DDefineSsm.cpp | 9 +++++++++ src/reader2/DExpectExprSsm.cpp | 9 +++++++++ src/reader2/DExpectSymbolSsm.cpp | 9 +++++++++ src/reader2/DExpectTypeSsm.cpp | 9 +++++++++ src/reader2/DExprSeqState.cpp | 9 +++++++++ src/reader2/DProgressSsm.cpp | 9 +++++++++ src/reader2/ISyntaxStateMachine_Any.cpp | 6 ++++++ src/reader2/ISyntaxStateMachine_DDefineSsm.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp | 5 +++++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DExprSeqState.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DProgressSsm.cpp | 5 +++++ src/reader2/ParserStateMachine.cpp | 13 ++++++++++++- 32 files changed, 166 insertions(+), 1 deletion(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 291108b3..d1229bb5 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -99,6 +99,15 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_semicolon_token", + doc: ["update state machine for incoming semicolon-token @p tk"], + return_type: "void", + args: [ + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_parsed_symbol", doc: ["update stat machine for incoming parsed symbol @p sym"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 5718606d..753571c0 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -153,6 +153,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming semicolon token @p tk, + * overall parser state in @p p_psm + **/ + void on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing a symbol @p sym; * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 36ae3c47..50c1e5a4 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -89,6 +89,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming semicolon token @p tk, + * overall parser state in @p p_psm + **/ + void on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing a symbol @p sym; * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 6584d1e4..8f25661e 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -109,6 +109,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming semicolon token @p tk, + * overall parser state in @p p_psm + **/ + void on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expectsymbol-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 6f88615c..ae2a4512 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -83,6 +83,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming semicolon token @p tk, + * overall parser state in @p p_psm + **/ + void on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm); + /** (Never called). * Operate state machine for this syntax after symbol * emitted from nested ssm. diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 1c62ced6..90ad3891 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -95,6 +95,11 @@ namespace xo { **/ void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming semicolon token @p tk, + * overall parser state in @p p_psm + **/ + void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on parsed symbol @p sym * from immediately-downstream ssm. * overall parser state in @p p_psm diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 0e22726c..25ba8a45 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -141,6 +141,8 @@ namespace xo { ParserStateMachine * p_psm); void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + void on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm); void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm); void on_parsed_typedescr(TypeDescr td, diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 8a019e8c..e43546d3 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -125,6 +125,9 @@ namespace xo { /** operate state machine for incoming f64-token @p tk **/ void on_f64_token(const Token & tk); + /** operate state machine for incoming semicolon-token @p tk **/ + void on_semicolon_token(const Token & tk); + ///@} /** @defgroup scm-parserstatemachine-error-entrypoints error entry points **/ ///@{ diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index 8eba08fe..687722ae 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -69,6 +69,8 @@ public: virtual void on_singleassign_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming f64-token @p tk **/ virtual void on_f64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; + /** update state machine for incoming semicolon-token @p tk **/ + virtual void on_semicolon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update stat machine for incoming parsed symbol @p sym **/ virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 86c180dd..a5d4ed08 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -66,6 +66,7 @@ namespace scm { [[noreturn]] void on_colon_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_singleassign_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_f64_token(Opaque, const Token &, ParserStateMachine *) override; + [[noreturn]] void on_semicolon_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index 06035486..fca6e193 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming semicolon-token @p tk **/ + static void on_semicolon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index ec80e8c8..7d4416f9 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming semicolon-token @p tk **/ + static void on_semicolon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectExprSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index b76b4d61..acf7ceea 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming semicolon-token @p tk **/ + static void on_semicolon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index 16c37fac..a6a3edba 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming semicolon-token @p tk **/ + static void on_semicolon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index 59bf00b4..4e73286c 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming semicolon-token @p tk **/ + static void on_semicolon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 4c4fade2..e830bf99 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming semicolon-token @p tk **/ + static void on_semicolon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DProgressSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index ef37f26d..231fa222 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -70,6 +70,9 @@ namespace scm { void on_f64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_f64_token(_dcast(data), tk, p_psm); } + void on_semicolon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_semicolon_token(_dcast(data), tk, p_psm); + } void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) override { return I::on_parsed_symbol(_dcast(data), sym, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 3c933117..03772439 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -74,6 +74,9 @@ public: void on_f64_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_f64_token(O::data(), tk, p_psm); } + void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_semicolon_token(O::data(), tk, p_psm); + } void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { return O::iface()->on_parsed_symbol(O::data(), sym, p_psm); } diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 5ba71d93..cc380568 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -574,6 +574,15 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DDefineSsm::on_semicolon_token", + tk, + this->get_expect_str()); + } + bool DDefineSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index abb5d076..2420b7c2 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -170,6 +170,15 @@ namespace xo { p_psm); } + void + DExpectExprSsm::on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectExprSsm::on_semicolon_token", + tk, + this->get_expect_str()); + } + void DExpectExprSsm::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 6915ced4..91cc3584 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -140,6 +140,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectSymbolSsm::on_semicolon_token", + tk, + this->get_expect_str()); + } + bool DExpectSymbolSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 44bdbdb0..96fc0ceb 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -101,6 +101,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectTypeSsm::on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectTypeSsm::on_semicolon_token", + tk, + this->get_expect_str()); + } + void DExpectTypeSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 354f06fb..32b9089c 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -187,6 +187,15 @@ namespace xo { this->get_expect_str()); } + void + DExprSeqState::on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExprSeqState::on_semicolon_token", + tk, + this->get_expect_str()); + } + void DExprSeqState::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index a811dda9..cfc6c10c 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -207,6 +207,15 @@ namespace xo { this->get_expect_str()); } + void + DProgressSsm::on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DProgressSsm::on_semicolon_token", + tk, + this->get_expect_str()); + } + void DProgressSsm::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 0e95dd2d..b19b5ea0 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -70,6 +70,12 @@ ISyntaxStateMachine_Any::on_f64_token(Opaque, const Token &, ParserStateMachine _fatal(); } +auto +ISyntaxStateMachine_Any::on_semicolon_token(Opaque, const Token &, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index a758178e..723b910d 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DDefineSsm::on_semicolon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_semicolon_token(tk, p_psm); + } + auto ISyntaxStateMachine_DDefineSsm::on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index 426e4c40..cf8d0969 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectExprSsm::on_semicolon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_semicolon_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectExprSsm::on_parsed_symbol(DExpectExprSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 586f492f..dfc56402 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectSymbolSsm::on_semicolon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_semicolon_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index f0360bbf..6126db55 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectTypeSsm::on_semicolon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_semicolon_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectTypeSsm::on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index 98a3009f..947060a8 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExprSeqState::on_semicolon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_semicolon_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExprSeqState::on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 901dba21..73546dc3 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DProgressSsm::on_semicolon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_semicolon_token(tk, p_psm); + } + auto ISyntaxStateMachine_DProgressSsm::on_parsed_symbol(DProgressSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { self.on_parsed_symbol(sym, p_psm); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 33e3a6c2..596b5e13 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -167,6 +167,10 @@ namespace xo { this->on_f64_token(tk); break; + case tokentype::tk_semicolon: + this->on_semicolon_token(tk); + break; + // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_bool: @@ -185,7 +189,6 @@ namespace xo { case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: - case tokentype::tk_semicolon: case tokentype::tk_assign: case tokentype::tk_yields: case tokentype::tk_plus: @@ -257,6 +260,14 @@ namespace xo { stack_->top().on_f64_token(tk, this); } + void + ParserStateMachine::on_semicolon_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + stack_->top().on_semicolon_token(tk, this); + } + void ParserStateMachine::capture_error(std::string_view ssm_name, const DString * errmsg) From 07d53f73fe7f8f585be6d919acd561eb938926ad Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 22 Jan 2026 15:37:20 -0500 Subject: [PATCH 108/342] xo-reader2: cosmetic: non-executable content --- src/reader2/DProgressSsm.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index cfc6c10c..c13e1799 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -211,6 +211,29 @@ namespace xo { DProgressSsm::on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) { + /* note: implementation should parallel .on_rightparen_token() */ + +#ifdef NOT_YET + obj expr = this->assemble_expr(p_psm); + + p_psm->pop_ssm(); + p_psm->on_expr_with_semicolon(expr); + + /* control here on input like: + * (1.234; + * + * a. '(' sets up stack [lparen_0:expect_rhs_expression] + * (see exprstate::on_leftparen()) + * b. 1.234 pushes (in case operators) [lparen_0:expect_rhs_expression:expr_progress] + * (see exprstate::on_f64()) + * c. semicolon completes expr_progress [lparen_0:expect_rhs_expression] + * deliver expresssion to expect_rhs_expression.on_expr_with_semicolon() + * (see exprstate::on_expr_with_semicolon()) + * d. expr_rhs_expression forwards expression to [lparen_0] + * e. lparen_0 would advance to [lparen_1], but rejects semicolon + */ +#endif + p_psm->illegal_input_on_token("DProgressSsm::on_semicolon_token", tk, this->get_expect_str()); From cfff71c4a9093a8bc27b7d10cfac7bed15b361fd Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 22 Jan 2026 15:49:07 -0500 Subject: [PATCH 109/342] xo-reader2: + SyntaxStateMachine.on_parsed_expression() --- idl/SyntaxStateMachine.json5 | 9 ++++++++ include/xo/reader2/DDefineSsm.hpp | 6 +++++ include/xo/reader2/DExpectExprSsm.hpp | 6 +++++ include/xo/reader2/DExpectSymbolSsm.hpp | 7 ++++++ include/xo/reader2/DExpectTypeSsm.hpp | 7 ++++++ include/xo/reader2/DExprSeqState.hpp | 6 +++++ include/xo/reader2/DProgressSsm.hpp | 2 ++ include/xo/reader2/ParserStateMachine.hpp | 8 +++++++ .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 ++ .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectExprSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 2 ++ .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 +++ .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 +++ src/reader2/DDefineSsm.cpp | 9 ++++++++ src/reader2/DExpectExprSsm.cpp | 9 ++++++++ src/reader2/DExpectSymbolSsm.cpp | 9 ++++++++ src/reader2/DExpectTypeSsm.cpp | 9 ++++++++ src/reader2/DExprSeqState.cpp | 9 ++++++++ src/reader2/DProgressSsm.cpp | 9 ++++++++ src/reader2/ISyntaxStateMachine_Any.cpp | 6 +++++ .../ISyntaxStateMachine_DDefineSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectExprSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExprSeqState.cpp | 5 ++++ .../ISyntaxStateMachine_DProgressSsm.cpp | 5 ++++ src/reader2/ParserStateMachine.cpp | 23 +++++++++++++++++++ 32 files changed, 185 insertions(+) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index d1229bb5..74843096 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -126,5 +126,14 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_parsed_expression", + doc: ["update state machine for incoming parsed expression @p expr"], + return_type: "void", + args: [ + {type: "obj", name: "expr"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, ], } diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 753571c0..3496b5c8 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -171,6 +171,12 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr, + * overall parser state in @p p_psm + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-define-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 50c1e5a4..6ed81bff 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -107,6 +107,12 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr, + * overall parser state in @p p_psm + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-define-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 8f25661e..6f9a568c 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -79,6 +79,13 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr + * in nested state machine. + * (provided to satisfy ASyntaxStateMachine api. not reachable) + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming token @p tk, * overall parser state in @p p_psm. **/ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index ae2a4512..49bd1aa9 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -107,6 +107,13 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for this syntax on receiving expression + * from nested parser. + * (provided to satisfy ASyntaxStateMachine api. not reachable) + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expecttype-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 90ad3891..a3989200 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -112,6 +112,12 @@ namespace xo { **/ void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** update state for this syntax on parsed expression @p expr + * from nested ssm. + * overall parser state in @p p_psm + **/ + void on_parsed_expression(obj expr, ParserStateMachine * p_psm); + ///@} /** @defgroup scm-exprseq-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 25ba8a45..f1e15fba 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -147,6 +147,8 @@ namespace xo { ParserStateMachine * p_psm); void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + void on_parsed_expression(obj, + ParserStateMachine * p_psm); ///@{ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index e43546d3..e5c0ab68 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -164,6 +164,14 @@ namespace xo { TypeDescr td, std::string_view expect_str); + /** report illegal parsed expression from nested ssm. + * Introducing as placeholder; not clear if this will be reachable + * in full parser + **/ + void illegal_parsed_expression(std::string_view ssm_name, + obj, + std::string_view expect_str); + ///@} private: diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index 687722ae..a5cf677f 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -75,6 +75,8 @@ public: virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; /** operate state machine for incoming type description @p td **/ virtual void on_parsed_typedescr(Opaque data, TypeDescr td, ParserStateMachine * p_psm) = 0; + /** update state machine for incoming parsed expression @p expr **/ + virtual void on_parsed_expression(Opaque data, obj expr, ParserStateMachine * p_psm) = 0; ///@} }; /*ASyntaxStateMachine*/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index a5d4ed08..1098b86e 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -69,6 +69,7 @@ namespace scm { [[noreturn]] void on_semicolon_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; + [[noreturn]] void on_parsed_expression(Opaque, obj, ParserStateMachine *) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index fca6e193..a65f47d5 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -72,6 +72,8 @@ namespace xo { static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 7d4416f9..28beddcd 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -72,6 +72,8 @@ namespace xo { static void on_parsed_symbol(DExpectExprSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectExprSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index acf7ceea..a38306ed 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -72,6 +72,8 @@ namespace xo { static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectSymbolSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index a6a3edba..aefe5afa 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -72,6 +72,8 @@ namespace xo { static void on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectTypeSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index 4e73286c..cc0d918d 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -72,6 +72,8 @@ namespace xo { static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExprSeqState & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DExprSeqState & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index e830bf99..c305cf80 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -72,6 +72,8 @@ namespace xo { static void on_parsed_symbol(DProgressSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DProgressSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DProgressSsm & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 231fa222..a0a832b5 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -79,6 +79,9 @@ namespace scm { void on_parsed_typedescr(Opaque data, TypeDescr td, ParserStateMachine * p_psm) override { return I::on_parsed_typedescr(_dcast(data), td, p_psm); } + void on_parsed_expression(Opaque data, obj expr, ParserStateMachine * p_psm) override { + return I::on_parsed_expression(_dcast(data), expr, p_psm); + } ///@} diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 03772439..187a32c7 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -83,6 +83,9 @@ public: void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm) { return O::iface()->on_parsed_typedescr(O::data(), td, p_psm); } + void on_parsed_expression(obj expr, ParserStateMachine * p_psm) { + return O::iface()->on_parsed_expression(O::data(), expr, p_psm); + } ///@} /** @defgroup scm-syntaxstatemachine-member-vars **/ diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index cc380568..3e91a480 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -583,6 +583,15 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DDefineSsm::on_parsed_expression", + expr, + this->get_expect_str()); + } + bool DDefineSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 2420b7c2..3f817763 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -197,6 +197,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectExprSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DExpectExprSsm::on_parsed_expression", + expr, + this->get_expect_str()); + } + bool DExpectExprSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 91cc3584..a1db308c 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -74,6 +74,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DExpectSymbolSsm::on_parsed_expression", + expr, + this->get_expect_str()); + } + void DExpectSymbolSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 96fc0ceb..9a97ef2d 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -163,6 +163,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectTypeSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DExpectTypeSsm::on_parsed_expression", + expr, + this->get_expect_str()); + } + bool DExpectTypeSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 32b9089c..a5b7edd6 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -214,6 +214,15 @@ namespace xo { this->get_expect_str()); } + void + DExprSeqState::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DExprSeqState::on_parsed_expression", + expr, + this->get_expect_str()); + } + bool DExprSeqState::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index c13e1799..d141daf6 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -257,6 +257,15 @@ namespace xo { this->get_expect_str()); } + void + DProgressSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DProgressSsm::on_parsed_expression", + expr, + this->get_expect_str()); + } + #ifdef NOT_YET void progress_xs::apply_type_error(const char * self_name, diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index b19b5ea0..c953b1e1 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -88,6 +88,12 @@ ISyntaxStateMachine_Any::on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachi _fatal(); } +auto +ISyntaxStateMachine_Any::on_parsed_expression(Opaque, obj, ParserStateMachine *) -> void +{ + _fatal(); +} + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index 723b910d..cab18818 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -72,6 +72,11 @@ namespace xo { { self.on_parsed_typedescr(td, p_psm); } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index cf8d0969..feb2d13a 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -72,6 +72,11 @@ namespace xo { { self.on_parsed_typedescr(td, p_psm); } + auto + ISyntaxStateMachine_DExpectExprSsm::on_parsed_expression(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index dfc56402..714ef041 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -72,6 +72,11 @@ namespace xo { { self.on_parsed_typedescr(td, p_psm); } + auto + ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_expression(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 6126db55..2dd5a9ca 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -72,6 +72,11 @@ namespace xo { { self.on_parsed_typedescr(td, p_psm); } + auto + ISyntaxStateMachine_DExpectTypeSsm::on_parsed_expression(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index 947060a8..6d42b86b 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -72,6 +72,11 @@ namespace xo { { self.on_parsed_typedescr(td, p_psm); } + auto + ISyntaxStateMachine_DExprSeqState::on_parsed_expression(DExprSeqState & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 73546dc3..62dd2ce0 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -72,6 +72,11 @@ namespace xo { { self.on_parsed_typedescr(td, p_psm); } + auto + ISyntaxStateMachine_DProgressSsm::on_parsed_expression(DProgressSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 596b5e13..262db2df 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -343,6 +343,29 @@ namespace xo { this->capture_error(ssm_name, errmsg); } + + void + ParserStateMachine::illegal_parsed_expression(std::string_view ssm_name, + obj expr, + std::string_view expect_str) + { + // TODO: + // - want to write error message using DArena + // - need something like log_streambuf and/or tostr() that's arena-aware + + auto errmsg_string = tostr("Unexpected expression", + xtag("expr", expr), + xtag("expecting", expect_str), + xtag("ssm", ssm_name), + xtag("via", "ParserStateMachine::illegal_parsed_expression")); + + assert(expr_alloc_); + + auto errmsg = DString::from_view(expr_alloc_, + std::string_view(errmsg_string)); + + this->capture_error(ssm_name, errmsg); + } } /*namespace scm*/ } /*namespace xo*/ From c33cfd7ae7b20610afb84d0ef9d459b79925c980 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 22 Jan 2026 17:15:05 -0500 Subject: [PATCH 110/342] xo-reader2: + on_parsed_expression_with_semicolon + DefineSsm works --- idl/SyntaxStateMachine.json5 | 9 + include/xo/reader2/DDefineSsm.hpp | 7 + include/xo/reader2/DExpectExprSsm.hpp | 7 + include/xo/reader2/DExpectSymbolSsm.hpp | 7 + include/xo/reader2/DExpectTypeSsm.hpp | 7 + include/xo/reader2/DExprSeqState.hpp | 6 + include/xo/reader2/DProgressSsm.hpp | 21 +- include/xo/reader2/ParserStateMachine.hpp | 16 ++ .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 + .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 + .../ISyntaxStateMachine_DExpectExprSsm.hpp | 2 + .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 + .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 + .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 + .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 2 + .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 + .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 + src/reader2/DDefineSsm.cpp | 22 ++ src/reader2/DExpectExprSsm.cpp | 11 + src/reader2/DExpectSymbolSsm.cpp | 9 + src/reader2/DExpectTypeSsm.cpp | 9 + src/reader2/DExprSeqState.cpp | 9 + src/reader2/DProgressSsm.cpp | 205 +++++++++++++++++- src/reader2/ISyntaxStateMachine_Any.cpp | 6 + .../ISyntaxStateMachine_DDefineSsm.cpp | 5 + .../ISyntaxStateMachine_DExpectExprSsm.cpp | 5 + .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 + .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 + .../ISyntaxStateMachine_DExprSeqState.cpp | 5 + .../ISyntaxStateMachine_DProgressSsm.cpp | 5 + src/reader2/ParserStateMachine.cpp | 20 ++ utest/SchematikaParser.test.cpp | 13 +- 33 files changed, 418 insertions(+), 17 deletions(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 74843096..c12d3736 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -135,5 +135,14 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_parsed_expression_with_semicolon", + doc: ["update state machine for incoming parsed expression @p expr followed by semicolon"], + return_type: "void", + args: [ + {type: "obj", name: "expr"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, ], } diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 3496b5c8..1d94f3ad 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -177,6 +177,13 @@ namespace xo { void on_parsed_expression(obj expr, ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr + * followed by semicolon, + * overall parser state in @p p_psm + **/ + void on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-define-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 6ed81bff..7bf48dea 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -113,6 +113,13 @@ namespace xo { void on_parsed_expression(obj expr, ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr + * followed by semicolon, + * overall parser state in @p p_psm + **/ + void on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-define-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 6f9a568c..1083b454 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -86,6 +86,13 @@ namespace xo { void on_parsed_expression(obj expr, ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr + * followed by semicolon in nested state machine. + * (provided to satisfy ASyntaxStateMachine api. not reachable) + **/ + void on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming token @p tk, * overall parser state in @p p_psm. **/ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 49bd1aa9..cf28fedf 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -114,6 +114,13 @@ namespace xo { void on_parsed_expression(obj expr, ParserStateMachine * p_psm); + /** operate state machine for this syntax on receiving expression + * followed by semicolon from nested parser. + * (provided to satisfy ASyntaxStateMachine api. not reachable) + **/ + void on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expecttype-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index a3989200..eefcb15d 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -118,6 +118,12 @@ namespace xo { **/ void on_parsed_expression(obj expr, ParserStateMachine * p_psm); + /** update state for this syntax on parsed expression @p expr + * followed by semicolon from nested ssm. + * overall parser state in @p p_psm + **/ + void on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm); + ///@} /** @defgroup scm-exprseq-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index f1e15fba..2b4121c3 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -123,12 +123,14 @@ namespace xo { std::string_view get_expect_str() const noexcept; -#ifdef NOT_YET - void on_expr(bp expr, - parserstatemachine * p_psm) override; - void on_expr_with_semicolon(bp expr, - parserstatemachine * p_psm) override; -#endif + /** assemble expression from collected inputs. + * Usually triggered by syntax like ';' or ')' + **/ + obj assemble_expr(ParserStateMachine * p_psm); + + /** @defgroup scm-progressssm-ssm-facet syntaxstatemachine facet methods **/ + /// @{ + void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); void on_def_token(const Token & tk, @@ -149,12 +151,17 @@ namespace xo { ParserStateMachine * p_psm); void on_parsed_expression(obj, ParserStateMachine * p_psm); + void on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm); + ///@} + /** @defgroup scm-progressssm-printable-facet printable facet methods **/ ///@{ - /** @defgroup scm-progressssm-printable-facet printable facet methods **/ bool pretty(const ppindentinfo & ppii) const; + ///@} + #ifdef NOT_YET void on_comma_token(const token_type & tk, parserstatemachine * p_psm) final override; diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index e5c0ab68..42c8af64 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -102,6 +102,22 @@ namespace xo { **/ void on_parsed_typedescr(TypeDescr td); + /** update state to respond to parsed expression @p expr + * (from nested parsing state) + **/ + void on_parsed_expression(obj expr); + + /** update state to respond to parsed expression @p expr + * (from nested parsing state), with trailing semicolon. + * + * Need to distinguish cases like: + * 6 // ; allowed + * f(6 // ) allowed ; forbidden + * 6 + // ) forbidden ; forbidden + * + **/ + void on_parsed_expression_with_semicolon(obj expr); + /** update state to respond to input token @p tk. * record output (if any) in @ref result_ **/ diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index a5cf677f..b68a1289 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -77,6 +77,8 @@ public: virtual void on_parsed_typedescr(Opaque data, TypeDescr td, ParserStateMachine * p_psm) = 0; /** update state machine for incoming parsed expression @p expr **/ virtual void on_parsed_expression(Opaque data, obj expr, ParserStateMachine * p_psm) = 0; + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + virtual void on_parsed_expression_with_semicolon(Opaque data, obj expr, ParserStateMachine * p_psm) = 0; ///@} }; /*ASyntaxStateMachine*/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 1098b86e..52dc4059 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -70,6 +70,7 @@ namespace scm { [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression(Opaque, obj, ParserStateMachine *) override; + [[noreturn]] void on_parsed_expression_with_semicolon(Opaque, obj, ParserStateMachine *) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index a65f47d5..3084631c 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -74,6 +74,8 @@ namespace xo { static void on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + static void on_parsed_expression_with_semicolon(DDefineSsm & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 28beddcd..efebe9c7 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -74,6 +74,8 @@ namespace xo { static void on_parsed_typedescr(DExpectExprSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + static void on_parsed_expression_with_semicolon(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index a38306ed..d870667a 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -74,6 +74,8 @@ namespace xo { static void on_parsed_typedescr(DExpectSymbolSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + static void on_parsed_expression_with_semicolon(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index aefe5afa..23eb8af0 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -74,6 +74,8 @@ namespace xo { static void on_parsed_typedescr(DExpectTypeSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + static void on_parsed_expression_with_semicolon(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index cc0d918d..020e7552 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -74,6 +74,8 @@ namespace xo { static void on_parsed_typedescr(DExprSeqState & self, TypeDescr td, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExprSeqState & self, obj expr, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + static void on_parsed_expression_with_semicolon(DExprSeqState & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index c305cf80..1735b2b1 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -74,6 +74,8 @@ namespace xo { static void on_parsed_typedescr(DProgressSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DProgressSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + static void on_parsed_expression_with_semicolon(DProgressSsm & self, obj expr, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index a0a832b5..da16f766 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -82,6 +82,9 @@ namespace scm { void on_parsed_expression(Opaque data, obj expr, ParserStateMachine * p_psm) override { return I::on_parsed_expression(_dcast(data), expr, p_psm); } + void on_parsed_expression_with_semicolon(Opaque data, obj expr, ParserStateMachine * p_psm) override { + return I::on_parsed_expression_with_semicolon(_dcast(data), expr, p_psm); + } ///@} diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 187a32c7..cfa354b9 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -86,6 +86,9 @@ public: void on_parsed_expression(obj expr, ParserStateMachine * p_psm) { return O::iface()->on_parsed_expression(O::data(), expr, p_psm); } + void on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm) { + return O::iface()->on_parsed_expression_with_semicolon(O::data(), expr, p_psm); + } ///@} /** @defgroup scm-syntaxstatemachine-member-vars **/ diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 3e91a480..6de3bd93 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -578,6 +578,12 @@ namespace xo { DDefineSsm::on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) { + if (defstate_ == defexprstatetype::def_6) { + p_psm->pop_ssm(); + p_psm->on_parsed_expression_with_semicolon(def_expr_); + return; + } + p_psm->illegal_input_on_token("DDefineSsm::on_semicolon_token", tk, this->get_expect_str()); @@ -587,11 +593,27 @@ namespace xo { DDefineSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) { + if (defstate_ == defexprstatetype::def_5) + { + this->defstate_ = defexprstatetype::def_6; + + def_expr_.data()->assign_rhs(expr); + return; + } + p_psm->illegal_parsed_expression("DDefineSsm::on_parsed_expression", expr, this->get_expect_str()); } + void + DDefineSsm::on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm) + { + this->on_parsed_expression(expr, p_psm); + this->on_semicolon_token(Token::semicolon_token(), p_psm); + } + bool DDefineSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 3f817763..cea683c4 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -206,6 +206,17 @@ namespace xo { this->get_expect_str()); } + void + DExpectExprSsm::on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm) + { + // expression (reported by nested ProgressSsm) + // completes this DExpectExprSsm's assignment + + p_psm->pop_ssm(); + p_psm->on_parsed_expression_with_semicolon(expr); + } + bool DExpectExprSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index a1db308c..e55d35be 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -83,6 +83,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DExpectSymbolSsm::on_parsed_expression_with_semicolon", + expr, + this->get_expect_str()); + } + void DExpectSymbolSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 9a97ef2d..30520811 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -172,6 +172,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectTypeSsm::on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DExpectTypeSsm::on_parsed_expression_with_semicolon", + expr, + this->get_expect_str()); + } + bool DExpectTypeSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index a5b7edd6..e67790d5 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -223,6 +223,15 @@ namespace xo { this->get_expect_str()); } + void + DExprSeqState::on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DExprSeqState::on_parsed_expression_with_semicolon", + expr, + this->get_expect_str()); + } + bool DExprSeqState::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index d141daf6..f202728e 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -213,11 +213,12 @@ namespace xo { { /* note: implementation should parallel .on_rightparen_token() */ -#ifdef NOT_YET + (void)tk; + obj expr = this->assemble_expr(p_psm); p_psm->pop_ssm(); - p_psm->on_expr_with_semicolon(expr); + p_psm->on_parsed_expression_with_semicolon(expr); /* control here on input like: * (1.234; @@ -232,11 +233,12 @@ namespace xo { * d. expr_rhs_expression forwards expression to [lparen_0] * e. lparen_0 would advance to [lparen_1], but rejects semicolon */ -#endif +#ifdef OBSOLETE p_psm->illegal_input_on_token("DProgressSsm::on_semicolon_token", tk, this->get_expect_str()); +#endif } void @@ -266,6 +268,15 @@ namespace xo { this->get_expect_str()); } + void + DProgressSsm::on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DProgressSsm::on_parsed_expression_with_semicolon", + expr, + this->get_expect_str()); + } + #ifdef NOT_YET void progress_xs::apply_type_error(const char * self_name, @@ -967,6 +978,194 @@ namespace xo { } #endif } + + obj + DProgressSsm::assemble_expr(ParserStateMachine * p_psm) + { + /* need to defer building Apply incase expr followed by higher-precedence operator: + * consider input like + * 3.14 + 2.0 * ... + */ + + constexpr const char * c_self_name = "DProgressSsm::assemble_expr"; + + if ((op_type_ != optype::invalid) && rhs_) { + std::string errmsg_string = tostr("expected expression on rhs of operator op", + xtag("lhs", lhs_), + xtag("op", op_type_)); + + auto errmsg = DString::from_view(p_psm->expr_alloc(), + std::string_view(errmsg_string)); + + p_psm->capture_error(c_self_name, errmsg); + } + + /* consecutive expressions not legal, e.g: + * 3.14 6.28 + * but expressions surrounding an infix operators is: + * 3.14 / 6.28 + */ + switch (op_type_) { + case optype::invalid: + return this->lhs_; + + case optype::op_assign: + case optype::op_equal: + case optype::op_not_equal: + case optype::op_less: + case optype::op_less_equal: + case optype::op_great: + case optype::op_great_equal: + case optype::op_add: + case optype::op_subtract: + case optype::op_multiply: + case optype::op_divide: + // TODO: implement binary operator expression assembly + break; + +#ifdef NOT_YET +case optype::op_assign: + { + bp lhs = Variable::from(this->lhs_); + + if (!lhs) { + throw std::runtime_error + (tostr("progress_xs::assemble_expr", + " expect variable on lhs of assignment operator :=", + xtag("lhs", lhs_), + xtag("rhs", rhs_))); + } + + return AssignExpr::make(lhs.promote(), + this->rhs_); + } + +case optype::op_equal: + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_eq_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + +case optype::op_not_equal: + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_ne_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + +case optype::op_less: + // TODO: floating-point less-than + + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_lt_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + +case optype::op_less_equal: + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_le_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + +case optype::op_great: + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_gt_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + +case optype::op_great_equal: + // TODO: upconvert integer->double + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_cmp_ge_i64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + + assert(false); + +case optype::op_add: + // TODO: upconvert integer->double + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_add2_i64(lhs_, rhs_); + } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { + return Apply::make_add2_f64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; +case optype::op_subtract: + // TODO: upconvert integer->double + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_sub2_i64(lhs_, rhs_); + } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { + return Apply::make_sub2_f64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; + +case optype::op_multiply: + // TODO: upconvert integer->double + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_mul2_i64(lhs_, rhs_); + } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { + return Apply::make_mul2_f64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + + break; + +case optype::op_divide: + // TODO: upconvert integer->double + if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { + return Apply::make_div2_i64(lhs_, rhs_); + } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { + return Apply::make_div2_f64(lhs_, rhs_); + } else { + this->apply_type_error(c_self_name, + op_type_, lhs_, rhs_, p_psm); + return nullptr; + } + break; +#endif + + case optype::n_optype: + /* unreachable */ + assert(false); + break; + } + + return obj(); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index c953b1e1..a789bce9 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -94,6 +94,12 @@ ISyntaxStateMachine_Any::on_parsed_expression(Opaque, obj, ParserSt _fatal(); } +auto +ISyntaxStateMachine_Any::on_parsed_expression_with_semicolon(Opaque, obj, ParserStateMachine *) -> void +{ + _fatal(); +} + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index cab18818..89589841 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_parsed_expression(expr, p_psm); } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_expression_with_semicolon(DDefineSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_semicolon(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index feb2d13a..858ce1ab 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_parsed_expression(expr, p_psm); } + auto + ISyntaxStateMachine_DExpectExprSsm::on_parsed_expression_with_semicolon(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_semicolon(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 714ef041..1982212c 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_parsed_expression(expr, p_psm); } + auto + ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_expression_with_semicolon(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_semicolon(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 2dd5a9ca..eb66f8db 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_parsed_expression(expr, p_psm); } + auto + ISyntaxStateMachine_DExpectTypeSsm::on_parsed_expression_with_semicolon(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_semicolon(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index 6d42b86b..cfd419b9 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_parsed_expression(expr, p_psm); } + auto + ISyntaxStateMachine_DExprSeqState::on_parsed_expression_with_semicolon(DExprSeqState & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_semicolon(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 62dd2ce0..53c8706c 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_parsed_expression(expr, p_psm); } + auto + ISyntaxStateMachine_DProgressSsm::on_parsed_expression_with_semicolon(DProgressSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_semicolon(expr, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 262db2df..66e4703e 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -129,6 +129,26 @@ namespace xo { this->stack_->top().on_parsed_typedescr(td, this); } + void + ParserStateMachine::on_parsed_expression(obj expr) + { + scope log(XO_DEBUG(debug_flag_), xtag("expr", expr)); + + assert(stack_); + + this->top_ssm().on_parsed_expression(expr, this); + } + + void + ParserStateMachine::on_parsed_expression_with_semicolon(obj expr) + { + scope log(XO_DEBUG(debug_flag_), xtag("expr", expr)); + + assert(stack_); + + this->top_ssm().on_parsed_expression_with_semicolon(expr, this); + } + void ParserStateMachine::on_token(const Token & tk) { diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index e70f449b..a8544687 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -177,14 +177,13 @@ namespace xo { } { -#ifdef NOT_YET - auto def_ssm - = obj::from(parser.top_ssm()); + auto & result = parser.on_token(Token::semicolon_token()); - REQUIRE(def_ssm); - REQUIRE(def_ssm.data()->ssm_type() == syntaxstatetype::defexpr); - REQUIRE(def_ssm.data()->defstate() == defexprstatetype::def_5); -#endif + log && log("after semicolon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == false); } // define-expressions not properly implemented From 81dcd2eb714fb910f6438d82f91366014895dd02 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 22 Jan 2026 17:15:05 -0500 Subject: [PATCH 111/342] xo-reader2: + on_parsed_expression_with_semicolon + DefineSsm works --- include/xo/tokenizer2/Token.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index d47b311d..cc6e13d9 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -112,7 +112,7 @@ namespace xo { /** token representing double-colo @c "::" **/ static Token doublecolon() { return Token(tokentype::tk_doublecolon); } /** token representing semicolon @c ";" **/ - static Token semicolon() { return Token(tokentype::tk_semicolon); } + static Token semicolon_token() { return Token(tokentype::tk_semicolon); } /** token representing single-assignment @c "=" (editor bait: equal_token) **/ static Token singleassign_token() { return Token(tokentype::tk_singleassign); } /** token representing unrestricted assignment @c ":=" **/ From 15e1e506595920c3f7ce74cb92fdbdff040e5f5c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 22 Jan 2026 17:41:40 -0500 Subject: [PATCH 112/342] xo-reader2: accept parsed expression at top level.. --- include/xo/reader2/ParserResult.hpp | 6 ++++++ include/xo/reader2/ParserStateMachine.hpp | 4 ++++ src/reader2/DExprSeqState.cpp | 12 +++++------- src/reader2/ParserResult.cpp | 10 ++++++++++ src/reader2/ParserStateMachine.cpp | 9 ++++++++- 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/include/xo/reader2/ParserResult.hpp b/include/xo/reader2/ParserResult.hpp index 45064d32..6592c7da 100644 --- a/include/xo/reader2/ParserResult.hpp +++ b/include/xo/reader2/ParserResult.hpp @@ -41,6 +41,12 @@ namespace xo { std::string_view error_src_fn, const DString * error_description); + /** create ParserResult for parsing success; + * parsing yields expression @p expr + **/ + static ParserResult expression(std::string_view ssm, + obj expr); + /** create ParserResult for a parsing error. * Reporting detailed message @p errmsg * from syntax state machine @p ssm diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 42c8af64..b838efe5 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -148,6 +148,10 @@ namespace xo { /** @defgroup scm-parserstatemachine-error-entrypoints error entry points **/ ///@{ + /** capture result expression @p expr **/ + void capture_result(std::string_view ssm_anme, + obj expr); + /** capture error message @p errmsg from @p ssm_name, * as current state machine output. * diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index e67790d5..33a68c15 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -218,18 +218,16 @@ namespace xo { DExprSeqState::on_parsed_expression(obj expr, ParserStateMachine * p_psm) { - p_psm->illegal_parsed_expression("DExprSeqState::on_parsed_expression", - expr, - this->get_expect_str()); + // toplevel expr sequence accepts an arbitrary number of expressions. + + p_psm->capture_result("DExprSeqState::on_parsed_expression", expr); } void DExprSeqState::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) + ParserStateMachine * p_psm) { - p_psm->illegal_parsed_expression("DExprSeqState::on_parsed_expression_with_semicolon", - expr, - this->get_expect_str()); + p_psm->capture_result("DExprSeqState::on_parsed_expression_with_semicolon", expr); } bool diff --git a/src/reader2/ParserResult.cpp b/src/reader2/ParserResult.cpp index 312538b1..974724d9 100644 --- a/src/reader2/ParserResult.cpp +++ b/src/reader2/ParserResult.cpp @@ -36,6 +36,16 @@ namespace xo { error_description_{error_description} {} + ParserResult + ParserResult::expression(std::string_view ssm_name, + obj expr) + { + return ParserResult(parser_result_type::expression, + expr, + ssm_name, + nullptr); + } + ParserResult ParserResult::error(std::string_view ssm_name, const DString * errmsg) diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 66e4703e..80841fd8 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -288,6 +288,13 @@ namespace xo { stack_->top().on_semicolon_token(tk, this); } + void + ParserStateMachine::capture_result(std::string_view ssm_name, + obj expr) + { + this->result_ = ParserResult::expression(ssm_name, expr); + } + void ParserStateMachine::capture_error(std::string_view ssm_name, const DString * errmsg) @@ -321,7 +328,7 @@ namespace xo { void ParserStateMachine::illegal_input_on_symbol(std::string_view ssm_name, std::string_view sym, - std::string_view expect_str) + std::string_view expect_str) { // TODO: // - want to write error message using DArena From f6224eefea0322dec902840ffddd8dafcd186d11 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 22 Jan 2026 18:40:42 -0500 Subject: [PATCH 113/342] xo-reader2 xo-expression2: define example working and printing def foo : f64 = 3.141593; --- src/reader2/DDefineSsm.cpp | 4 +++- src/reader2/DProgressSsm.cpp | 31 +++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 6de3bd93..21ff70f0 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -11,6 +11,7 @@ #include "ssm/IPrintable_DDefineSsm.hpp" #include #include +#include #ifdef NOT_YET #include "parserstatemachine.hpp" @@ -22,6 +23,7 @@ namespace xo { using xo::print::APrintable; + using xo::facet::FacetRegistry; using xo::facet::with_facet; using xo::facet::typeseq; @@ -617,7 +619,7 @@ namespace xo { bool DDefineSsm::pretty(const ppindentinfo & ppii) const { - auto expr = with_facet::mkobj(def_expr_.data()); + auto expr = FacetRegistry::instance().variant(def_expr_); return ppii.pps()->pretty_struct (ppii, diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index f202728e..ec19e994 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -5,7 +5,10 @@ #include "DProgressSsm.hpp" #include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" +#include +#include #include +#include #ifdef NOT_YET #include "apply_xs.hpp" @@ -25,6 +28,8 @@ namespace xo { using xo::scm::Variable; using xo::scm::Apply; #endif + using xo::print::APrintable; + using xo::facet::FacetRegistry; using xo::facet::with_facet; using xo::reflect::typeseq; @@ -211,12 +216,23 @@ namespace xo { DProgressSsm::on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + /* note: implementation should parallel .on_rightparen_token() */ (void)tk; obj expr = this->assemble_expr(p_psm); + { + obj expr_pr = FacetRegistry::instance().variant(expr); + + assert(expr_pr); + + log && log(xtag("expr", expr_pr)); + } + p_psm->pop_ssm(); p_psm->on_parsed_expression_with_semicolon(expr); @@ -951,12 +967,23 @@ namespace xo { bool DProgressSsm::pretty(const xo::print::ppindentinfo & ppii) const { + scope log(XO_DEBUG(true)); + log && log(xtag("lhs_.tseq", lhs_._typeseq())); + log && log(xtag("rhs_.tseq", rhs_._typeseq())); + + obj lhs + = FacetRegistry::instance().variant(lhs_); + + obj rhs; + if (rhs_) + rhs = FacetRegistry::instance().variant(rhs_); + return ppii.pps()->pretty_struct (ppii, "DProgressSsm", - refrtag("lhs", lhs_), + refrtag("lhs", lhs), refrtag("op", op_type_), - refrtag("rhs", rhs_)); + cond(rhs, refrtag("rhs", rhs), "nullptr")); #ifdef NOPE if (ppii.upto()) { From 8c038ed66985996efd876345d4e4bfc2af30b4c4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 22 Jan 2026 21:03:40 -0500 Subject: [PATCH 114/342] xo-reader2: working on example parser repl --- example/readerreplxx/readerreplxx.cpp | 146 ++++++++++++++++++++++++ include/xo/reader2/ParserResult.hpp | 2 +- include/xo/reader2/ReaderConfig.hpp | 54 +++++++++ include/xo/reader2/SchematikaParser.hpp | 2 +- include/xo/reader2/SchematikaReader.hpp | 70 ++++++++++++ src/reader2/CMakeLists.txt | 3 + src/reader2/ReaderConfig.cpp | 13 +++ src/reader2/SchematikaReader.cpp | 105 +++++++++++++++++ 8 files changed, 393 insertions(+), 2 deletions(-) create mode 100644 example/readerreplxx/readerreplxx.cpp create mode 100644 include/xo/reader2/ReaderConfig.hpp create mode 100644 include/xo/reader2/SchematikaReader.hpp create mode 100644 src/reader2/ReaderConfig.cpp create mode 100644 src/reader2/SchematikaReader.cpp diff --git a/example/readerreplxx/readerreplxx.cpp b/example/readerreplxx/readerreplxx.cpp new file mode 100644 index 00000000..e30ab047 --- /dev/null +++ b/example/readerreplxx/readerreplxx.cpp @@ -0,0 +1,146 @@ +/** @file readerreplxx.cpp **/ + +#include "xo/reader/reader.hpp" +#include +#include +#include // for isatty + +// presumeably replxx assumes input is a tty +// +bool replxx_getline(bool interactive, + std::size_t parser_stack_size, + replxx::Replxx & rx, + const char ** p_input) +{ + using namespace std; + + char const * prompt = ""; + + if (interactive) { + if (parser_stack_size <= 1) + prompt = "> "; + else + prompt = ". "; + } + + const char * input_cstr = rx.input(prompt); + + bool retval = (input_cstr != nullptr); + + if (retval) { + //cerr << "got reval->true" << endl; + + input = input_cstr; + + } else { + //cerr << "got retval->false" << endl; + } + + rx.history_add(input); + + return retval; +} + +void +welcome(std::ostream& os) +{ + using namespace std; + + os << "read-eval-print loop for schematika expressions" << endl; + os << " ctrl-a/ctrl-e beginning/end of line" << endl; + os << " ctrl-u delete entire line" << endl; + os << " ctrl-k delete to end of line" << endl; + os << " meta- backward delete word" << endl; + os << " |meta-p previous command from history" << endl; + os << " |meta-n next command from history" << endl; + os << " / page through history faster" << endl; + os << " ctrl-s/ctrl-r forward/backward history search" << endl; + os << endl; +} + +int +main() +{ + using namespace replxx; + using namespace xo::scm; + using xo::scm::Expression; + using xo::print::ppconfig; + using xo::print::ppstate_standalone; + using xo::rp; + using namespace std; + + using span_type = xo::scm::span; + + bool interactive = isatty(STDIN_FILENO); + + Replxx rx; + rx.set_max_history_size(1000); + rx.history_load("repl_history.txt"); +// rx.bind_key_internal(Replxx::KEY::control('p'), "history_previous"); +// rx.bind_key_internal(Replxx::KEY::control('n'), "history_next"); + + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag)); + + DArena expr_arena = DArena::map(ArenaConfig{ .name_ = "expr-arena", .size_ = 2*1024*1024; }); + obj expr_alloc = with_facet::mkobj(&expr_arena); + constexpr size_t c_max_stringtable_cap = 1024*1024; + SchematikaParser parser(expr_arena.config_, c_max_stringtable_cap, expr_alloc, c_debug_flag); + + parser.begin_interactive_session(); + + string input_str; + + bool eof = false; + + span_type input; + std::size_t parser_stack_size = 0; + + welcome(cerr); + + while (replxx_getline(interactive, parser_stack_size, rx, input_str)) { + input = span_type::from_string(input_str); + + while (!input.empty()) { + auto [expr, consumed, psz, error] = rdr.read_expr(input, eof); + + if (expr) { + ppconfig ppc; + ppstate_standalone pps(&cout, 0, &ppc); + + pps.prettyn(expr); + } else if (error.is_error()) { + cout << "parsing error (detected in " << error.src_function() << "): " << endl; + error.report(cout); + + /* discard stashed remainder of input line + * (for nicely-formatted errors) + */ + rdr.reset_to_idle_toplevel(); + break; + } + + input = input.after_prefix(consumed); + parser_stack_size = psz; + } + + /* here: input.empty() or error encountered */ + + } + + auto [expr, _1, _2, error] = rdr.read_expr(input, true /*eof*/); + + if (expr) { + ppconfig ppc; + ppstate_standalone pps(&cout, 0, &ppc); + + pps.prettyn>(rp(expr)); + } else if (error.is_error()) { + cout << "parsing error (detected in " << error.src_function() << "): " << endl; + error.report(cout); + } + + rx.history_save("repl_history.txt"); +} + +/* end readerreplxx.cpp */ diff --git a/include/xo/reader2/ParserResult.hpp b/include/xo/reader2/ParserResult.hpp index 6592c7da..492b78b0 100644 --- a/include/xo/reader2/ParserResult.hpp +++ b/include/xo/reader2/ParserResult.hpp @@ -67,7 +67,7 @@ namespace xo { /** pretty-printing support **/ bool pretty(const ppindentinfo & ppii) const; - private: + public: /** none|expression|error_description * * @text diff --git a/include/xo/reader2/ReaderConfig.hpp b/include/xo/reader2/ReaderConfig.hpp new file mode 100644 index 00000000..e7f0d7a6 --- /dev/null +++ b/include/xo/reader2/ReaderConfig.hpp @@ -0,0 +1,54 @@ +/** @file ReaderConfig.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include +#include + +namespace xo { + namespace scm { + + /** @brief Configuration for SchemtikaReader + **/ + struct ReaderConfig { + using CircularBufferConfig = xo::mm::CircularBufferConfig; + using ArenaConfig = xo::mm::ArenaConfig; + using size_t = std::size_t; + + /** tokenizer circular buffer config **/ + CircularBufferConfig tk_buffer_config_ {.name_ = "tk-buffer", + .max_capacity_ = 2*1024*1024, + .hugepage_z_ = 2*1024*1024, + .threshold_move_efficiency_ = 50.0, + .max_captured_span_ = 128 }; + /** debug flag for schematika tokenizer **/ + bool tk_debug_flag_ = false; + /** arena configuration for parser stack **/ + ArenaConfig parser_arena_config_ { .name_ = "parer-arena", + .size_ = 2*1024*1024, + .hugepage_z_ = 2*1024*1024, + .store_header_flag_ = false, + .header_{}, + .debug_flag_ = false }; + /** max size (in bytes) of stringtable **/ + size_t max_stringtable_cap_ = 64*1024; + /** debug flag for schematika parser **/ + bool parser_debug_flag_ = false; +#ifdef NOT_YET + /** arena configuration for output expressions **/ + ArenaConfig expr_arena_config_ { .name_ = "expr-arena", + .size_ = 2*1024*1024, + .hugepage_z_ = 2*1024*1024, + .store_header_flag_ = false, + .header_{}, + .debug_flag_ = false }; +#endif + }; + + } /*namespace scm*/ +} /*namepspace xo*/ + +/* end ReaderConfig.hpp */ diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index aecc3c9a..e2667b5f 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -162,7 +162,7 @@ namespace xo { /** create parser in initial state; * parser is ready to receive tokens via @ref include_token * - * @p config arena configuration for parser memory + * @p config arena configuration for parser stack * @p expr_alloc allocator for schematika expressions. * Probably shared with execution. * @p debug_flag true to enable debug logging diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp new file mode 100644 index 00000000..c60612a2 --- /dev/null +++ b/include/xo/reader2/SchematikaReader.hpp @@ -0,0 +1,70 @@ +/** @file SchematikaReader.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "ReaderConfig.hpp" +#include "SchematikaParser.hpp" +#include + +namespace xo { + namespace scm { + struct ReaderResult { + using span_type = xo::mm::span; + + bool is_tk_error() const { return tk_error_.is_error(); } + + /** schematika expression parsed from input **/ + obj expr_; + /** input span up to end of expression. + * only relevant when result type is expression. + * (otherwise treat entire input as consumed) + **/ + span_type consumed_; + + /** {src_function, error_description, input_state, error_pos} **/ + TokenizerError tk_error_; + }; + + /** @class SchematikaReader + * @brief Pipeline comprising Schematika tokenizer and parser + * + * Consumes text; produces expressions + **/ + class SchematikaReader { + public: + using AAllocator = xo::mm::AAllocator; + + public: + SchematikaReader(const ReaderConfig & config, + obj expr_alloc); + + /** prepare interactive session + * (allows rvalue expressions at toplevel) + **/ + void begin_interactive_session(); + + /** consume input @p input_cstr **/ + const ReaderResult & read_expr(const char * input_cstr, bool eof); + + private: + /** tokenizer converts a stream of chars + * to a stream of lexical tokens + **/ + Tokenizer tokenizer_; + + /** parser converts a stream of tokens + * to a stream of expressions + **/ + SchematikaParser parser_; + + /** current output from reader **/ + ReaderResult result_; + + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end SchematikaReader.hpp */ diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 232174ef..97c46c6a 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -4,6 +4,9 @@ set(SELF_LIB xo_reader2) set(SELF_SRCS init_reader2.cpp + SchematikaReader.cpp + ReaderConfig.cpp + SchematikaParser.cpp ParserStateMachine.cpp ParserStack.cpp diff --git a/src/reader2/ReaderConfig.cpp b/src/reader2/ReaderConfig.cpp new file mode 100644 index 00000000..7db5fe59 --- /dev/null +++ b/src/reader2/ReaderConfig.cpp @@ -0,0 +1,13 @@ +/** @file ReaderConfig.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "ReaderConfig.hpp" + +namespace xo { + namespace scm { + } +} /*namespace xo*/ + +/* end ReaderConfig.cpp */ diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp new file mode 100644 index 00000000..f8c6a152 --- /dev/null +++ b/src/reader2/SchematikaReader.cpp @@ -0,0 +1,105 @@ +/** @file SchematikaReader.cpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#include "SchematikaReader.hpp" + +namespace xo { + namespace scm { + SchematikaReader::SchematikaReader(const ReaderConfig & config, + obj expr_alloc) + : tokenizer_{config.tk_buffer_config_, config.tk_debug_flag_}, + parser_{config.parser_arena_config_, + config.max_stringtable_cap_, + expr_alloc, + config.parser_debug_flag_} + { + } + + void + SchematikaReader::begin_interactive_session() + { + parser_.begin_interactive_session(); + } + + // TODO: + // Schematika::end_interactive_session() + + const ReaderResult & + SchematikaReader::read_expr(const char * input_cstr, bool eof) + { + if (input_cstr && *input_cstr) { + auto [error, input] + = tokenizer_.buffer_input_line(input_cstr, + false /*!eof*/); + // log && log(xtag("msg", "buffered input line")); + // log && log(xtag("input", input)); + + + + while (!input.empty()) { + auto [tk, consumed, error] = tkz.scan(input); + + if (!tk.is_valid() && error.is_error()) { + this->result_ = ReaderResult { .expr_ = obj(), + .tk_error_ = std::move(error), + .consumed_ = nullptr }; + return result_; + } + + // log && log(xtag("consumed", consumed), xtag("tk", tk)); + + if (tk.is_valid()) { + // presult { + // result_type :: parser_result_type = none|expression|error + // result_expr :: obj + // error_src_function :: string_view + // error_description :: const DString * + // } + // + const ParserResult & presult = parser_include_token(tk); + + if (presult.is_error()) { + // tk_error { + // src_function :: const char * + // error_description :: string + // input_state { + // current_line :: span + // tk_start :: size_t + // current_pos :: size_t + // whitespace :: size_t + // debug_flag :: bool + // } + // error_pos :: size_t + // } + // + // tk_error.report(cout); + + this->result_ = ReaderResult { .expr = obj(), + .tk_error_ = std::move(error), + .consumed_ = nullptr }; + + // carefully created error description, maybe + this->result.tk_error_.error_description_ = presult.error_description_; + + } + + xxxx; + } else if (error.is_error()) { + xxxx; + // error.report(cout); + break; + } + + input = input.after_prefix(consumed); + } + } + + ++line_no; + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end SchematikaReader.cpp */ From 5d8f4b4b92ceb5a0a94829ad988d393551d84c22 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 22 Jan 2026 21:03:40 -0500 Subject: [PATCH 115/342] xo-reader2: working on example parser repl --- include/xo/tokenizer2/TokenizerError.hpp | 2 +- include/xo/tokenizer2/scan_result.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xo/tokenizer2/TokenizerError.hpp b/include/xo/tokenizer2/TokenizerError.hpp index a1cb99ee..b8a50988 100644 --- a/include/xo/tokenizer2/TokenizerError.hpp +++ b/include/xo/tokenizer2/TokenizerError.hpp @@ -99,7 +99,7 @@ namespace xo { size_t error_pos_ = 0; ///@} - }; /*error_token*/ + }; inline std::ostream & operator<< (std::ostream & os, diff --git a/include/xo/tokenizer2/scan_result.hpp b/include/xo/tokenizer2/scan_result.hpp index 249154f1..45718c5c 100644 --- a/include/xo/tokenizer2/scan_result.hpp +++ b/include/xo/tokenizer2/scan_result.hpp @@ -28,9 +28,9 @@ namespace xo { **/ class scan_result { public: - using CharT = char; + //using CharT = char; using token_type = Token; - using span_type = xo::mm::span; + using span_type = xo::mm::span; using error_type = TokenizerError; using input_state_type = TkInputState; From 8f64b05b711aa37794fb49f9450b24c3b282b5c5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 23 Jan 2026 11:54:32 -0500 Subject: [PATCH 116/342] xo-reader2: + example app 'readerreplxx' --- CMakeLists.txt | 5 + example/CMakeLists.txt | 1 + example/readerreplxx/CMakeLists.txt | 14 +++ example/readerreplxx/readerreplxx.cpp | 159 ++++++++++++++---------- include/xo/reader2/SchematikaParser.hpp | 1 + include/xo/reader2/SchematikaReader.hpp | 22 +++- src/reader2/CMakeLists.txt | 4 +- src/reader2/SchematikaParser.cpp | 1 + src/reader2/SchematikaReader.cpp | 77 ++++++++---- 9 files changed, 187 insertions(+), 97 deletions(-) create mode 100644 example/CMakeLists.txt create mode 100644 example/readerreplxx/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index bc35b6a9..43c747f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,6 +197,11 @@ xo_add_genfacet_all(xo-reader2-genfacet-all) add_subdirectory(src/reader2) +# ---------------------------------------------------------------- +# example programs + +add_subdirectory(example) + # ---------------------------------------------------------------- # cmake helper (for external xo-reader2 users) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 00000000..fbb01ff0 --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(readerreplxx) diff --git a/example/readerreplxx/CMakeLists.txt b/example/readerreplxx/CMakeLists.txt new file mode 100644 index 00000000..37ecd45e --- /dev/null +++ b/example/readerreplxx/CMakeLists.txt @@ -0,0 +1,14 @@ +# xo-reader2/example/readerreplxx/CMakeLists.txt + +set(SELF_EXE xo_reader2_readereplxx) +set(SELF_SRCS readerreplxx.cpp) + +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_dependency(${SELF_EXE} xo_reader2) + xo_external_target_dependency(${SELF_EXE} replxx replxx::replxx) + + # replxx requires this + find_package(Threads REQUIRED) + target_link_libraries(${SELF_EXE} PUBLIC Threads::Threads) +endif() diff --git a/example/readerreplxx/readerreplxx.cpp b/example/readerreplxx/readerreplxx.cpp index e30ab047..76bd0520 100644 --- a/example/readerreplxx/readerreplxx.cpp +++ b/example/readerreplxx/readerreplxx.cpp @@ -1,6 +1,11 @@ /** @file readerreplxx.cpp **/ -#include "xo/reader/reader.hpp" +#include +#include +#include +#include +//#include +#include #include #include #include // for isatty @@ -8,7 +13,7 @@ // presumeably replxx assumes input is a tty // bool replxx_getline(bool interactive, - std::size_t parser_stack_size, + bool is_at_toplevel, replxx::Replxx & rx, const char ** p_input) { @@ -17,32 +22,23 @@ bool replxx_getline(bool interactive, char const * prompt = ""; if (interactive) { - if (parser_stack_size <= 1) - prompt = "> "; - else - prompt = ". "; + prompt = ((is_at_toplevel) ? "> " : ". "); } const char * input_cstr = rx.input(prompt); bool retval = (input_cstr != nullptr); - if (retval) { - //cerr << "got reval->true" << endl; + if (retval) + *p_input = input_cstr; - input = input_cstr; - - } else { - //cerr << "got retval->false" << endl; - } - - rx.history_add(input); + rx.history_add(input_cstr); return retval; } void -welcome(std::ostream& os) +welcome(std::ostream & os) { using namespace std; @@ -58,18 +54,68 @@ welcome(std::ostream& os) os << endl; } +namespace { + using xo::scm::SchematikaReader; + using xo::print::ppstate_standalone; + using xo::print::ppconfig; + using std::cout; + using std::endl; + + /** body of read-parse-print loop + * + * true -> no errors; + * false -> reader encountered error + **/ + bool + reader_seq(SchematikaReader * p_reader, + SchematikaReader::span_type * p_input, + bool eof) + { + auto [expr, remaining, error] = p_reader->read_expr(*p_input, eof); + + if (expr) { + ppconfig ppc; + ppstate_standalone pps(&cout, 0, &ppc); + + pps.prettyn(expr); + + *p_input = remaining; + + return true; + } else if (error.is_error()) { + cout << "parsing error (detected in " << error.src_function() << "): " << endl; + error.report(cout); + + /* discard stashed remainder of input line + * (for nicely-formatted errors) + */ + p_reader->reset_to_idle_toplevel(); + + return false; + } else { + /* partial expression or whitespace input, no error */ + return true; + } + } +} + int main() { using namespace replxx; - using namespace xo::scm; - using xo::scm::Expression; - using xo::print::ppconfig; - using xo::print::ppstate_standalone; - using xo::rp; - using namespace std; - using span_type = xo::scm::span; + using xo::scm::SchematikaReader; + using xo::scm::ReaderConfig; + using xo::mm::AAllocator; + using xo::mm::DX1Collector; + using xo::mm::CollectorConfig; + using xo::mm::DArena; + //using xo::print::ppconfig; + //using xo::print::ppstate_standalone; + using xo::facet::with_facet; + using xo::facet::obj; + using xo::scope; + using namespace std; bool interactive = isatty(STDIN_FILENO); @@ -82,63 +128,40 @@ main() constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag)); - DArena expr_arena = DArena::map(ArenaConfig{ .name_ = "expr-arena", .size_ = 2*1024*1024; }); - obj expr_alloc = with_facet::mkobj(&expr_arena); - constexpr size_t c_max_stringtable_cap = 1024*1024; - SchematikaParser parser(expr_arena.config_, c_max_stringtable_cap, expr_alloc, c_debug_flag); + CollectorConfig x1_config = (CollectorConfig() + .with_size(4*1024*1024)); + DX1Collector x1(x1_config); + obj expr_alloc = with_facet::mkobj(&x1); - parser.begin_interactive_session(); + // accepting defaults too + ReaderConfig rdr_config = ReaderConfig(); - string input_str; - - bool eof = false; - - span_type input; - std::size_t parser_stack_size = 0; + SchematikaReader rdr(rdr_config, expr_alloc); + using span_type = SchematikaReader::span_type; welcome(cerr); - while (replxx_getline(interactive, parser_stack_size, rx, input_str)) { - input = span_type::from_string(input_str); + rdr.begin_interactive_session(); - while (!input.empty()) { - auto [expr, consumed, psz, error] = rdr.read_expr(input, eof); + bool eof = false; + const char * input_str; + span_type input; - if (expr) { - ppconfig ppc; - ppstate_standalone pps(&cout, 0, &ppc); + while (replxx_getline(interactive, rdr.is_at_toplevel(), rx, &input_str)) { + input = span_type::from_cstr(input_str); - pps.prettyn(expr); - } else if (error.is_error()) { - cout << "parsing error (detected in " << error.src_function() << "): " << endl; - error.report(cout); - - /* discard stashed remainder of input line - * (for nicely-formatted errors) - */ - rdr.reset_to_idle_toplevel(); - break; - } - - input = input.after_prefix(consumed); - parser_stack_size = psz; + while (!input.empty() && reader_seq(&rdr, &input, false /*eof*/)) { + ; } - /* here: input.empty() or error encountered */ - + /* here: either: + * 1. input.empty() or + * 2. error encountered + */ } - auto [expr, _1, _2, error] = rdr.read_expr(input, true /*eof*/); - - if (expr) { - ppconfig ppc; - ppstate_standalone pps(&cout, 0, &ppc); - - pps.prettyn>(rp(expr)); - } else if (error.is_error()) { - cout << "parsing error (detected in " << error.src_function() << "): " << endl; - error.report(cout); - } + /* reminder: eof can complete at most one token */ + reader_seq(&rdr, &input, true /*eof*/); rx.history_save("repl_history.txt"); } diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index e2667b5f..7be74aa5 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -157,6 +157,7 @@ namespace xo { using ArenaConfig = xo::mm::ArenaConfig; using AAllocator = xo::mm::AAllocator; using ppindentinfo = xo::print::ppindentinfo; + using size_type = std::size_t; public: /** create parser in initial state; diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index c60612a2..bad6c053 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -18,11 +18,11 @@ namespace xo { /** schematika expression parsed from input **/ obj expr_; - /** input span up to end of expression. + /** unconsumed portion of input span * only relevant when result type is expression. - * (otherwise treat entire input as consumed) + * (otherwise input consumed) **/ - span_type consumed_; + span_type remaining_input_; /** {src_function, error_description, input_state, error_pos} **/ TokenizerError tk_error_; @@ -36,18 +36,32 @@ namespace xo { class SchematikaReader { public: using AAllocator = xo::mm::AAllocator; + using span_type = xo::mm::span; + using size_type = std::size_t; public: SchematikaReader(const ReaderConfig & config, obj expr_alloc); + /** true iff parser is at top-level. + * false iff parser is working on incomplete expression + **/ + bool is_at_toplevel() const noexcept; + /** prepare interactive session * (allows rvalue expressions at toplevel) **/ void begin_interactive_session(); /** consume input @p input_cstr **/ - const ReaderResult & read_expr(const char * input_cstr, bool eof); + const ReaderResult & read_expr(span_type input_span, bool eof); + + /** reset to known starting point after encountering an error. + * - remainder of stashed current line. + * Necesary for well-formatted error reporting. + * - current parsing state + **/ + void reset_to_idle_toplevel(); private: /** tokenizer converts a stream of chars diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 97c46c6a..37dda298 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -3,6 +3,8 @@ set(SELF_LIB xo_reader2) set(SELF_SRCS init_reader2.cpp + reader2_register_facets.cpp + reader2_register_types.cpp SchematikaReader.cpp ReaderConfig.cpp @@ -39,8 +41,6 @@ set(SELF_SRCS ISyntaxStateMachine_DProgressSsm.cpp IPrintable_DProgressSsm.cpp - reader2_register_facets.cpp - reader2_register_types.cpp ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index fea573c7..13f9edff 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -7,6 +7,7 @@ #include "ParserStateMachine.hpp" #include "ParserStack.hpp" #include "DExprSeqState.hpp" +#include #include #include diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index f8c6a152..bfd14575 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -17,6 +17,12 @@ namespace xo { { } + bool + SchematikaReader::is_at_toplevel() const noexcept + { + return parser_.is_at_toplevel(); + } + void SchematikaReader::begin_interactive_session() { @@ -27,24 +33,28 @@ namespace xo { // Schematika::end_interactive_session() const ReaderResult & - SchematikaReader::read_expr(const char * input_cstr, bool eof) + SchematikaReader::read_expr(span_type input_ext, bool eof) { - if (input_cstr && *input_cstr) { + if (!input_ext.empty()) { auto [error, input] - = tokenizer_.buffer_input_line(input_cstr, - false /*!eof*/); + = tokenizer_.buffer_input_line(input_ext, eof); + // log && log(xtag("msg", "buffered input line")); // log && log(xtag("input", input)); - - while (!input.empty()) { - auto [tk, consumed, error] = tkz.scan(input); + auto [tk, consumed, error] = tokenizer_.scan(input); + + auto rem_input = input.after_prefix(consumed); if (!tk.is_valid() && error.is_error()) { - this->result_ = ReaderResult { .expr_ = obj(), - .tk_error_ = std::move(error), - .consumed_ = nullptr }; + this->result_ + = ReaderResult + { .expr_ = obj(), + .remaining_input_ = rem_input, + .tk_error_ = std::move(error) + }; + return result_; } @@ -58,7 +68,7 @@ namespace xo { // error_description :: const DString * // } // - const ParserResult & presult = parser_include_token(tk); + const ParserResult & presult = parser_.on_token(tk); if (presult.is_error()) { // tk_error { @@ -76,29 +86,50 @@ namespace xo { // // tk_error.report(cout); - this->result_ = ReaderResult { .expr = obj(), - .tk_error_ = std::move(error), - .consumed_ = nullptr }; + this->result_ + = ReaderResult + { .expr_ = obj(), + .remaining_input_ = rem_input, + .tk_error_ = std::move(error) }; + + assert(presult.error_description()); // carefully created error description, maybe - this->result.tk_error_.error_description_ = presult.error_description_; + this->result_.tk_error_ + = result_.tk_error_.with_error + (presult.error_src_fn_, + std::string + (std::string_view(*(presult.error_description())))); + return result_; + } else if (presult.is_expression()) { + this->result_ + = ReaderResult + { + .expr_ = presult.result_expr(), + .remaining_input_ = rem_input, + .tk_error_ = TokenizerError() + }; + + return result_; } - - xxxx; - } else if (error.is_error()) { - xxxx; - // error.report(cout); - break; } - input = input.after_prefix(consumed); + input = rem_input; } } - ++line_no; + this->result_ = ReaderResult(); + + return this->result_; } + void + SchematikaReader::reset_to_idle_toplevel() + { + this->tokenizer_.discard_current_line(); + this->parser_.reset_to_idle_toplevel(); + } } /*namespace scm*/ } /*namespace xo*/ From 9044e1d196418a3189d982b8c564556ea38e106c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 23 Jan 2026 11:54:32 -0500 Subject: [PATCH 117/342] xo-reader2: + example app 'readerreplxx' --- example/tokenrepl/tokenrepl.cpp | 45 ++++++++++++------------ include/xo/tokenizer2/Tokenizer.hpp | 5 +-- include/xo/tokenizer2/TokenizerError.hpp | 16 ++++++--- src/tokenizer2/Tokenizer.cpp | 17 +++++---- 4 files changed, 46 insertions(+), 37 deletions(-) diff --git a/example/tokenrepl/tokenrepl.cpp b/example/tokenrepl/tokenrepl.cpp index 1cf02244..d8ddbd7f 100644 --- a/example/tokenrepl/tokenrepl.cpp +++ b/example/tokenrepl/tokenrepl.cpp @@ -85,32 +85,33 @@ main() { { //cout << "input: " << input << endl; + auto input_ext = Tokenizer::span_type::from_cstr(input_cstr); + // reminder: input may contain multiple tokens - if (input_cstr && *input_cstr) { - auto [error, input] = tkz.buffer_input_line(input_cstr, false /*!eof*/); + auto [error, input] = tkz.buffer_input_line(input_ext, false /*!eof*/); - if (log) { - log(xtag("msg", "buffered input line")); - log(xtag("input", input)); + if (log) { + log(xtag("msg", "buffered input line")); + log(xtag("input", input)); + } + + while (!input.empty()) + { + auto [tk, consumed, error] = tkz.scan(input); + + log && log(xtag("consumed", consumed), xtag("tk", tk)); + + if (tk.is_valid()) { + cout << tk << endl; + } else if (error.is_error()) { + cout << "tokenizer error: " << endl; + + error.report(cout); + + break; } - while (!input.empty()) - { - auto [tk, consumed, error] = tkz.scan(input); - - log && log(xtag("consumed", consumed), xtag("tk", tk)); - - if (tk.is_valid()) { - cout << tk << endl; - } else if (error.is_error()) { - cout << "tokenizer error: " << endl; - error.report(cout); - - break; - } - - input = input.after_prefix(consumed); - } + input = input.after_prefix(consumed); } /* here: input.empty() or error encountered */ diff --git a/include/xo/tokenizer2/Tokenizer.hpp b/include/xo/tokenizer2/Tokenizer.hpp index 40a98cd9..69843a5a 100644 --- a/include/xo/tokenizer2/Tokenizer.hpp +++ b/include/xo/tokenizer2/Tokenizer.hpp @@ -129,10 +129,11 @@ namespace xo { **/ bool has_prefix() const { return !prefix_.empty(); } - /** buffer contents of input_cstr. + /** copy into buffer the contents of @p input. * May throw if buffer space exhausted **/ - std::pair buffer_input_line(const char * input_cstr, bool eof_flag); + std::pair buffer_input_line(span_type input, + bool eof_flag); /** scan for next input token, given @p input. * Note: diff --git a/include/xo/tokenizer2/TokenizerError.hpp b/include/xo/tokenizer2/TokenizerError.hpp index b8a50988..bf7702b1 100644 --- a/include/xo/tokenizer2/TokenizerError.hpp +++ b/include/xo/tokenizer2/TokenizerError.hpp @@ -32,7 +32,7 @@ namespace xo { * @p tk_start current position on entry to scanner * @p error_pos error location relative to token start **/ - TokenizerError(const char * src_function, + TokenizerError(std::string_view src_function, std::string error_description, const TkInputState & input_state, size_t error_pos) @@ -46,12 +46,20 @@ namespace xo { log && log(xtag("input_state.current_pos", input_state.current_pos()), xtag("error_pos", error_pos)); } + + TokenizerError with_error(std::string_view error_src_fn, + std::string error_msg) { + return TokenizerError(error_src_fn, + std::string(error_msg), + this->input_state_, + 0 /*error_pos*/); + } ///@} /** @defgroup tokenizer-error-access-methods **/ ///@{ - const char * src_function() const { return src_function_; } + std::string_view src_function() const { return src_function_; } const std::string & error_description() const { return error_description_; } #pragma GCC diagnostic push #ifndef __APPLE__ @@ -88,8 +96,8 @@ namespace xo { ///@{ /** source location (in tokenizer) at which error identified **/ - char const * src_function_ = nullptr; - /** static error description **/ + std::string_view src_function_; + /** error description **/ std::string error_description_; /** input state associated with this error. * Sufficient to precisely locate it with context. diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index 7076a95d..2784072a 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -615,19 +615,18 @@ namespace xo { } auto - Tokenizer::buffer_input_line(const char * input_cstr, + Tokenizer::buffer_input_line(span_type input_ext, bool eof_flag) -> std::pair { scope log(XO_DEBUG(input_state_.debug_flag())); - log && log(xtag("input", input_cstr)); + log && log(xtag("input_ext", input_ext)); auto buf_input_0 = input_buffer_.input_range().hi(); - auto remainder = input_buffer_.append - (DCircularBuffer::const_span_type::from_cstr(input_cstr)); - auto remainder2 = input_buffer_.append - (DCircularBuffer::const_span_type::from_cstr("\n")); + auto remainder = input_buffer_.append(input_ext); + auto remainder2 = input_buffer_.append(span_type::from_cstr("\n")); + //(DCircularBuffer::const_span_type::from_cstr("\n")); if (!remainder.empty() || !remainder2.empty()) { throw std::runtime_error(tostr("Tokenizer::buffer_line: line too long!", @@ -636,10 +635,10 @@ namespace xo { auto buf_input_1 = input_buffer_.input_range().hi(); - span_type input = span_type(buf_input_0, - buf_input_1); + span_type input_ours = span_type(buf_input_0, + buf_input_1); - return this->input_state_.capture_current_line(input, eof_flag); + return this->input_state_.capture_current_line(input_ours, eof_flag); } auto From 68940555487016323e6cbdcb753990a2dcd2146f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 23 Jan 2026 14:57:43 -0500 Subject: [PATCH 118/342] xo-reader2: readerreplxx works + streamline debugging --- example/readerreplxx/readerreplxx.cpp | 80 +++++++++++++++++++------ include/xo/reader2/ReaderConfig.hpp | 20 +++---- include/xo/reader2/SchematikaReader.hpp | 2 + src/reader2/DDefineSsm.cpp | 2 +- src/reader2/DExpectTypeSsm.cpp | 2 +- src/reader2/DProgressSsm.cpp | 3 +- src/reader2/SchematikaReader.cpp | 26 ++++++-- 7 files changed, 98 insertions(+), 37 deletions(-) diff --git a/example/readerreplxx/readerreplxx.cpp b/example/readerreplxx/readerreplxx.cpp index 76bd0520..28598292 100644 --- a/example/readerreplxx/readerreplxx.cpp +++ b/example/readerreplxx/readerreplxx.cpp @@ -1,11 +1,14 @@ /** @file readerreplxx.cpp **/ +#include #include #include #include #include -//#include +#include +#include #include +#include #include #include #include // for isatty @@ -32,7 +35,8 @@ bool replxx_getline(bool interactive, if (retval) *p_input = input_cstr; - rx.history_add(input_cstr); + if (input_cstr) + rx.history_add(input_cstr); return retval; } @@ -56,8 +60,14 @@ welcome(std::ostream & os) namespace { using xo::scm::SchematikaReader; + using xo::scm::AExpression; + using xo::print::APrintable; using xo::print::ppstate_standalone; using xo::print::ppconfig; + using xo::facet::FacetRegistry; + using xo::facet::obj; + using xo::xtag; + using xo::scope; using std::cout; using std::endl; @@ -69,15 +79,36 @@ namespace { bool reader_seq(SchematikaReader * p_reader, SchematikaReader::span_type * p_input, - bool eof) + bool eof, + bool debug_flag) { + scope log(XO_DEBUG(debug_flag)); + + if (!p_input || p_input->empty()) + return true; + auto [expr, remaining, error] = p_reader->read_expr(*p_input, eof); + obj expr_pr; + + if (expr) { + expr_pr = FacetRegistry::instance().variant(expr); + assert(expr_pr); + } + + if (log) { + if (expr_pr) { + log(xtag("expr", expr_pr)); + } + log(xtag("remaining", remaining)); + log(xtag("error", error)); + } + if (expr) { ppconfig ppc; ppstate_standalone pps(&cout, 0, &ppc); - pps.prettyn(expr); + pps.prettyn(expr_pr); *p_input = remaining; @@ -93,6 +124,8 @@ namespace { return false; } else { + *p_input = remaining; + /* partial expression or whitespace input, no error */ return true; } @@ -110,15 +143,19 @@ main() using xo::mm::DX1Collector; using xo::mm::CollectorConfig; using xo::mm::DArena; - //using xo::print::ppconfig; - //using xo::print::ppstate_standalone; using xo::facet::with_facet; using xo::facet::obj; + using xo::S_reader2_tag; + using xo::InitSubsys; + using xo::Subsystem; using xo::scope; using namespace std; bool interactive = isatty(STDIN_FILENO); + InitSubsys::require(); + Subsystem::initialize_all(); + Replxx rx; rx.set_max_history_size(1000); rx.history_load("repl_history.txt"); @@ -134,7 +171,12 @@ main() obj expr_alloc = with_facet::mkobj(&x1); // accepting defaults too - ReaderConfig rdr_config = ReaderConfig(); + ReaderConfig rdr_config; + { + //rdr_config.reader_debug_flag_ = true; + //rdr_config.parser_debug_flag_ = true; + //rdr_config.tk_debug_flag_ = true; + } SchematikaReader rdr(rdr_config, expr_alloc); using span_type = SchematikaReader::span_type; @@ -144,24 +186,28 @@ main() rdr.begin_interactive_session(); bool eof = false; - const char * input_str; + const char * input_str = nullptr; span_type input; while (replxx_getline(interactive, rdr.is_at_toplevel(), rx, &input_str)) { - input = span_type::from_cstr(input_str); + if (input_str && *input_str) { + input = span_type::from_cstr(input_str); - while (!input.empty() && reader_seq(&rdr, &input, false /*eof*/)) { - ; + while (!input.empty() + && reader_seq(&rdr, &input, false /*eof*/, c_debug_flag)) + { + ; + } + + /* here: either: + * 1. input.empty() or + * 2. error encountered + */ } - - /* here: either: - * 1. input.empty() or - * 2. error encountered - */ } /* reminder: eof can complete at most one token */ - reader_seq(&rdr, &input, true /*eof*/); + reader_seq(&rdr, &input, true /*eof*/, c_debug_flag); rx.history_save("repl_history.txt"); } diff --git a/include/xo/reader2/ReaderConfig.hpp b/include/xo/reader2/ReaderConfig.hpp index e7f0d7a6..826bb215 100644 --- a/include/xo/reader2/ReaderConfig.hpp +++ b/include/xo/reader2/ReaderConfig.hpp @@ -11,7 +11,7 @@ namespace xo { namespace scm { - /** @brief Configuration for SchemtikaReader + /** @brief Configuration for SchematikaReader **/ struct ReaderConfig { using CircularBufferConfig = xo::mm::CircularBufferConfig; @@ -26,6 +26,7 @@ namespace xo { .max_captured_span_ = 128 }; /** debug flag for schematika tokenizer **/ bool tk_debug_flag_ = false; + /** arena configuration for parser stack **/ ArenaConfig parser_arena_config_ { .name_ = "parer-arena", .size_ = 2*1024*1024, @@ -33,19 +34,14 @@ namespace xo { .store_header_flag_ = false, .header_{}, .debug_flag_ = false }; - /** max size (in bytes) of stringtable **/ - size_t max_stringtable_cap_ = 64*1024; /** debug flag for schematika parser **/ bool parser_debug_flag_ = false; -#ifdef NOT_YET - /** arena configuration for output expressions **/ - ArenaConfig expr_arena_config_ { .name_ = "expr-arena", - .size_ = 2*1024*1024, - .hugepage_z_ = 2*1024*1024, - .store_header_flag_ = false, - .header_{}, - .debug_flag_ = false }; -#endif + + /** max size (in bytes) of stringtable **/ + size_t max_stringtable_cap_ = 64*1024; + + /** debug flag for schematika_reader **/ + bool reader_debug_flag_ = false;; }; } /*namespace scm*/ diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index bad6c053..540c19bc 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -77,6 +77,8 @@ namespace xo { /** current output from reader **/ ReaderResult result_; + /** true to enable reader debug logging **/ + bool debug_flag_ = false; }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 21ff70f0..d110df35 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -550,7 +550,7 @@ namespace xo { DDefineSsm::on_singleassign_token(const Token & tk, ParserStateMachine * p_psm) { - scope log(XO_DEBUG(true), xtag("defstate", defstate_)); + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("defstate", defstate_)); if ((defstate_ == defexprstatetype::def_2) || (defstate_ == defexprstatetype::def_4)) diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 30520811..e527dffa 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -114,7 +114,7 @@ namespace xo { DExpectTypeSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) { - scope log(XO_DEBUG(true)); + scope log(XO_DEBUG(p_psm->debug_flag())); TypeDescr td = nullptr; diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index ec19e994..5a9a81ec 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -216,8 +216,7 @@ namespace xo { DProgressSsm::on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); /* note: implementation should parallel .on_rightparen_token() */ diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index bfd14575..8aa85bf8 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -9,11 +9,13 @@ namespace xo { namespace scm { SchematikaReader::SchematikaReader(const ReaderConfig & config, obj expr_alloc) - : tokenizer_{config.tk_buffer_config_, config.tk_debug_flag_}, + : tokenizer_{config.tk_buffer_config_, + config.tk_debug_flag_}, parser_{config.parser_arena_config_, config.max_stringtable_cap_, expr_alloc, - config.parser_debug_flag_} + config.parser_debug_flag_}, + debug_flag_{config.reader_debug_flag_} { } @@ -35,18 +37,34 @@ namespace xo { const ReaderResult & SchematikaReader::read_expr(span_type input_ext, bool eof) { + scope log(XO_DEBUG(debug_flag_)); + + if (log) { + log(xtag("input_ext", input_ext)); + log(xtag("eof", eof)); + } + if (!input_ext.empty()) { auto [error, input] = tokenizer_.buffer_input_line(input_ext, eof); - // log && log(xtag("msg", "buffered input line")); - // log && log(xtag("input", input)); + if (log) { + log(xtag("msg", "before loop: buffered input line")); + log(xtag("input", input)); + } while (!input.empty()) { + log && log(xtag("msg", "loop"), + xtag("input", input)); + auto [tk, consumed, error] = tokenizer_.scan(input); + log && log(xtag("tk", tk), xtag("consumed", consumed)); + auto rem_input = input.after_prefix(consumed); + log && log(xtag("rem_input", rem_input)); + if (!tk.is_valid() && error.is_error()) { this->result_ = ReaderResult From 7432a0bd1d75350e640d18d50c76d6c8bddc9dc8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 23 Jan 2026 14:57:43 -0500 Subject: [PATCH 119/342] xo-reader2: readerreplxx works + streamline debugging --- include/xo/tokenizer2/Tokenizer.hpp | 8 ++--- src/tokenizer2/Tokenizer.cpp | 51 ++++++++++++----------------- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/include/xo/tokenizer2/Tokenizer.hpp b/include/xo/tokenizer2/Tokenizer.hpp index 69843a5a..3dc6da11 100644 --- a/include/xo/tokenizer2/Tokenizer.hpp +++ b/include/xo/tokenizer2/Tokenizer.hpp @@ -109,19 +109,19 @@ namespace xo { static bool is_2char_punctuation(CharT ch); /** assemble token from text @p token_text. - * @p initial_whitespace Amount of whitespace input being consumed from input. + * @p ws_span whitespace preceding token * @p token_text subset of input_line representing a single token. * @p p_input_state input state containing input_line. On exit current line cleared * if error * * retval.consumed will represent some possibly-empty prefix of @p input **/ - static scan_result assemble_token(std::size_t initial_whitespace, - const span_type & token_text, + static scan_result assemble_token( span_type ws_span, + span_type token_text, TkInputState * p_input_state); /** degenerate version of assemble_token() on reaching end-of-file **/ - static scan_result assemble_final_token(const span_type & token_text, + static scan_result assemble_final_token(span_type token_text, TkInputState * p_input_state); /** true if tokenizer contains stored prefix of diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index 2784072a..c79e10c3 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -110,8 +110,8 @@ namespace xo { } auto - Tokenizer::assemble_token(std::size_t initial_whitespace, - const span_type & token_text, + Tokenizer::assemble_token(span_type ws_span, + span_type token_text, TkInputState * p_input_state) -> result_type { /* literal|pretty|streamlined */ @@ -119,7 +119,7 @@ namespace xo { scope log(XO_DEBUG(p_input_state->debug_flag())); log && log(xtag("token_text", token_text), - xtag("initial_whitespace", initial_whitespace), + xtag("initial_whitespace", ws_span.size()), xtag("input_state", *p_input_state)); tokentype tk_type = tokentype::tk_invalid; @@ -598,18 +598,16 @@ namespace xo { // TOOD: report tk_text as span, // but must pin / unpin - /* input.prefix(0): - * require caller preserves current input line until it's entirely exhausted - */ return result_type(Token(tk_type, std::move(tk_text)), - p_input_state->current_line().prefix(0)); + span_type::concat(ws_span, + span_type(tk_start, tk_end))); } /*assemble_token*/ auto - Tokenizer::assemble_final_token(const span_type & token_text, + Tokenizer::assemble_final_token(span_type token_text, TkInputState * p_input_state) -> result_type { - return assemble_token(0 /*initial_whitespace*/, + return assemble_token(token_text.prefix(0) /*ws_span*/, token_text, p_input_state); } @@ -645,6 +643,7 @@ namespace xo { Tokenizer::scan(const span_type & input) -> result_type { scope log(XO_DEBUG(input_state_.debug_flag())); + log && log(xtag("input", input)); /* - Always at beginning of token when scan() invoked * - scan will not report any portion of line as consumed until it has @@ -659,12 +658,14 @@ namespace xo { const CharT * ix = this->input_state_.skip_leading_whitespace(); if(ix == input.hi()) { - log && log("end input -> consume current line"); + log && log("end buffered input -> consume current line"); /* entirety of current line has been tokenized * -> caller may consume it */ - return result_type::make_whitespace(this->input_state_.consume_current_line()); + this->input_state_.consume_current_line(); + + return result_type::make_whitespace(input); } /* ix: if ix < input.hi: first non-whitespace character after input_state_.current_pos_ */ @@ -697,27 +698,17 @@ namespace xo { ++ix; -#ifdef OBSOLETE // no longer a thing. either input ends in whitespace, or ends translation unit - if (ix == input.hi()) { - /* need more input to know if/when token complete */ - this->prefix_ += std::string(tk_start, input.hi()); + CharT ch2 = *ix; - log && log(xtag("captured-prefix1", this->prefix_)); - } else -#endif - { - CharT ch2 = *ix; - - if (((ch2 >= '0') && (ch2 <= '9')) - || ((ch2 >= 'A') && (ch2 <= 'Z')) - || ((ch2 >= 'a') && (ch2 <= 'z'))) + if (((ch2 >= '0') && (ch2 <= '9')) + || ((ch2 >= 'A') && (ch2 <= 'Z')) + || ((ch2 >= 'a') && (ch2 <= 'z'))) { /* treat as 1 char punctuation */ ; } else { - /* include next char */ - ++ix; - } + /* include next char */ + ++ix; } } else if (*ix == '"') { bool complete_flag = false; @@ -779,7 +770,7 @@ namespace xo { this->input_state_.advance_until(ix); - return assemble_token(whitespace_z, + return assemble_token(span_type(input.lo(), tk_start), span_type(tk_start, ix) /*token*/, &(this->input_state_)); } @@ -803,7 +794,7 @@ namespace xo { this->input_state_.advance_until(ix); /* ignore next char and complete token */ - return assemble_token(whitespace_z, + return assemble_token(span_type(input.lo(), tk_start), span_type(tk_start, ix) /*token*/, &(this->input_state_)); } @@ -854,7 +845,7 @@ namespace xo { this->input_state_.advance_until(ix); - return assemble_token(whitespace_z, + return assemble_token(span_type(input.lo(), tk_start), span_type(tk_start, ix) /*token*/, &(this->input_state_)); } /*_scan_aux*/ From bd60b45ae94368f2a18a762cdd5428d7f8dfc965 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 23 Jan 2026 15:11:36 -0500 Subject: [PATCH 120/342] xo-reader2: + f64 toplevel constant in interactive session --- example/readerreplxx/readerreplxx.cpp | 2 +- src/reader2/DExprSeqState.cpp | 30 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/example/readerreplxx/readerreplxx.cpp b/example/readerreplxx/readerreplxx.cpp index 28598292..5d74dc06 100644 --- a/example/readerreplxx/readerreplxx.cpp +++ b/example/readerreplxx/readerreplxx.cpp @@ -173,7 +173,7 @@ main() // accepting defaults too ReaderConfig rdr_config; { - //rdr_config.reader_debug_flag_ = true; + rdr_config.reader_debug_flag_ = true; //rdr_config.parser_debug_flag_ = true; //rdr_config.tk_debug_flag_ = true; } diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 33a68c15..65ec004c 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -6,8 +6,18 @@ #include "DExprSeqState.hpp" #include "DDefineSsm.hpp" #include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" +#include +#include +#include +#include +#include +#include namespace xo { + using xo::scm::DProgressSsm; + using xo::scm::DConstant; + using xo::scm::DFloat; + using xo::mm::AGCObject; using xo::mm::AAllocator; using xo::facet::with_facet; using xo::reflect::typeseq; @@ -182,6 +192,26 @@ namespace xo { DExprSeqState::on_f64_token(const Token & tk, ParserStateMachine * p_psm) { + switch (seqtype_) { + case exprseqtype::toplevel_interactive: + { + auto f64o = DFloat::box(p_psm->expr_alloc(), + tk.f64_value()); + auto * dconst = DConstant::make(p_psm->expr_alloc(), f64o); + auto expr = with_facet::mkobj(dconst); + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); + return; + } + case exprseqtype::toplevel_batch: + break; + case exprseqtype::N: + assert(false); // unreachable + break; + } + p_psm->illegal_input_on_token("DExprSeqState::on_f64_token", tk, this->get_expect_str()); From e94ec86c037527e4b8cfd650f5233a862bf5074c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 23 Jan 2026 15:25:30 -0500 Subject: [PATCH 121/342] xo-reader2: + on_bool_token scaffold in parser etc. --- idl/SyntaxStateMachine.json5 | 9 +++++++++ include/xo/reader2/DDefineSsm.hpp | 6 ++++++ include/xo/reader2/DExpectExprSsm.hpp | 6 ++++++ include/xo/reader2/DExpectSymbolSsm.hpp | 6 ++++++ include/xo/reader2/DExpectTypeSsm.hpp | 6 ++++++ include/xo/reader2/DExprSeqState.hpp | 5 +++++ include/xo/reader2/DProgressSsm.hpp | 2 ++ include/xo/reader2/ParserStateMachine.hpp | 3 +++ include/xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 ++ include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExpectExprSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 2 ++ include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 +++ include/xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 +++ src/reader2/DDefineSsm.cpp | 9 +++++++++ src/reader2/DExpectExprSsm.cpp | 9 +++++++++ src/reader2/DExpectSymbolSsm.cpp | 9 +++++++++ src/reader2/DExpectTypeSsm.cpp | 9 +++++++++ src/reader2/DExprSeqState.cpp | 9 +++++++++ src/reader2/DProgressSsm.cpp | 9 +++++++++ src/reader2/ISyntaxStateMachine_Any.cpp | 6 ++++++ src/reader2/ISyntaxStateMachine_DDefineSsm.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp | 5 +++++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DExprSeqState.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DProgressSsm.cpp | 5 +++++ src/reader2/ParserStateMachine.cpp | 13 ++++++++++++- 32 files changed, 166 insertions(+), 1 deletion(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index c12d3736..ad68d5bc 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -99,6 +99,15 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_bool_token", + doc: ["update state machine for incoming bool-token @p tk"], + return_type: "void", + args: [ + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_semicolon_token", doc: ["update state machine for incoming semicolon-token @p tk"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 1d94f3ad..912ccaf5 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -153,6 +153,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming bool token @p tk, + * overall parser state in @p p_psm + **/ + void on_bool_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming semicolon token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 7bf48dea..8b37a901 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -89,6 +89,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming bool token @p tk, + * overall parser state in @p p_psm + **/ + void on_bool_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming semicolon token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 1083b454..9ece9f51 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -123,6 +123,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming bool token @p tk, + * overall parser state in @p p_psm + **/ + void on_bool_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming semicolon token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index cf28fedf..b43b6eee 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -83,6 +83,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming bool token @p tk, + * overall parser state in @p p_psm + **/ + void on_bool_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming semicolon token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index eefcb15d..c9fe69e1 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -95,6 +95,11 @@ namespace xo { **/ void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming bool token @p tk, + * overall parser state in @p p_psm + **/ + void on_bool_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming semicolon token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 2b4121c3..2d0a4df2 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -143,6 +143,8 @@ namespace xo { ParserStateMachine * p_psm); void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + void on_bool_token(const Token & tk, + ParserStateMachine * p_psm); void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm); void on_parsed_symbol(std::string_view sym, diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index b838efe5..80690c29 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -141,6 +141,9 @@ namespace xo { /** operate state machine for incoming f64-token @p tk **/ void on_f64_token(const Token & tk); + /** operate state machine for incoming bool-token @p tk **/ + void on_bool_token(const Token & tk); + /** operate state machine for incoming semicolon-token @p tk **/ void on_semicolon_token(const Token & tk); diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index b68a1289..4e9bd99f 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -69,6 +69,8 @@ public: virtual void on_singleassign_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming f64-token @p tk **/ virtual void on_f64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; + /** update state machine for incoming bool-token @p tk **/ + virtual void on_bool_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming semicolon-token @p tk **/ virtual void on_semicolon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 52dc4059..5d339902 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -66,6 +66,7 @@ namespace scm { [[noreturn]] void on_colon_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_singleassign_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_f64_token(Opaque, const Token &, ParserStateMachine *) override; + [[noreturn]] void on_bool_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_semicolon_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index 3084631c..cdc01066 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming bool-token @p tk **/ + static void on_bool_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index efebe9c7..8758347c 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming bool-token @p tk **/ + static void on_bool_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index d870667a..95adca39 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming bool-token @p tk **/ + static void on_bool_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index 23eb8af0..81d13c47 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming bool-token @p tk **/ + static void on_bool_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index 020e7552..f95989ad 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming bool-token @p tk **/ + static void on_bool_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 1735b2b1..0362e433 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming bool-token @p tk **/ + static void on_bool_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index da16f766..fbfd99b7 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -70,6 +70,9 @@ namespace scm { void on_f64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_f64_token(_dcast(data), tk, p_psm); } + void on_bool_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_bool_token(_dcast(data), tk, p_psm); + } void on_semicolon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_semicolon_token(_dcast(data), tk, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index cfa354b9..2741dc76 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -74,6 +74,9 @@ public: void on_f64_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_f64_token(O::data(), tk, p_psm); } + void on_bool_token(const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_bool_token(O::data(), tk, p_psm); + } void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_semicolon_token(O::data(), tk, p_psm); } diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index d110df35..063572d3 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -576,6 +576,15 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_bool_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DDefineSsm::on_bool_token", + tk, + this->get_expect_str()); + } + void DDefineSsm::on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index cea683c4..a6aff620 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -170,6 +170,15 @@ namespace xo { p_psm); } + void + DExpectExprSsm::on_bool_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectExprSsm::on_bool_token", + tk, + this->get_expect_str()); + } + void DExpectExprSsm::on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index e55d35be..4bb3c05a 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -158,6 +158,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_bool_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectSymbolSsm::on_bool_token", + tk, + this->get_expect_str()); + } + void DExpectSymbolSsm::on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index e527dffa..643defb5 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -101,6 +101,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectTypeSsm::on_bool_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectTypeSsm::on_bool_token", + tk, + this->get_expect_str()); + } + void DExpectTypeSsm::on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 65ec004c..c6e53ba2 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -217,6 +217,15 @@ namespace xo { this->get_expect_str()); } + void + DExprSeqState::on_bool_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExprSeqState::on_bool_token", + tk, + this->get_expect_str()); + } + void DExprSeqState::on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 5a9a81ec..00571edb 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -212,6 +212,15 @@ namespace xo { this->get_expect_str()); } + void + DProgressSsm::on_bool_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DProgressSsm::on_bool_token", + tk, + this->get_expect_str()); + } + void DProgressSsm::on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index a789bce9..4637f4c0 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -70,6 +70,12 @@ ISyntaxStateMachine_Any::on_f64_token(Opaque, const Token &, ParserStateMachine _fatal(); } +auto +ISyntaxStateMachine_Any::on_bool_token(Opaque, const Token &, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_semicolon_token(Opaque, const Token &, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index 89589841..ed07a417 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DDefineSsm::on_bool_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_bool_token(tk, p_psm); + } + auto ISyntaxStateMachine_DDefineSsm::on_semicolon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index 858ce1ab..7ad963c8 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectExprSsm::on_bool_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_bool_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectExprSsm::on_semicolon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 1982212c..0012daad 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectSymbolSsm::on_bool_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_bool_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectSymbolSsm::on_semicolon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index eb66f8db..20d930b9 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectTypeSsm::on_bool_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_bool_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectTypeSsm::on_semicolon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index cfd419b9..ddf20702 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExprSeqState::on_bool_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_bool_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExprSeqState::on_semicolon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 53c8706c..535ac2f6 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DProgressSsm::on_bool_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_bool_token(tk, p_psm); + } + auto ISyntaxStateMachine_DProgressSsm::on_semicolon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 80841fd8..3915aca7 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -187,13 +187,16 @@ namespace xo { this->on_f64_token(tk); break; + case tokentype::tk_bool: + this->on_bool_token(tk); + break; + case tokentype::tk_semicolon: this->on_semicolon_token(tk); break; // all the not-yet handled cases case tokentype::tk_invalid: - case tokentype::tk_bool: case tokentype::tk_i64: case tokentype::tk_string: case tokentype::tk_leftparen: @@ -280,6 +283,14 @@ namespace xo { stack_->top().on_f64_token(tk, this); } + void + ParserStateMachine::on_bool_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + stack_->top().on_bool_token(tk, this); + } + void ParserStateMachine::on_semicolon_token(const Token & tk) { From b7a813ec07e42b9c1db94f3af42dc0ff9a0a9012 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 23 Jan 2026 16:34:33 -0500 Subject: [PATCH 122/342] xo-reader2: fix clearing result in SchematikaReader --- example/readerreplxx/readerreplxx.cpp | 2 ++ include/xo/reader2/SchematikaReader.hpp | 3 +++ src/reader2/DExprSeqState.cpp | 22 ++++++++++++++++++++++ src/reader2/SchematikaReader.cpp | 6 ++++++ 4 files changed, 33 insertions(+) diff --git a/example/readerreplxx/readerreplxx.cpp b/example/readerreplxx/readerreplxx.cpp index 5d74dc06..341893cf 100644 --- a/example/readerreplxx/readerreplxx.cpp +++ b/example/readerreplxx/readerreplxx.cpp @@ -110,6 +110,8 @@ namespace { pps.prettyn(expr_pr); + p_reader->reset_result(); + *p_input = remaining; return true; diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index 540c19bc..fd26a4ec 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -56,6 +56,9 @@ namespace xo { /** consume input @p input_cstr **/ const ReaderResult & read_expr(span_type input_span, bool eof); + /** reset @ref result_ to nominal value **/ + void reset_result(); + /** reset to known starting point after encountering an error. * - remainder of stashed current line. * Necesary for well-formatted error reporting. diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index c6e53ba2..1d7aea93 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include namespace xo { @@ -221,6 +223,26 @@ namespace xo { DExprSeqState::on_bool_token(const Token & tk, ParserStateMachine * p_psm) { + switch (seqtype_) { + case exprseqtype::toplevel_interactive: + { + auto dvalue = DBoolean::box(p_psm->expr_alloc(), + tk.bool_value()); + auto * dconst = DConstant::make(p_psm->expr_alloc(), dvalue); + auto expr = with_facet::mkobj(dconst); + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); + return; + } + case exprseqtype::toplevel_batch: + break; + case exprseqtype::N: + assert(false); // unreachable + break; + } + p_psm->illegal_input_on_token("DExprSeqState::on_bool_token", tk, this->get_expect_str()); diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index 8aa85bf8..4dd8600c 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -142,6 +142,12 @@ namespace xo { return this->result_; } + void + SchematikaReader::reset_result() + { + this->parser_.reset_result(); + } + void SchematikaReader::reset_to_idle_toplevel() { From e7930122a7306e055ea404987a2e256b6549ce23 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 23 Jan 2026 16:45:15 -0500 Subject: [PATCH 123/342] xo-reader2: + on_i64_token in all Ssm classes. --- idl/SyntaxStateMachine.json5 | 9 +++++++++ include/xo/reader2/DDefineSsm.hpp | 6 ++++++ include/xo/reader2/DExpectExprSsm.hpp | 6 ++++++ include/xo/reader2/DExpectSymbolSsm.hpp | 6 ++++++ include/xo/reader2/DExpectTypeSsm.hpp | 6 ++++++ include/xo/reader2/DExprSeqState.hpp | 5 +++++ include/xo/reader2/DProgressSsm.hpp | 2 ++ include/xo/reader2/ParserStateMachine.hpp | 3 +++ include/xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 ++ include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExpectExprSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 2 ++ include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 +++ include/xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 +++ src/reader2/DDefineSsm.cpp | 9 +++++++++ src/reader2/DExpectExprSsm.cpp | 9 +++++++++ src/reader2/DExpectSymbolSsm.cpp | 9 +++++++++ src/reader2/DExpectTypeSsm.cpp | 9 +++++++++ src/reader2/DExprSeqState.cpp | 9 +++++++++ src/reader2/DProgressSsm.cpp | 9 +++++++++ src/reader2/ISyntaxStateMachine_Any.cpp | 6 ++++++ src/reader2/ISyntaxStateMachine_DDefineSsm.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp | 5 +++++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DExprSeqState.cpp | 5 +++++ src/reader2/ISyntaxStateMachine_DProgressSsm.cpp | 5 +++++ src/reader2/ParserStateMachine.cpp | 13 ++++++++++++- 32 files changed, 166 insertions(+), 1 deletion(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index ad68d5bc..d03808c1 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -99,6 +99,15 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_i64_token", + doc: ["update state machine for incoming i64-token @p tk"], + return_type: "void", + args: [ + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_bool_token", doc: ["update state machine for incoming bool-token @p tk"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 912ccaf5..0bafe4cb 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -153,6 +153,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming i64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_i64_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming bool token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 8b37a901..5a628742 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -89,6 +89,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming i64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_i64_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming bool token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 9ece9f51..910c1978 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -123,6 +123,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming i64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_i64_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming bool token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index b43b6eee..77a54f61 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -83,6 +83,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming i64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_i64_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming bool token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index c9fe69e1..4ee2e177 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -95,6 +95,11 @@ namespace xo { **/ void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming i64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_i64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming bool token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 2d0a4df2..ae3bdb85 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -143,6 +143,8 @@ namespace xo { ParserStateMachine * p_psm); void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + void on_i64_token(const Token & tk, + ParserStateMachine * p_psm); void on_bool_token(const Token & tk, ParserStateMachine * p_psm); void on_semicolon_token(const Token & tk, diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 80690c29..870b1d66 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -141,6 +141,9 @@ namespace xo { /** operate state machine for incoming f64-token @p tk **/ void on_f64_token(const Token & tk); + /** operate state machine for incoming i64-token @p tk **/ + void on_i64_token(const Token & tk); + /** operate state machine for incoming bool-token @p tk **/ void on_bool_token(const Token & tk); diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index 4e9bd99f..feb4a62b 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -69,6 +69,8 @@ public: virtual void on_singleassign_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming f64-token @p tk **/ virtual void on_f64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; + /** update state machine for incoming i64-token @p tk **/ + virtual void on_i64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming bool-token @p tk **/ virtual void on_bool_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming semicolon-token @p tk **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 5d339902..06fd2ff9 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -66,6 +66,7 @@ namespace scm { [[noreturn]] void on_colon_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_singleassign_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_f64_token(Opaque, const Token &, ParserStateMachine *) override; + [[noreturn]] void on_i64_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_bool_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_semicolon_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index cdc01066..4c22c587 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming i64-token @p tk **/ + static void on_i64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 8758347c..6c64836e 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming i64-token @p tk **/ + static void on_i64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 95adca39..0647ce38 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming i64-token @p tk **/ + static void on_i64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index 81d13c47..ec3f10fc 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming i64-token @p tk **/ + static void on_i64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index f95989ad..c8205ff1 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming i64-token @p tk **/ + static void on_i64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 0362e433..9cec85e1 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -66,6 +66,8 @@ namespace xo { static void on_singleassign_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming f64-token @p tk **/ static void on_f64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming i64-token @p tk **/ + static void on_i64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index fbfd99b7..31681b46 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -70,6 +70,9 @@ namespace scm { void on_f64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_f64_token(_dcast(data), tk, p_psm); } + void on_i64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_i64_token(_dcast(data), tk, p_psm); + } void on_bool_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_bool_token(_dcast(data), tk, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 2741dc76..4df02804 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -74,6 +74,9 @@ public: void on_f64_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_f64_token(O::data(), tk, p_psm); } + void on_i64_token(const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_i64_token(O::data(), tk, p_psm); + } void on_bool_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_bool_token(O::data(), tk, p_psm); } diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 063572d3..eb1d5d55 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -576,6 +576,15 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_i64_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DDefineSsm::on_i64_token", + tk, + this->get_expect_str()); + } + void DDefineSsm::on_bool_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index a6aff620..553973a6 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -170,6 +170,15 @@ namespace xo { p_psm); } + void + DExpectExprSsm::on_i64_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectExprSsm::on_i64_token", + tk, + this->get_expect_str()); + } + void DExpectExprSsm::on_bool_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 4bb3c05a..d32f3ce5 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -158,6 +158,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_i64_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectSymbolSsm::on_i64_token", + tk, + this->get_expect_str()); + } + void DExpectSymbolSsm::on_bool_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 643defb5..d20128c0 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -101,6 +101,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectTypeSsm::on_i64_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectTypeSsm::on_i64_token", + tk, + this->get_expect_str()); + } + void DExpectTypeSsm::on_bool_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 1d7aea93..6f196963 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -219,6 +219,15 @@ namespace xo { this->get_expect_str()); } + void + DExprSeqState::on_i64_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExprSeqState::on_i64_token", + tk, + this->get_expect_str()); + } + void DExprSeqState::on_bool_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 00571edb..f6b14bc1 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -212,6 +212,15 @@ namespace xo { this->get_expect_str()); } + void + DProgressSsm::on_i64_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DProgressSsm::on_i64_token", + tk, + this->get_expect_str()); + } + void DProgressSsm::on_bool_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 4637f4c0..39fcea13 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -70,6 +70,12 @@ ISyntaxStateMachine_Any::on_f64_token(Opaque, const Token &, ParserStateMachine _fatal(); } +auto +ISyntaxStateMachine_Any::on_i64_token(Opaque, const Token &, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_bool_token(Opaque, const Token &, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index ed07a417..69520cae 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DDefineSsm::on_i64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_i64_token(tk, p_psm); + } + auto ISyntaxStateMachine_DDefineSsm::on_bool_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_bool_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index 7ad963c8..b247c821 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectExprSsm::on_i64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_i64_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectExprSsm::on_bool_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_bool_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 0012daad..318e68cb 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectSymbolSsm::on_i64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_i64_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectSymbolSsm::on_bool_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_bool_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 20d930b9..3d98c1f8 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectTypeSsm::on_i64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_i64_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectTypeSsm::on_bool_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_bool_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index ddf20702..8ec4d055 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DExprSeqState::on_i64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_i64_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExprSeqState::on_bool_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_bool_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 535ac2f6..45e9a566 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -58,6 +58,11 @@ namespace xo { self.on_f64_token(tk, p_psm); } auto + ISyntaxStateMachine_DProgressSsm::on_i64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_i64_token(tk, p_psm); + } + auto ISyntaxStateMachine_DProgressSsm::on_bool_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_bool_token(tk, p_psm); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 3915aca7..9a594340 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -187,6 +187,10 @@ namespace xo { this->on_f64_token(tk); break; + case tokentype::tk_i64: + this->on_i64_token(tk); + break; + case tokentype::tk_bool: this->on_bool_token(tk); break; @@ -197,7 +201,6 @@ namespace xo { // all the not-yet handled cases case tokentype::tk_invalid: - case tokentype::tk_i64: case tokentype::tk_string: case tokentype::tk_leftparen: case tokentype::tk_rightparen: @@ -283,6 +286,14 @@ namespace xo { stack_->top().on_f64_token(tk, this); } + void + ParserStateMachine::on_i64_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + stack_->top().on_i64_token(tk, this); + } + void ParserStateMachine::on_bool_token(const Token & tk) { From fa6f6defc16f813e342a99d93aeea2b87c855aa3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 23 Jan 2026 16:48:24 -0500 Subject: [PATCH 124/342] xo-reader2: accept i64 token in top-level interactive session --- src/reader2/DExprSeqState.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 6f196963..86c98d84 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -223,6 +225,26 @@ namespace xo { DExprSeqState::on_i64_token(const Token & tk, ParserStateMachine * p_psm) { + switch (seqtype_) { + case exprseqtype::toplevel_interactive: + { + auto i64o = DFloat::box(p_psm->expr_alloc(), + tk.i64_value()); + auto * dconst = DConstant::make(p_psm->expr_alloc(), i64o); + auto expr = with_facet::mkobj(dconst); + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); + return; + } + case exprseqtype::toplevel_batch: + break; + case exprseqtype::N: + assert(false); // unreachable + break; + } + p_psm->illegal_input_on_token("DExprSeqState::on_i64_token", tk, this->get_expect_str()); From 4d0c97ab7a4a3ca82f186df2ddea6d20301d7db1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 23 Jan 2026 17:23:19 -0500 Subject: [PATCH 125/342] xo-reader2: top-level string literal + on_string_token() in SSM --- idl/SyntaxStateMachine.json5 | 9 ++++++ include/xo/reader2/DDefineSsm.hpp | 6 ++++ include/xo/reader2/DExpectExprSsm.hpp | 6 ++++ include/xo/reader2/DExpectSymbolSsm.hpp | 6 ++++ include/xo/reader2/DExpectTypeSsm.hpp | 6 ++++ include/xo/reader2/DExprSeqState.hpp | 5 +++ include/xo/reader2/DProgressSsm.hpp | 2 ++ include/xo/reader2/ParserStateMachine.hpp | 3 ++ .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 ++ .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectExprSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 2 ++ .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 ++ .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 ++ src/reader2/DDefineSsm.cpp | 9 ++++++ src/reader2/DExpectExprSsm.cpp | 9 ++++++ src/reader2/DExpectSymbolSsm.cpp | 9 ++++++ src/reader2/DExpectTypeSsm.cpp | 9 ++++++ src/reader2/DExprSeqState.cpp | 32 +++++++++++++++++++ src/reader2/DProgressSsm.cpp | 9 ++++++ src/reader2/ISyntaxStateMachine_Any.cpp | 6 ++++ .../ISyntaxStateMachine_DDefineSsm.cpp | 5 +++ .../ISyntaxStateMachine_DExpectExprSsm.cpp | 5 +++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 +++ .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 +++ .../ISyntaxStateMachine_DExprSeqState.cpp | 5 +++ .../ISyntaxStateMachine_DProgressSsm.cpp | 5 +++ src/reader2/ParserStateMachine.cpp | 13 +++++++- 32 files changed, 189 insertions(+), 1 deletion(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index d03808c1..72dbbf13 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -117,6 +117,15 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_string_token", + doc: ["update state machine for incoming string-token @p tk"], + return_type: "void", + args: [ + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_semicolon_token", doc: ["update state machine for incoming semicolon-token @p tk"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 0bafe4cb..d0af630d 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -147,6 +147,12 @@ namespace xo { void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming string tokne @p tk, + * overall parser state in @p p_psm + **/ + void on_string_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 5a628742..c1c9ede7 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -83,6 +83,12 @@ namespace xo { void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming string token @p tk, + * overall parser state in @p p_psm + **/ + void on_string_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 910c1978..03dd8408 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -117,6 +117,12 @@ namespace xo { void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming string token @p tk, + * overall parser state in @p p_psm + **/ + void on_string_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 77a54f61..8290225f 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -77,6 +77,12 @@ namespace xo { void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming string token @p tk, + * overall parser state in @p p_psm + **/ + void on_string_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 4ee2e177..acfcba64 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -90,6 +90,11 @@ namespace xo { **/ void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming string token @p tk, + * overall parser state in @p p_psm + **/ + void on_string_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index ae3bdb85..33981d76 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -141,6 +141,8 @@ namespace xo { ParserStateMachine * p_psm); void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + void on_string_token(const Token & tk, + ParserStateMachine * p_psm); void on_f64_token(const Token & tk, ParserStateMachine * p_psm); void on_i64_token(const Token & tk, diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 870b1d66..eae4d663 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -138,6 +138,9 @@ namespace xo { /** operate state machine for incoming singleassign-token @p tk **/ void on_singleassign_token(const Token & tk); + /** operate state machine for incoming string-otoken @p tk **/ + void on_string_token(const Token & tk); + /** operate state machine for incoming f64-token @p tk **/ void on_f64_token(const Token & tk); diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index feb4a62b..d501232f 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -73,6 +73,8 @@ public: virtual void on_i64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming bool-token @p tk **/ virtual void on_bool_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; + /** update state machine for incoming string-token @p tk **/ + virtual void on_string_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for incoming semicolon-token @p tk **/ virtual void on_semicolon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 06fd2ff9..351f6a8c 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -68,6 +68,7 @@ namespace scm { [[noreturn]] void on_f64_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_i64_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_bool_token(Opaque, const Token &, ParserStateMachine *) override; + [[noreturn]] void on_string_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_semicolon_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index 4c22c587..432b6fac 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -70,6 +70,8 @@ namespace xo { static void on_i64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming string-token @p tk **/ + static void on_string_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 6c64836e..aa1d082e 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -70,6 +70,8 @@ namespace xo { static void on_i64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming string-token @p tk **/ + static void on_string_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 0647ce38..039fcae2 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -70,6 +70,8 @@ namespace xo { static void on_i64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming string-token @p tk **/ + static void on_string_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index ec3f10fc..64106cfb 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -70,6 +70,8 @@ namespace xo { static void on_i64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming string-token @p tk **/ + static void on_string_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index c8205ff1..fbf1f317 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -70,6 +70,8 @@ namespace xo { static void on_i64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming string-token @p tk **/ + static void on_string_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 9cec85e1..0277e1ba 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -70,6 +70,8 @@ namespace xo { static void on_i64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming bool-token @p tk **/ static void on_bool_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for incoming string-token @p tk **/ + static void on_string_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update state machine for incoming semicolon-token @p tk **/ static void on_semicolon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 31681b46..fccd523e 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -76,6 +76,9 @@ namespace scm { void on_bool_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_bool_token(_dcast(data), tk, p_psm); } + void on_string_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_string_token(_dcast(data), tk, p_psm); + } void on_semicolon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_semicolon_token(_dcast(data), tk, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 4df02804..b91381d0 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -80,6 +80,9 @@ public: void on_bool_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_bool_token(O::data(), tk, p_psm); } + void on_string_token(const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_string_token(O::data(), tk, p_psm); + } void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_semicolon_token(O::data(), tk, p_psm); } diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index eb1d5d55..0f4ac7e1 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -567,6 +567,15 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_string_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DDefineSsm::on_string_token", + tk, + this->get_expect_str()); + } + void DDefineSsm::on_f64_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 553973a6..a5d46052 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -147,6 +147,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectExprSsm::on_string_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectExprSsm::on_string_token", + tk, + this->get_expect_str()); + } + void DExpectExprSsm::on_f64_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index d32f3ce5..d41f08da 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -149,6 +149,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_string_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectSymbolSsm::on_string_token", + tk, + this->get_expect_str()); + } + void DExpectSymbolSsm::on_f64_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index d20128c0..b8be164c 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -92,6 +92,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectTypeSsm::on_string_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectTypeSsm", + tk, + this->get_expect_str()); + } + void DExpectTypeSsm::on_f64_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 86c98d84..90b9824b 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -192,6 +194,36 @@ namespace xo { this->get_expect_str()); } + void + DExprSeqState::on_string_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (seqtype_) { + case exprseqtype::toplevel_interactive: + { + DString * dstr = DString::from_cstr(p_psm->expr_alloc(), + tk.text().c_str()); + obj str(dstr); + auto * dconst = DConstant::make(p_psm->expr_alloc(), str); + obj expr(dconst); + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); + return; + } + case exprseqtype::toplevel_batch: + break; + case exprseqtype::N: + assert(false); // unreachable + break; + } + + p_psm->illegal_input_on_token("DExprSeqState::on_string_token", + tk, + this->get_expect_str()); + } + void DExprSeqState::on_f64_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index f6b14bc1..50ec2fbe 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -203,6 +203,15 @@ namespace xo { this->get_expect_str()); } + void + DProgressSsm::on_string_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DProgressSsm::on_string_token", + tk, + this->get_expect_str()); + } + void DProgressSsm::on_f64_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 39fcea13..f270c352 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -82,6 +82,12 @@ ISyntaxStateMachine_Any::on_bool_token(Opaque, const Token &, ParserStateMachine _fatal(); } +auto +ISyntaxStateMachine_Any::on_string_token(Opaque, const Token &, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_semicolon_token(Opaque, const Token &, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index 69520cae..c39c51b2 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -68,6 +68,11 @@ namespace xo { self.on_bool_token(tk, p_psm); } auto + ISyntaxStateMachine_DDefineSsm::on_string_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_string_token(tk, p_psm); + } + auto ISyntaxStateMachine_DDefineSsm::on_semicolon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index b247c821..0e5efa5d 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -68,6 +68,11 @@ namespace xo { self.on_bool_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectExprSsm::on_string_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_string_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectExprSsm::on_semicolon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 318e68cb..0b47c31a 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -68,6 +68,11 @@ namespace xo { self.on_bool_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectSymbolSsm::on_string_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_string_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectSymbolSsm::on_semicolon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 3d98c1f8..515b81a8 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -68,6 +68,11 @@ namespace xo { self.on_bool_token(tk, p_psm); } auto + ISyntaxStateMachine_DExpectTypeSsm::on_string_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_string_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExpectTypeSsm::on_semicolon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index 8ec4d055..04cc4516 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -68,6 +68,11 @@ namespace xo { self.on_bool_token(tk, p_psm); } auto + ISyntaxStateMachine_DExprSeqState::on_string_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_string_token(tk, p_psm); + } + auto ISyntaxStateMachine_DExprSeqState::on_semicolon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 45e9a566..28b69cfb 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -68,6 +68,11 @@ namespace xo { self.on_bool_token(tk, p_psm); } auto + ISyntaxStateMachine_DProgressSsm::on_string_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_string_token(tk, p_psm); + } + auto ISyntaxStateMachine_DProgressSsm::on_semicolon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { self.on_semicolon_token(tk, p_psm); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 9a594340..adc14f1b 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -183,6 +183,10 @@ namespace xo { this->on_singleassign_token(tk); break; + case tokentype::tk_string: + this->on_string_token(tk); + break; + case tokentype::tk_f64: this->on_f64_token(tk); break; @@ -201,7 +205,6 @@ namespace xo { // all the not-yet handled cases case tokentype::tk_invalid: - case tokentype::tk_string: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: @@ -278,6 +281,14 @@ namespace xo { stack_->top().on_singleassign_token(tk, this); } + void + ParserStateMachine::on_string_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + stack_->top().on_string_token(tk, this); + } + void ParserStateMachine::on_f64_token(const Token & tk) { From a8df123045b91aa7f9455f82b140109a3be6616a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 23 Jan 2026 19:01:12 -0500 Subject: [PATCH 126/342] xo-reader2: refactor: push token dispatch to satellite SSMs --- idl/SyntaxStateMachine.json5 | 85 +--------- include/xo/reader2/DDefineSsm.hpp | 6 + include/xo/reader2/DExpectExprSsm.hpp | 6 + include/xo/reader2/DExpectSymbolSsm.hpp | 6 + include/xo/reader2/DExpectTypeSsm.hpp | 6 + include/xo/reader2/DExprSeqState.hpp | 6 + include/xo/reader2/DProgressSsm.hpp | 6 + include/xo/reader2/ParserStateMachine.hpp | 30 ---- .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 22 +-- .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 11 +- .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 22 +-- .../ISyntaxStateMachine_DExpectExprSsm.hpp | 22 +-- .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 22 +-- .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 22 +-- .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 22 +-- .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 22 +-- .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 31 +--- .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 31 +--- src/reader2/DDefineSsm.cpp | 90 +++++++++- src/reader2/DExpectExprSsm.cpp | 86 ++++++++++ src/reader2/DExpectSymbolSsm.cpp | 86 ++++++++++ src/reader2/DExpectTypeSsm.cpp | 86 ++++++++++ src/reader2/DExprSeqState.cpp | 86 ++++++++++ src/reader2/DProgressSsm.cpp | 86 ++++++++++ src/reader2/ISyntaxStateMachine_Any.cpp | 56 +------ .../ISyntaxStateMachine_DDefineSsm.cpp | 49 +----- .../ISyntaxStateMachine_DExpectExprSsm.cpp | 49 +----- .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 49 +----- .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 49 +----- .../ISyntaxStateMachine_DExprSeqState.cpp | 49 +----- .../ISyntaxStateMachine_DProgressSsm.cpp | 49 +----- src/reader2/ParserStateMachine.cpp | 158 +----------------- 32 files changed, 590 insertions(+), 816 deletions(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 72dbbf13..15a36f12 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -46,89 +46,8 @@ ], nonconst_methods: [ { - name: "on_symbol_token", - doc: ["operate state machine for incoming symbol-token @p tk"], - return_type: "void", - args: [ - {type: "const Token &", name: "tk"}, - {type: "ParserStateMachine *", name: "p_psm"}, - ], - }, - { - name: "on_def_token", - doc: ["update state machine for incoming define-keyword-token @p tk"], - return_type: "void", - args: [ - {type: "const Token &", name: "tk"}, - {type: "ParserStateMachine *", name: "p_psm"}, - ], - }, - { - name: "on_if_token", - doc: ["update state machine for incoming if-keyword-token @p tk"], - return_type: "void", - args: [ - {type: "const Token &", name: "tk"}, - {type: "ParserStateMachine *", name: "p_psm"}, - ], - }, - { - name: "on_colon_token", - doc: ["update state machine for incoming colon-token @p tk"], - return_type: "void", - args: [ - {type: "const Token &", name: "tk"}, - {type: "ParserStateMachine *", name: "p_psm"}, - ], - }, - { - name: "on_singleassign_token", - doc: ["update state machine for incoming singleassign-token @p tk"], - return_type: "void", - args: [ - {type: "const Token &", name: "tk"}, - {type: "ParserStateMachine *", name: "p_psm"}, - ], - }, - { - name: "on_f64_token", - doc: ["update state machine for incoming f64-token @p tk"], - return_type: "void", - args: [ - {type: "const Token &", name: "tk"}, - {type: "ParserStateMachine *", name: "p_psm"}, - ], - }, - { - name: "on_i64_token", - doc: ["update state machine for incoming i64-token @p tk"], - return_type: "void", - args: [ - {type: "const Token &", name: "tk"}, - {type: "ParserStateMachine *", name: "p_psm"}, - ], - }, - { - name: "on_bool_token", - doc: ["update state machine for incoming bool-token @p tk"], - return_type: "void", - args: [ - {type: "const Token &", name: "tk"}, - {type: "ParserStateMachine *", name: "p_psm"}, - ], - }, - { - name: "on_string_token", - doc: ["update state machine for incoming string-token @p tk"], - return_type: "void", - args: [ - {type: "const Token &", name: "tk"}, - {type: "ParserStateMachine *", name: "p_psm"}, - ], - }, - { - name: "on_semicolon_token", - doc: ["update state machine for incoming semicolon-token @p tk"], + name: "on_token", + doc: ["operate state machine for incoming token @p tk"], return_type: "void", args: [ {type: "const Token &", name: "tk"}, diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index d0af630d..9f707fca 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -117,6 +117,12 @@ namespace xo { **/ std::string_view get_expect_str() const noexcept; + /** operate state machine for this syntax on incoming token @p tk + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + /** operate state machine for this syntax on incoming symbol-token @p tk * with overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index c1c9ede7..85d4e5e1 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -53,6 +53,12 @@ namespace xo { **/ std::string_view get_expect_str() const noexcept; + /** operate state machine for this syntax on incoming token @p tk + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + /** operate state machine for this syntax on incoming symbol-token @p tk * with overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 03dd8408..4cb04019 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -93,6 +93,12 @@ namespace xo { void on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm); + /** operate state machine for this syntax on incoming token @p tk + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming token @p tk, * overall parser state in @p p_psm. **/ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 8290225f..346a6d6c 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -47,6 +47,12 @@ namespace xo { **/ std::string_view get_expect_str() const noexcept; + /** operate state machine for this syntax on incoming token @p tk + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + /** operate state machien for this syntax on incoming symbol-token @p tk * with overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index acfcba64..72566004 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -65,6 +65,12 @@ namespace xo { **/ std::string_view get_expect_str() const noexcept; + /** operate state machine for this syntax on incoming token @p tk + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + /** operate state machine for this syntax on incoming symbol token @p tk * with overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 33981d76..7258731c 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -131,6 +131,12 @@ namespace xo { /** @defgroup scm-progressssm-ssm-facet syntaxstatemachine facet methods **/ /// @{ + /** operate state machine for this syntax on incoming token @p tk + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); void on_def_token(const Token & tk, diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index eae4d663..a674e7e2 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -123,36 +123,6 @@ namespace xo { **/ void on_token(const Token & tk); - /** operate state machine for incoming symbol-token @p tk **/ - void on_symbol_token(const Token & tk); - - /** operate state machine for incoming define-token @p tk **/ - void on_def_token(const Token & tk); - - /** operate state machine for incoming if-token @p tk **/ - void on_if_token(const Token & tk); - - /** operate state machine for incoming colon-token @p tk **/ - void on_colon_token(const Token & tk); - - /** operate state machine for incoming singleassign-token @p tk **/ - void on_singleassign_token(const Token & tk); - - /** operate state machine for incoming string-otoken @p tk **/ - void on_string_token(const Token & tk); - - /** operate state machine for incoming f64-token @p tk **/ - void on_f64_token(const Token & tk); - - /** operate state machine for incoming i64-token @p tk **/ - void on_i64_token(const Token & tk); - - /** operate state machine for incoming bool-token @p tk **/ - void on_bool_token(const Token & tk); - - /** operate state machine for incoming semicolon-token @p tk **/ - void on_semicolon_token(const Token & tk); - ///@} /** @defgroup scm-parserstatemachine-error-entrypoints error entry points **/ ///@{ diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index d501232f..3115d692 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -57,26 +57,8 @@ public: virtual std::string_view get_expect_str(Copaque data) const noexcept = 0; // nonconst methods - /** operate state machine for incoming symbol-token @p tk **/ - virtual void on_symbol_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; - /** update state machine for incoming define-keyword-token @p tk **/ - virtual void on_def_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; - /** update state machine for incoming if-keyword-token @p tk **/ - virtual void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; - /** update state machine for incoming colon-token @p tk **/ - virtual void on_colon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; - /** update state machine for incoming singleassign-token @p tk **/ - virtual void on_singleassign_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; - /** update state machine for incoming f64-token @p tk **/ - virtual void on_f64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; - /** update state machine for incoming i64-token @p tk **/ - virtual void on_i64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; - /** update state machine for incoming bool-token @p tk **/ - virtual void on_bool_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; - /** update state machine for incoming string-token @p tk **/ - virtual void on_string_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; - /** update state machine for incoming semicolon-token @p tk **/ - virtual void on_semicolon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; + /** operate state machine for incoming token @p tk **/ + virtual void on_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; /** update stat machine for incoming parsed symbol @p sym **/ virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 351f6a8c..45be148e 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -60,16 +60,7 @@ namespace scm { [[noreturn]] std::string_view get_expect_str(Copaque) const noexcept override { _fatal(); } // nonconst methods - [[noreturn]] void on_symbol_token(Opaque, const Token &, ParserStateMachine *) override; - [[noreturn]] void on_def_token(Opaque, const Token &, ParserStateMachine *) override; - [[noreturn]] void on_if_token(Opaque, const Token &, ParserStateMachine *) override; - [[noreturn]] void on_colon_token(Opaque, const Token &, ParserStateMachine *) override; - [[noreturn]] void on_singleassign_token(Opaque, const Token &, ParserStateMachine *) override; - [[noreturn]] void on_f64_token(Opaque, const Token &, ParserStateMachine *) override; - [[noreturn]] void on_i64_token(Opaque, const Token &, ParserStateMachine *) override; - [[noreturn]] void on_bool_token(Opaque, const Token &, ParserStateMachine *) override; - [[noreturn]] void on_string_token(Opaque, const Token &, ParserStateMachine *) override; - [[noreturn]] void on_semicolon_token(Opaque, const Token &, ParserStateMachine *) override; + [[noreturn]] void on_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression(Opaque, obj, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index 432b6fac..dad8ff29 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -54,26 +54,8 @@ namespace xo { static std::string_view get_expect_str(const DDefineSsm & self) noexcept; // non-const methods - /** operate state machine for incoming symbol-token @p tk **/ - static void on_symbol_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming define-keyword-token @p tk **/ - static void on_def_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming if-keyword-token @p tk **/ - static void on_if_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming colon-token @p tk **/ - static void on_colon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming singleassign-token @p tk **/ - static void on_singleassign_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming f64-token @p tk **/ - static void on_f64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming i64-token @p tk **/ - static void on_i64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming bool-token @p tk **/ - static void on_bool_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming string-token @p tk **/ - static void on_string_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming semicolon-token @p tk **/ - static void on_semicolon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** operate state machine for incoming token @p tk **/ + static void on_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index aa1d082e..7250cec7 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -54,26 +54,8 @@ namespace xo { static std::string_view get_expect_str(const DExpectExprSsm & self) noexcept; // non-const methods - /** operate state machine for incoming symbol-token @p tk **/ - static void on_symbol_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming define-keyword-token @p tk **/ - static void on_def_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming if-keyword-token @p tk **/ - static void on_if_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming colon-token @p tk **/ - static void on_colon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming singleassign-token @p tk **/ - static void on_singleassign_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming f64-token @p tk **/ - static void on_f64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming i64-token @p tk **/ - static void on_i64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming bool-token @p tk **/ - static void on_bool_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming string-token @p tk **/ - static void on_string_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming semicolon-token @p tk **/ - static void on_semicolon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectExprSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 039fcae2..7e83d0e4 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -54,26 +54,8 @@ namespace xo { static std::string_view get_expect_str(const DExpectSymbolSsm & self) noexcept; // non-const methods - /** operate state machine for incoming symbol-token @p tk **/ - static void on_symbol_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming define-keyword-token @p tk **/ - static void on_def_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming if-keyword-token @p tk **/ - static void on_if_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming colon-token @p tk **/ - static void on_colon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming singleassign-token @p tk **/ - static void on_singleassign_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming f64-token @p tk **/ - static void on_f64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming i64-token @p tk **/ - static void on_i64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming bool-token @p tk **/ - static void on_bool_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming string-token @p tk **/ - static void on_string_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming semicolon-token @p tk **/ - static void on_semicolon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index 64106cfb..c8c4cc9f 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -54,26 +54,8 @@ namespace xo { static std::string_view get_expect_str(const DExpectTypeSsm & self) noexcept; // non-const methods - /** operate state machine for incoming symbol-token @p tk **/ - static void on_symbol_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming define-keyword-token @p tk **/ - static void on_def_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming if-keyword-token @p tk **/ - static void on_if_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming colon-token @p tk **/ - static void on_colon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming singleassign-token @p tk **/ - static void on_singleassign_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming f64-token @p tk **/ - static void on_f64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming i64-token @p tk **/ - static void on_i64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming bool-token @p tk **/ - static void on_bool_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming string-token @p tk **/ - static void on_string_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming semicolon-token @p tk **/ - static void on_semicolon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index fbf1f317..2a86db05 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -54,26 +54,8 @@ namespace xo { static std::string_view get_expect_str(const DExprSeqState & self) noexcept; // non-const methods - /** operate state machine for incoming symbol-token @p tk **/ - static void on_symbol_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming define-keyword-token @p tk **/ - static void on_def_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming if-keyword-token @p tk **/ - static void on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming colon-token @p tk **/ - static void on_colon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming singleassign-token @p tk **/ - static void on_singleassign_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming f64-token @p tk **/ - static void on_f64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming i64-token @p tk **/ - static void on_i64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming bool-token @p tk **/ - static void on_bool_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming string-token @p tk **/ - static void on_string_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming semicolon-token @p tk **/ - static void on_semicolon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); + /** operate state machine for incoming token @p tk **/ + static void on_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 0277e1ba..3d70afed 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -54,26 +54,8 @@ namespace xo { static std::string_view get_expect_str(const DProgressSsm & self) noexcept; // non-const methods - /** operate state machine for incoming symbol-token @p tk **/ - static void on_symbol_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming define-keyword-token @p tk **/ - static void on_def_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming if-keyword-token @p tk **/ - static void on_if_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming colon-token @p tk **/ - static void on_colon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming singleassign-token @p tk **/ - static void on_singleassign_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming f64-token @p tk **/ - static void on_f64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming i64-token @p tk **/ - static void on_i64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming bool-token @p tk **/ - static void on_bool_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming string-token @p tk **/ - static void on_string_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for incoming semicolon-token @p tk **/ - static void on_semicolon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** operate state machine for incoming token @p tk **/ + static void on_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ static void on_parsed_symbol(DProgressSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index fccd523e..36c2ff83 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -52,35 +52,8 @@ namespace scm { } // non-const methods - void on_symbol_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { - return I::on_symbol_token(_dcast(data), tk, p_psm); - } - void on_def_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { - return I::on_def_token(_dcast(data), tk, p_psm); - } - void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { - return I::on_if_token(_dcast(data), tk, p_psm); - } - void on_colon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { - return I::on_colon_token(_dcast(data), tk, p_psm); - } - void on_singleassign_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { - return I::on_singleassign_token(_dcast(data), tk, p_psm); - } - void on_f64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { - return I::on_f64_token(_dcast(data), tk, p_psm); - } - void on_i64_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { - return I::on_i64_token(_dcast(data), tk, p_psm); - } - void on_bool_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { - return I::on_bool_token(_dcast(data), tk, p_psm); - } - void on_string_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { - return I::on_string_token(_dcast(data), tk, p_psm); - } - void on_semicolon_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { - return I::on_semicolon_token(_dcast(data), tk, p_psm); + void on_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_token(_dcast(data), tk, p_psm); } void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) override { return I::on_parsed_symbol(_dcast(data), sym, p_psm); diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index b91381d0..fb1fb496 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -56,35 +56,8 @@ public: } // non-const methods (still const in router!) - void on_symbol_token(const Token & tk, ParserStateMachine * p_psm) { - return O::iface()->on_symbol_token(O::data(), tk, p_psm); - } - void on_def_token(const Token & tk, ParserStateMachine * p_psm) { - return O::iface()->on_def_token(O::data(), tk, p_psm); - } - void on_if_token(const Token & tk, ParserStateMachine * p_psm) { - return O::iface()->on_if_token(O::data(), tk, p_psm); - } - void on_colon_token(const Token & tk, ParserStateMachine * p_psm) { - return O::iface()->on_colon_token(O::data(), tk, p_psm); - } - void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm) { - return O::iface()->on_singleassign_token(O::data(), tk, p_psm); - } - void on_f64_token(const Token & tk, ParserStateMachine * p_psm) { - return O::iface()->on_f64_token(O::data(), tk, p_psm); - } - void on_i64_token(const Token & tk, ParserStateMachine * p_psm) { - return O::iface()->on_i64_token(O::data(), tk, p_psm); - } - void on_bool_token(const Token & tk, ParserStateMachine * p_psm) { - return O::iface()->on_bool_token(O::data(), tk, p_psm); - } - void on_string_token(const Token & tk, ParserStateMachine * p_psm) { - return O::iface()->on_string_token(O::data(), tk, p_psm); - } - void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm) { - return O::iface()->on_semicolon_token(O::data(), tk, p_psm); + void on_token(const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_token(O::data(), tk, p_psm); } void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { return O::iface()->on_parsed_symbol(O::data(), sym, p_psm); diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 0f4ac7e1..b8c5b0ae 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -369,7 +369,9 @@ namespace xo { = with_facet::mkobj(define_ssm); p_psm->push_ssm(ssm); - p_psm->on_def_token(Token::def_token()); + + // note: triggers poly dispatch + p_psm->on_token(Token::def_token()); } syntaxstatetype @@ -489,6 +491,92 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); + + switch (tk.tk_type()) { + case tokentype::tk_symbol: + this->on_symbol_token(tk, p_psm); + break; + + case tokentype::tk_def: + this->on_def_token(tk, p_psm); + break; + + case tokentype::tk_if: + this->on_if_token(tk, p_psm); + break; + + case tokentype::tk_colon: + this->on_colon_token(tk, p_psm); + break; + + case tokentype::tk_singleassign: + this->on_singleassign_token(tk, p_psm); + break; + + case tokentype::tk_string: + this->on_string_token(tk, p_psm); + break; + + case tokentype::tk_f64: + this->on_f64_token(tk, p_psm); + break; + + case tokentype::tk_i64: + this->on_i64_token(tk, p_psm); + break; + + case tokentype::tk_bool: + this->on_bool_token(tk, p_psm); + break; + + case tokentype::tk_semicolon: + this->on_semicolon_token(tk, p_psm); + break; + + // all the not-yet handled cases + case tokentype::tk_invalid: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + p_psm->illegal_input_on_token("DDefineSsm::on_token", + tk, + this->get_expect_str()); + } + void DDefineSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index a5d46052..fc5dbe08 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -102,6 +102,92 @@ namespace xo { } } + void + DExpectExprSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); + + switch (tk.tk_type()) { + case tokentype::tk_symbol: + this->on_symbol_token(tk, p_psm); + break; + + case tokentype::tk_def: + this->on_def_token(tk, p_psm); + break; + + case tokentype::tk_if: + this->on_if_token(tk, p_psm); + break; + + case tokentype::tk_colon: + this->on_colon_token(tk, p_psm); + break; + + case tokentype::tk_singleassign: + this->on_singleassign_token(tk, p_psm); + break; + + case tokentype::tk_string: + this->on_string_token(tk, p_psm); + break; + + case tokentype::tk_f64: + this->on_f64_token(tk, p_psm); + break; + + case tokentype::tk_i64: + this->on_i64_token(tk, p_psm); + break; + + case tokentype::tk_bool: + this->on_bool_token(tk, p_psm); + break; + + case tokentype::tk_semicolon: + this->on_semicolon_token(tk, p_psm); + break; + + // all the not-yet handled cases + case tokentype::tk_invalid: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + p_psm->illegal_input_on_token("DExpectExprSsm::on_token", + tk, + this->get_expect_str()); + } + void DExpectExprSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index d41f08da..cbfb1c91 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -92,6 +92,92 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); + + switch (tk.tk_type()) { + case tokentype::tk_symbol: + this->on_symbol_token(tk, p_psm); + break; + + case tokentype::tk_def: + this->on_def_token(tk, p_psm); + break; + + case tokentype::tk_if: + this->on_if_token(tk, p_psm); + break; + + case tokentype::tk_colon: + this->on_colon_token(tk, p_psm); + break; + + case tokentype::tk_singleassign: + this->on_singleassign_token(tk, p_psm); + break; + + case tokentype::tk_string: + this->on_string_token(tk, p_psm); + break; + + case tokentype::tk_f64: + this->on_f64_token(tk, p_psm); + break; + + case tokentype::tk_i64: + this->on_i64_token(tk, p_psm); + break; + + case tokentype::tk_bool: + this->on_bool_token(tk, p_psm); + break; + + case tokentype::tk_semicolon: + this->on_semicolon_token(tk, p_psm); + break; + + // all the not-yet handled cases + case tokentype::tk_invalid: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + p_psm->illegal_input_on_token("DExpectSymbolSsm::on_token", + tk, + this->get_expect_str()); + } + void DExpectSymbolSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index b8be164c..2feaee26 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -56,6 +56,92 @@ namespace xo { return "typename"; } + void + DExpectTypeSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); + + switch (tk.tk_type()) { + case tokentype::tk_symbol: + this->on_symbol_token(tk, p_psm); + break; + + case tokentype::tk_def: + this->on_def_token(tk, p_psm); + break; + + case tokentype::tk_if: + this->on_if_token(tk, p_psm); + break; + + case tokentype::tk_colon: + this->on_colon_token(tk, p_psm); + break; + + case tokentype::tk_singleassign: + this->on_singleassign_token(tk, p_psm); + break; + + case tokentype::tk_string: + this->on_string_token(tk, p_psm); + break; + + case tokentype::tk_f64: + this->on_f64_token(tk, p_psm); + break; + + case tokentype::tk_i64: + this->on_i64_token(tk, p_psm); + break; + + case tokentype::tk_bool: + this->on_bool_token(tk, p_psm); + break; + + case tokentype::tk_semicolon: + this->on_semicolon_token(tk, p_psm); + break; + + // all the not-yet handled cases + case tokentype::tk_invalid: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + p_psm->illegal_input_on_token("DExpectTypeSsm::on_token", + tk, + this->get_expect_str()); + } + void DExpectTypeSsm::on_def_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 90b9824b..9691d665 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -105,6 +105,92 @@ namespace xo { return "impossible-DExprSeqState::get_expr_str"; } + void + DExprSeqState::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); + + switch (tk.tk_type()) { + case tokentype::tk_symbol: + this->on_symbol_token(tk, p_psm); + break; + + case tokentype::tk_def: + this->on_def_token(tk, p_psm); + break; + + case tokentype::tk_if: + this->on_if_token(tk, p_psm); + break; + + case tokentype::tk_colon: + this->on_colon_token(tk, p_psm); + break; + + case tokentype::tk_singleassign: + this->on_singleassign_token(tk, p_psm); + break; + + case tokentype::tk_string: + this->on_string_token(tk, p_psm); + break; + + case tokentype::tk_f64: + this->on_f64_token(tk, p_psm); + break; + + case tokentype::tk_i64: + this->on_i64_token(tk, p_psm); + break; + + case tokentype::tk_bool: + this->on_bool_token(tk, p_psm); + break; + + case tokentype::tk_semicolon: + this->on_semicolon_token(tk, p_psm); + break; + + // all the not-yet handled cases + case tokentype::tk_invalid: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + p_psm->illegal_input_on_token("DExprSeqState::on_token", + tk, + this->get_expect_str()); + } + void DExprSeqState::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 50ec2fbe..a40b6f59 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -158,6 +158,92 @@ namespace xo { } } + void + DProgressSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); + + switch (tk.tk_type()) { + case tokentype::tk_symbol: + this->on_symbol_token(tk, p_psm); + break; + + case tokentype::tk_def: + this->on_def_token(tk, p_psm); + break; + + case tokentype::tk_if: + this->on_if_token(tk, p_psm); + break; + + case tokentype::tk_colon: + this->on_colon_token(tk, p_psm); + break; + + case tokentype::tk_singleassign: + this->on_singleassign_token(tk, p_psm); + break; + + case tokentype::tk_string: + this->on_string_token(tk, p_psm); + break; + + case tokentype::tk_f64: + this->on_f64_token(tk, p_psm); + break; + + case tokentype::tk_i64: + this->on_i64_token(tk, p_psm); + break; + + case tokentype::tk_bool: + this->on_bool_token(tk, p_psm); + break; + + case tokentype::tk_semicolon: + this->on_semicolon_token(tk, p_psm); + break; + + // all the not-yet handled cases + case tokentype::tk_invalid: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + p_psm->illegal_input_on_token("DProgressSsm::on_token", + tk, + this->get_expect_str()); + } + void DProgressSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index f270c352..4cfb72a7 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -35,61 +35,7 @@ ISyntaxStateMachine_Any::_valid // nonconst methods auto -ISyntaxStateMachine_Any::on_symbol_token(Opaque, const Token &, ParserStateMachine *) -> void -{ - _fatal(); -} - -auto -ISyntaxStateMachine_Any::on_def_token(Opaque, const Token &, ParserStateMachine *) -> void -{ - _fatal(); -} - -auto -ISyntaxStateMachine_Any::on_if_token(Opaque, const Token &, ParserStateMachine *) -> void -{ - _fatal(); -} - -auto -ISyntaxStateMachine_Any::on_colon_token(Opaque, const Token &, ParserStateMachine *) -> void -{ - _fatal(); -} - -auto -ISyntaxStateMachine_Any::on_singleassign_token(Opaque, const Token &, ParserStateMachine *) -> void -{ - _fatal(); -} - -auto -ISyntaxStateMachine_Any::on_f64_token(Opaque, const Token &, ParserStateMachine *) -> void -{ - _fatal(); -} - -auto -ISyntaxStateMachine_Any::on_i64_token(Opaque, const Token &, ParserStateMachine *) -> void -{ - _fatal(); -} - -auto -ISyntaxStateMachine_Any::on_bool_token(Opaque, const Token &, ParserStateMachine *) -> void -{ - _fatal(); -} - -auto -ISyntaxStateMachine_Any::on_string_token(Opaque, const Token &, ParserStateMachine *) -> void -{ - _fatal(); -} - -auto -ISyntaxStateMachine_Any::on_semicolon_token(Opaque, const Token &, ParserStateMachine *) -> void +ISyntaxStateMachine_Any::on_token(Opaque, const Token &, ParserStateMachine *) -> void { _fatal(); } diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index c39c51b2..85c2a8f0 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -28,54 +28,9 @@ namespace xo { } auto - ISyntaxStateMachine_DDefineSsm::on_symbol_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DDefineSsm::on_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_symbol_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_def_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_def_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_if_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_if_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_colon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_colon_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_singleassign_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_singleassign_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_f64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_f64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_i64_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_i64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_bool_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_bool_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_string_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_string_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_semicolon_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_semicolon_token(tk, p_psm); + self.on_token(tk, p_psm); } auto ISyntaxStateMachine_DDefineSsm::on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index 0e5efa5d..e545eedd 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -28,54 +28,9 @@ namespace xo { } auto - ISyntaxStateMachine_DExpectExprSsm::on_symbol_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExpectExprSsm::on_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_symbol_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectExprSsm::on_def_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_def_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectExprSsm::on_if_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_if_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectExprSsm::on_colon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_colon_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectExprSsm::on_singleassign_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_singleassign_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectExprSsm::on_f64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_f64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectExprSsm::on_i64_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_i64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectExprSsm::on_bool_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_bool_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectExprSsm::on_string_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_string_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectExprSsm::on_semicolon_token(DExpectExprSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_semicolon_token(tk, p_psm); + self.on_token(tk, p_psm); } auto ISyntaxStateMachine_DExpectExprSsm::on_parsed_symbol(DExpectExprSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 0b47c31a..0a35bb71 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -28,54 +28,9 @@ namespace xo { } auto - ISyntaxStateMachine_DExpectSymbolSsm::on_symbol_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExpectSymbolSsm::on_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_symbol_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectSymbolSsm::on_def_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_def_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectSymbolSsm::on_if_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_if_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectSymbolSsm::on_colon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_colon_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectSymbolSsm::on_singleassign_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_singleassign_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectSymbolSsm::on_f64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_f64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectSymbolSsm::on_i64_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_i64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectSymbolSsm::on_bool_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_bool_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectSymbolSsm::on_string_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_string_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectSymbolSsm::on_semicolon_token(DExpectSymbolSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_semicolon_token(tk, p_psm); + self.on_token(tk, p_psm); } auto ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 515b81a8..4b6950ab 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -28,54 +28,9 @@ namespace xo { } auto - ISyntaxStateMachine_DExpectTypeSsm::on_symbol_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExpectTypeSsm::on_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_symbol_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectTypeSsm::on_def_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_def_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectTypeSsm::on_if_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_if_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectTypeSsm::on_colon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_colon_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectTypeSsm::on_singleassign_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_singleassign_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectTypeSsm::on_f64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_f64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectTypeSsm::on_i64_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_i64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectTypeSsm::on_bool_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_bool_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectTypeSsm::on_string_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_string_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExpectTypeSsm::on_semicolon_token(DExpectTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_semicolon_token(tk, p_psm); + self.on_token(tk, p_psm); } auto ISyntaxStateMachine_DExpectTypeSsm::on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index 04cc4516..af5d3cc9 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -28,54 +28,9 @@ namespace xo { } auto - ISyntaxStateMachine_DExprSeqState::on_symbol_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExprSeqState::on_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_symbol_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_def_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_def_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_if_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_colon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_colon_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_singleassign_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_singleassign_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_f64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_f64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_i64_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_i64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_bool_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_bool_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_string_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_string_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_semicolon_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_semicolon_token(tk, p_psm); + self.on_token(tk, p_psm); } auto ISyntaxStateMachine_DExprSeqState::on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm) -> void diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 28b69cfb..1fdd6c90 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -28,54 +28,9 @@ namespace xo { } auto - ISyntaxStateMachine_DProgressSsm::on_symbol_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DProgressSsm::on_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_symbol_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DProgressSsm::on_def_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_def_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DProgressSsm::on_if_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_if_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DProgressSsm::on_colon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_colon_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DProgressSsm::on_singleassign_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_singleassign_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DProgressSsm::on_f64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_f64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DProgressSsm::on_i64_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_i64_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DProgressSsm::on_bool_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_bool_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DProgressSsm::on_string_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_string_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DProgressSsm::on_semicolon_token(DProgressSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_semicolon_token(tk, p_psm); + self.on_token(tk, p_psm); } auto ISyntaxStateMachine_DProgressSsm::on_parsed_symbol(DProgressSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index adc14f1b..2d9e4970 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -162,163 +162,7 @@ namespace xo { )); } - switch (tk.tk_type()) { - case tokentype::tk_symbol: - this->on_symbol_token(tk); - break; - - case tokentype::tk_def: - this->on_def_token(tk); - break; - - case tokentype::tk_if: - this->on_if_token(tk); - break; - - case tokentype::tk_colon: - this->on_colon_token(tk); - break; - - case tokentype::tk_singleassign: - this->on_singleassign_token(tk); - break; - - case tokentype::tk_string: - this->on_string_token(tk); - break; - - case tokentype::tk_f64: - this->on_f64_token(tk); - break; - - case tokentype::tk_i64: - this->on_i64_token(tk); - break; - - case tokentype::tk_bool: - this->on_bool_token(tk); - break; - - case tokentype::tk_semicolon: - this->on_semicolon_token(tk); - break; - - // all the not-yet handled cases - case tokentype::tk_invalid: - case tokentype::tk_leftparen: - case tokentype::tk_rightparen: - case tokentype::tk_leftbracket: - case tokentype::tk_rightbracket: - case tokentype::tk_leftbrace: - case tokentype::tk_rightbrace: - case tokentype::tk_leftangle: - case tokentype::tk_rightangle: - case tokentype::tk_lessequal: - case tokentype::tk_greatequal: - case tokentype::tk_dot: - case tokentype::tk_comma: - case tokentype::tk_doublecolon: - case tokentype::tk_assign: - case tokentype::tk_yields: - case tokentype::tk_plus: - case tokentype::tk_minus: - case tokentype::tk_star: - case tokentype::tk_slash: - case tokentype::tk_cmpeq: - case tokentype::tk_cmpne: - case tokentype::tk_type: - case tokentype::tk_lambda: - case tokentype::tk_then: - case tokentype::tk_else: - case tokentype::tk_let: - case tokentype::tk_in: - case tokentype::tk_end: - case tokentype::N: - throw std::runtime_error(tostr("ParserStateMachin::on_token:", - "NOT IMPLEMENTED", - xtag("token", tk))); - - } - } - - void - ParserStateMachine::on_symbol_token(const Token & tk) - { - scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); - - stack_->top().on_symbol_token(tk, this); - } - - void - ParserStateMachine::on_def_token(const Token & tk) - { - scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); - - stack_->top().on_def_token(tk, this); - } - - void - ParserStateMachine::on_if_token(const Token & tk) - { - scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); - - stack_->top().on_if_token(tk, this); - } - - void - ParserStateMachine::on_colon_token(const Token & tk) - { - scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); - - stack_->top().on_colon_token(tk, this); - } - - void - ParserStateMachine::on_singleassign_token(const Token & tk) - { - scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); - - stack_->top().on_singleassign_token(tk, this); - } - - void - ParserStateMachine::on_string_token(const Token & tk) - { - scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); - - stack_->top().on_string_token(tk, this); - } - - void - ParserStateMachine::on_f64_token(const Token & tk) - { - scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); - - stack_->top().on_f64_token(tk, this); - } - - void - ParserStateMachine::on_i64_token(const Token & tk) - { - scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); - - stack_->top().on_i64_token(tk, this); - } - - void - ParserStateMachine::on_bool_token(const Token & tk) - { - scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); - - stack_->top().on_bool_token(tk, this); - } - - void - ParserStateMachine::on_semicolon_token(const Token & tk) - { - scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); - - stack_->top().on_semicolon_token(tk, this); + stack_->top().on_token(tk, this); } void From 4b4c69cfed439b9e30e2ebf6c10accdce3c9cf22 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 25 Jan 2026 10:47:28 -0500 Subject: [PATCH 127/342] xo-reader2: bugfix: prior refactor requires switch remodel on_token --- src/reader2/DDefineSsm.cpp | 29 ++++++++++++++--------------- src/reader2/DExpectSymbolSsm.cpp | 6 +++--- src/reader2/DExpectTypeSsm.cpp | 7 +++---- src/reader2/DExprSeqState.cpp | 20 ++++++++++---------- src/reader2/DProgressSsm.cpp | 23 +++++++++++++---------- 5 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index b8c5b0ae..0cd488e5 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -500,43 +500,43 @@ namespace xo { switch (tk.tk_type()) { case tokentype::tk_symbol: this->on_symbol_token(tk, p_psm); - break; + return; case tokentype::tk_def: this->on_def_token(tk, p_psm); - break; + return; case tokentype::tk_if: this->on_if_token(tk, p_psm); - break; + return; case tokentype::tk_colon: this->on_colon_token(tk, p_psm); - break; + return; case tokentype::tk_singleassign: this->on_singleassign_token(tk, p_psm); - break; + return; case tokentype::tk_string: this->on_string_token(tk, p_psm); - break; + return; case tokentype::tk_f64: this->on_f64_token(tk, p_psm); - break; + return; case tokentype::tk_i64: this->on_i64_token(tk, p_psm); - break; + return; case tokentype::tk_bool: this->on_bool_token(tk, p_psm); - break; + return; case tokentype::tk_semicolon: this->on_semicolon_token(tk, p_psm); - break; + return; // all the not-yet handled cases case tokentype::tk_invalid: @@ -569,12 +569,11 @@ namespace xo { case tokentype::tk_in: case tokentype::tk_end: case tokentype::N: - break; + p_psm->illegal_input_on_token("DDefineSsm::on_token", + tk, + this->get_expect_str()); + return; } - - p_psm->illegal_input_on_token("DDefineSsm::on_token", - tk, - this->get_expect_str()); } void diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index cbfb1c91..c10678f2 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -170,12 +170,12 @@ namespace xo { case tokentype::tk_in: case tokentype::tk_end: case tokentype::N: + p_psm->illegal_input_on_token("DExpectSymbolSsm::on_token", + tk, + this->get_expect_str()); break; } - p_psm->illegal_input_on_token("DExpectSymbolSsm::on_token", - tk, - this->get_expect_str()); } void diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 2feaee26..d99ff817 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -134,12 +134,11 @@ namespace xo { case tokentype::tk_in: case tokentype::tk_end: case tokentype::N: + p_psm->illegal_input_on_token("DExpectTypeSsm::on_token", + tk, + this->get_expect_str()); break; } - - p_psm->illegal_input_on_token("DExpectTypeSsm::on_token", - tk, - this->get_expect_str()); } void diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 9691d665..d6037908 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -114,43 +114,43 @@ namespace xo { switch (tk.tk_type()) { case tokentype::tk_symbol: this->on_symbol_token(tk, p_psm); - break; + return; case tokentype::tk_def: this->on_def_token(tk, p_psm); - break; + return; case tokentype::tk_if: this->on_if_token(tk, p_psm); - break; + return; case tokentype::tk_colon: this->on_colon_token(tk, p_psm); - break; + return; case tokentype::tk_singleassign: this->on_singleassign_token(tk, p_psm); - break; + return; case tokentype::tk_string: this->on_string_token(tk, p_psm); - break; + return; case tokentype::tk_f64: this->on_f64_token(tk, p_psm); - break; + return; case tokentype::tk_i64: this->on_i64_token(tk, p_psm); - break; + return; case tokentype::tk_bool: this->on_bool_token(tk, p_psm); - break; + return; case tokentype::tk_semicolon: this->on_semicolon_token(tk, p_psm); - break; + return; // all the not-yet handled cases case tokentype::tk_invalid: diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index a40b6f59..f501d5fe 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -167,43 +167,43 @@ namespace xo { switch (tk.tk_type()) { case tokentype::tk_symbol: this->on_symbol_token(tk, p_psm); - break; + return; case tokentype::tk_def: this->on_def_token(tk, p_psm); - break; + return; case tokentype::tk_if: this->on_if_token(tk, p_psm); - break; + return; case tokentype::tk_colon: this->on_colon_token(tk, p_psm); - break; + return; case tokentype::tk_singleassign: this->on_singleassign_token(tk, p_psm); - break; + return; case tokentype::tk_string: this->on_string_token(tk, p_psm); - break; + return; case tokentype::tk_f64: this->on_f64_token(tk, p_psm); - break; + return; case tokentype::tk_i64: this->on_i64_token(tk, p_psm); - break; + return; case tokentype::tk_bool: this->on_bool_token(tk, p_psm); - break; + return; case tokentype::tk_semicolon: this->on_semicolon_token(tk, p_psm); - break; + return; // all the not-yet handled cases case tokentype::tk_invalid: @@ -224,7 +224,10 @@ namespace xo { case tokentype::tk_yields: case tokentype::tk_plus: case tokentype::tk_minus: + break; case tokentype::tk_star: + this->on_operator_token(tk, p_psm); + return; case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: From e283ee0126b6fddfbb029e2d91b21b1ea5aad135 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 26 Jan 2026 12:38:17 -0500 Subject: [PATCH 128/342] xo-procedure2 xo-object2: + polymorphic primitive support --- src/reader2/DProgressSsm.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index f501d5fe..85f7b1d3 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -226,8 +226,11 @@ namespace xo { case tokentype::tk_minus: break; case tokentype::tk_star: +#ifdef NOT_YET this->on_operator_token(tk, p_psm); return; +#endif + break; case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: From c69ce58e15c0f19db24db7e22b64c9826157a25e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 26 Jan 2026 13:42:42 -0500 Subject: [PATCH 129/342] xo-expression2 xo-procedure2: work on calling primitive for x*y --- include/xo/reader2/DProgressSsm.hpp | 32 ++-- src/reader2/DExpectExprSsm.cpp | 7 +- src/reader2/DProgressSsm.cpp | 262 +++++++++++++++------------- 3 files changed, 162 insertions(+), 139 deletions(-) diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 7258731c..31b3a55d 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -100,14 +100,12 @@ namespace xo { optype op); static void start(DArena & parser_mm, - obj valex, + obj lhs, ParserStateMachine * p_psm); - -#ifdef NOT_YET - static void start(rp valex, + static void start(DArena & parsermm, + obj lhs, optype optype, - parserstatemachine * p_psm); -#endif + ParserStateMachine * p_psm); syntaxstatetype ssm_type() const noexcept; @@ -147,6 +145,8 @@ namespace xo { ParserStateMachine * p_psm); void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + void on_operator_token(const Token & tk, + ParserStateMachine * p_psm); void on_string_token(const Token & tk, ParserStateMachine * p_psm); void on_f64_token(const Token & tk, @@ -207,17 +207,6 @@ namespace xo { void print(std::ostream & os) const override; - - private: - /** assemble expression representing - * value of - * @code - * f(lhs_, rhs_) - * @endcode - * - * where f determined by @ref op_type_ - **/ - obj assemble_expr(ParserStateMachine * p_psm); #endif private: @@ -227,7 +216,14 @@ namespace xo { /** infix operator, if supplied **/ optype op_type_ = optype::invalid; - /** populate an expression here, following infix operator */ + /** populate an expression here, that follows an infix operator. + * + * Note this may not resolve immediately. + * Consider input + * 5 + 6 + * Need to know if following token is * + * before deciding if 6 belongs to addition 5 + 6 + **/ obj rhs_; }; } /*namespace scm*/ diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index fc5dbe08..49e95296 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -180,12 +180,11 @@ namespace xo { case tokentype::tk_in: case tokentype::tk_end: case tokentype::N: + p_psm->illegal_input_on_token("DExpectExprSsm::on_token", + tk, + this->get_expect_str()); break; } - - p_psm->illegal_input_on_token("DExpectExprSsm::on_token", - tk, - this->get_expect_str()); } void diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 85f7b1d3..830dd30e 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -5,6 +5,15 @@ #include "DProgressSsm.hpp" #include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" + +#include "DExpectExprSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" + +#ifdef NOT_YET +#include "DApplySsm.hpp" +#include "ssm/ISyntaxStateMachine_DApplySsm.hpp" +#endif + #include #include #include @@ -67,6 +76,7 @@ namespace xo { return "???"; } + /** higher-precedence operators bind before lower-preference operators **/ int precedence(optype x) { switch (x) { @@ -97,6 +107,40 @@ namespace xo { return 0; } + namespace { + optype + tk2op(const tokentype & tktype) { + switch (tktype) { + case tokentype::tk_assign: + return optype::op_assign; + case tokentype::tk_plus: + return optype::op_add; + case tokentype::tk_minus: + return optype::op_subtract; + case tokentype::tk_star: + return optype::op_multiply; + case tokentype::tk_slash: + return optype::op_divide; + case tokentype::tk_cmpeq: + return optype::op_equal; + case tokentype::tk_cmpne: + return optype::op_not_equal; + case tokentype::tk_leftangle: + return optype::op_less; + case tokentype::tk_lessequal: + return optype::op_less_equal; + case tokentype::tk_rightangle: + return optype::op_great; + case tokentype::tk_greatequal: + return optype::op_great_equal; + default: + assert(false); + return optype::invalid; + } + return optype::invalid; + } + } + DProgressSsm * DProgressSsm::make(DArena & mm, obj lhs, @@ -112,26 +156,26 @@ namespace xo { void DProgressSsm::start(DArena & parser_mm, - obj valex, + obj lhs, + optype op, ParserStateMachine * p_psm) { DProgressSsm * progress_ssm - = DProgressSsm::make(parser_mm, valex, optype::invalid); + = DProgressSsm::make(parser_mm, lhs, op); - obj ssm - = with_facet::mkobj(progress_ssm); + obj ssm(progress_ssm); p_psm->push_ssm(ssm); } -#ifdef NOT_YET void - progress_xs::start(rp valex, optype op, parserstatemachine * p_psm) { - p_psm->push_exprstate(progress_xs::make(valex, op)); + DProgressSsm::start(DArena & parser_mm, + obj lhs, + ParserStateMachine * p_psm) + { + start(parser_mm, lhs, optype::invalid, p_psm); } -#endif - DProgressSsm::DProgressSsm(obj valex, optype op) : lhs_{valex}, @@ -225,12 +269,11 @@ namespace xo { case tokentype::tk_plus: case tokentype::tk_minus: break; + case tokentype::tk_star: -#ifdef NOT_YET this->on_operator_token(tk, p_psm); return; -#endif - break; + case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: @@ -295,6 +338,75 @@ namespace xo { this->get_expect_str()); } + void + DProgressSsm::on_operator_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (op_type_ == optype::invalid) { + // tk is the operator this instance was waiting for + this->op_type_ = tk2op(tk.tk_type()); + + DExpectExprSsm::start(p_psm->parser_alloc(), p_psm); + return; + } else if (rhs_) { + optype op_type2 = tk2op(tk.tk_type()); + + /* already have {lhs_, op_type_, rhs_}, + * with incoming op_type2 operator decides whether to parse like + * (lhs_, op_type_, rhs_) op_type2 ... + * or + * (lhs_, op_type_, (rhs_ op_type2 ...)) + */ + + if (precedence(op_type_) >= precedence(op_type2)) { + /* associate to the left + * + * parse like + * a + b - ... (a + b) - ... + * a * b - ... (a * b) - ... + */ + + auto lhs2 = this->assemble_expr(p_psm); + + p_psm->pop_ssm(); + + DProgressSsm::start(p_psm->parser_alloc(), + lhs2, + op_type2, + p_psm); + return; + } else { + /* associate to the right + * + * parse like + * a + b * ... (a + (b * ...)) + */ + + p_psm->pop_ssm(); + + /* (a + ..) */ + DProgressSsm::start(p_psm->parser_alloc(), + lhs_, + op_type_, + p_psm); + DExpectExprSsm::start(p_psm->parser_alloc(), + p_psm); + /* (b * ..) */ + DProgressSsm::start(p_psm->parser_alloc(), + rhs_, + op_type2, + p_psm); + DExpectExprSsm::start(p_psm->parser_alloc(), + p_psm); + return; + } + } + + p_psm->illegal_input_on_token("DProgressSsm::on_operator_token", + tk, + this->get_expect_str()); + } + void DProgressSsm::on_string_token(const Token & tk, ParserStateMachine * p_psm) @@ -905,112 +1017,10 @@ namespace xo { * { n * n } */ } +#endif - namespace { - optype - tk2op(const tokentype & tktype) { - switch (tktype) { - case tokentype::tk_assign: - return optype::op_assign; - case tokentype::tk_plus: - return optype::op_add; - case tokentype::tk_minus: - return optype::op_subtract; - case tokentype::tk_star: - return optype::op_multiply; - case tokentype::tk_slash: - return optype::op_divide; - case tokentype::tk_cmpeq: - return optype::op_equal; - case tokentype::tk_cmpne: - return optype::op_not_equal; - case tokentype::tk_leftangle: - return optype::op_less; - case tokentype::tk_lessequal: - return optype::op_less_equal; - case tokentype::tk_rightangle: - return optype::op_great; - case tokentype::tk_greatequal: - return optype::op_great_equal; - default: - assert(false); - return optype::invalid; - } - return optype::invalid; - } - } - - void - progress_xs::on_operator_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - constexpr const char * c_self_name = "progress_xs::on_operator_token"; - - if (op_type_ == optype::invalid) { - this->op_type_ = tk2op(tk.tk_type()); - - /* infix operator must be followed by non-empty expression */ - expect_expr_xs::start(p_psm); - } else if (rhs_) { - /* already have complete expression stashed. - * behavior depends on operator precedence for tk with stored operator - * this->op_type_ - */ - optype op2 = tk2op(tk.tk_type()); - - if (precedence(op2) <= precedence(this->op_type_)) { - /* e.g. - * 6.2 * 4.9 + ... - * - * in stack: - * 1. progress_xs lhs=6.2, op=*, rhs=4.9 - * - * out stack - * 1. progress_xs lhs=apply(*,6.2,4.9), op=+ - */ - - /* 1. instantiate expression for *this */ - auto expr = this->assemble_expr(p_psm); - - /* 2. remove from stack */ - std::unique_ptr self = p_psm->pop_exprstate(); - - /* 3. replace with new progress_xs: */ - progress_xs::start(expr, op2, p_psm); - - /* infix operator must be followed by non-empty expression */ - expect_expr_xs::start(p_psm); - } else { - /* e.g. - * 6.2 + 4.9 * ... - * - * in stack: - * 1. progress_xs lhs=6.2, op=+, rhs=4.9 - * - * out stack: - * 1. progress_xs lhs=6.2, op=+ - * 2. expect_rhs_expression - * 3. progress_xs lhs=4.9, op=* - * 4. expect_rhs_expression - */ - - std::unique_ptr self = p_psm->pop_exprstate(); - - /* 1. replace with nested incomplete infix exprs */ - progress_xs::start(lhs_, op_type_, p_psm); - expect_expr_xs::start(p_psm); - progress_xs::start(rhs_, op2, p_psm); - expect_expr_xs::start(p_psm); - } - - } else { - throw std::runtime_error(tostr(c_self_name, - ": expected expression following operator", - xtag("tk", tk))); - } - } +#ifdef OBSOLETE + //void progress_xs::on_operator_token(const token_type & tk, parserstatemachine * p_psm) void progress_xs::on_bool_token(const token_type & tk, @@ -1163,7 +1173,25 @@ namespace xo { case optype::op_great_equal: case optype::op_add: case optype::op_subtract: + break; + case optype::op_multiply: +#ifdef NOT_YET + { + /* note: + * 1. don't assume we know lhs_ / rhs_ value types yet. + * perhaps have expression like + * f(..) * g(..) + * where f is the function that contains current ssm. + * 2. consequence: we need representation for + * polymorphic multiply on unknown numeric arguments. + */ + + DApplyExpr::make2(); + } +#endif + + break; case optype::op_divide: // TODO: implement binary operator expression assembly break; From 6b2ad521f3ae01c7d842c1c5f2c2d330c3b16876 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 26 Jan 2026 15:33:58 -0500 Subject: [PATCH 130/342] xo-expression2: + DConstant utest --- src/reader2/DExpectExprSsm.cpp | 2 +- src/reader2/DExprSeqState.cpp | 12 ++++-------- src/reader2/DProgressSsm.cpp | 3 +++ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 49e95296..66eb41cd 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -248,7 +248,7 @@ namespace xo { auto f64o = DFloat::box(p_psm->expr_alloc(), tk.f64_value()); - auto expr = with_facet::mkobj(DConstant::make(p_psm->expr_alloc(), f64o)); + auto expr = DConstant::make(p_psm->expr_alloc(), f64o); // DProgressSsm responsible for resolving cases like // 1.9, diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index d6037908..e926565d 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -290,8 +290,7 @@ namespace xo { DString * dstr = DString::from_cstr(p_psm->expr_alloc(), tk.text().c_str()); obj str(dstr); - auto * dconst = DConstant::make(p_psm->expr_alloc(), str); - obj expr(dconst); + obj expr = DConstant::make(p_psm->expr_alloc(), str); DProgressSsm::start(p_psm->parser_alloc(), expr, @@ -319,8 +318,7 @@ namespace xo { { auto f64o = DFloat::box(p_psm->expr_alloc(), tk.f64_value()); - auto * dconst = DConstant::make(p_psm->expr_alloc(), f64o); - auto expr = with_facet::mkobj(dconst); + auto expr = DConstant::make(p_psm->expr_alloc(), f64o); DProgressSsm::start(p_psm->parser_alloc(), expr, @@ -348,8 +346,7 @@ namespace xo { { auto i64o = DFloat::box(p_psm->expr_alloc(), tk.i64_value()); - auto * dconst = DConstant::make(p_psm->expr_alloc(), i64o); - auto expr = with_facet::mkobj(dconst); + auto expr = DConstant::make(p_psm->expr_alloc(), i64o); DProgressSsm::start(p_psm->parser_alloc(), expr, @@ -377,8 +374,7 @@ namespace xo { { auto dvalue = DBoolean::box(p_psm->expr_alloc(), tk.bool_value()); - auto * dconst = DConstant::make(p_psm->expr_alloc(), dvalue); - auto expr = with_facet::mkobj(dconst); + auto expr = DConstant::make(p_psm->expr_alloc(), dvalue); DProgressSsm::start(p_psm->parser_alloc(), expr, diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 830dd30e..cfed858f 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -9,6 +9,9 @@ #include "DExpectExprSsm.hpp" #include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" + +#include +#include #ifdef NOT_YET #include "DApplySsm.hpp" #include "ssm/ISyntaxStateMachine_DApplySsm.hpp" From ce732b3d3acd8fab347eff102975ca9258d8271e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 26 Jan 2026 15:45:22 -0500 Subject: [PATCH 131/342] xo-reader2: + missing subsystem deps --- cmake/xo_reader2Config.cmake.in | 2 ++ src/reader2/CMakeLists.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/cmake/xo_reader2Config.cmake.in b/cmake/xo_reader2Config.cmake.in index 2b36efff..ed161c20 100644 --- a/cmake/xo_reader2Config.cmake.in +++ b/cmake/xo_reader2Config.cmake.in @@ -6,9 +6,11 @@ include(CMakeFindDependencyMacro) # must coordinate with xo_dependency() calls # in CMakeLists.txt # +find_dependency(xo_procedure2) find_dependency(xo_gc) find_dependency(xo_tokenizer2) find_dependency(xo_expression2) +find_dependency(subsys) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") check_required_components("@PROJECT_NAME@") diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 37dda298..e18cce73 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -45,6 +45,7 @@ set(SELF_SRCS xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) # note: deps here must also appear in cmake/xo_expression2Config.cmake.in +xo_dependency(${SELF_LIB} xo_procedure2) xo_dependency(${SELF_LIB} xo_gc) xo_dependency(${SELF_LIB} xo_tokenizer2) xo_dependency(${SELF_LIB} xo_expression2) From 774a6ebe22f39ff554ab6280ae87f1f41a39575c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 26 Jan 2026 15:45:40 -0500 Subject: [PATCH 132/342] xo-expression2: + DApplyExpr::make --- src/reader2/DProgressSsm.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index cfed858f..cc0fc14b 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -9,9 +9,15 @@ #include "DExpectExprSsm.hpp" #include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" +#include +#include #include #include + +#include // for xo::scm::Primitives +#include + #ifdef NOT_YET #include "DApplySsm.hpp" #include "ssm/ISyntaxStateMachine_DApplySsm.hpp" @@ -1179,20 +1185,36 @@ namespace xo { break; case optype::op_multiply: -#ifdef NOT_YET { + auto pm_obj = with_facet::mkobj(&Primitives::s_mul_gco_gco_pm); + + auto fn_expr = DConstant::make(p_psm->expr_alloc(), pm_obj); + /* note: * 1. don't assume we know lhs_ / rhs_ value types yet. * perhaps have expression like * f(..) * g(..) * where f is the function that contains current ssm. + * * 2. consequence: we need representation for * polymorphic multiply on unknown numeric arguments. + * + * 3. TypeRef::dwim(..) is a placeholder. + * Plan to later provide abstract interpreter + * (ie compiler pass :) to drive type inference/unification + * + * 4. Alternatively could supply type-annotation syntax + * so human can assist inference; context here is we want + * to automate the boring stuff */ - DApplyExpr::make2(); + TypeRef tref = TypeRef::dwim + (TypeRef::prefix_type::from_chars("_mul_gco"), + nullptr); + + return DApplyExpr::make2(p_psm->expr_alloc(), + tref, fn_expr, lhs_, rhs_); } -#endif break; case optype::op_divide: From d720d89fd26a76101fb1238c917a0b1cd5b38a78 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 26 Jan 2026 19:26:54 -0500 Subject: [PATCH 133/342] xo-reflect: + pretty printing for xo::reflect::TypeDescr --- include/xo/alloc/GcStatistics.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/xo/alloc/GcStatistics.hpp b/include/xo/alloc/GcStatistics.hpp index b591bf22..69053457 100644 --- a/include/xo/alloc/GcStatistics.hpp +++ b/include/xo/alloc/GcStatistics.hpp @@ -1,16 +1,16 @@ -/* GcStatistics.hpp +/** @file GcStatistics.hpp * - * author: Roland Conybeare, Aug 2025 - */ + * @author Roland Conybeare, Aug 2025 + **/ #pragma once #include "generation.hpp" #include "CircularBuffer.hpp" -#include "xo/reflect/TypeDescr.hpp" -#include "xo/unit/quantity.hpp" -#include "xo/unit/quantity_iostream.hpp" -#include "xo/indentlog/print/pretty.hpp" +#include +#include +#include +#include #include #include From a346dcc5797c3ee04b46f6b1e139d7796cf83ad2 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 26 Jan 2026 21:36:10 -0500 Subject: [PATCH 134/342] xo-reader2: formatting + asserts --- src/reader2/DDefineSsm.cpp | 9 +++++++-- src/reader2/DExpectExprSsm.cpp | 3 ++- src/reader2/DProgressSsm.cpp | 24 ++++-------------------- src/reader2/ParserStack.cpp | 5 +++-- src/reader2/SchematikaParser.cpp | 3 ++- utest/SchematikaParser.test.cpp | 4 ++-- 6 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 0cd488e5..c4628c22 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -733,13 +733,18 @@ namespace xo { bool DDefineSsm::pretty(const ppindentinfo & ppii) const { - auto expr = FacetRegistry::instance().variant(def_expr_); + auto expr + = FacetRegistry::instance().variant(def_expr_); + assert(expr.data()); + (void)expr; return ppii.pps()->pretty_struct (ppii, "DDefineSsm", refrtag("defstate", defstate_), - refrtag("def_expr", expr)); + refrtag("def_expr", expr) + ); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 66eb41cd..7a82ad1c 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -336,7 +336,8 @@ namespace xo { (ppii, "DExpectExprSsm", refrtag("allow_defs", allow_defs_), - refrtag("cxl_on_rightbrace", cxl_on_rightbrace_)); + refrtag("cxl_on_rightbrace", cxl_on_rightbrace_) + ); } #ifdef NOT_YET diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index cc0fc14b..e085f8cf 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -1115,32 +1115,16 @@ namespace xo { if (rhs_) rhs = FacetRegistry::instance().variant(rhs_); + (void)lhs; + return ppii.pps()->pretty_struct (ppii, "DProgressSsm", refrtag("lhs", lhs), refrtag("op", op_type_), - cond(rhs, refrtag("rhs", rhs), "nullptr")); + cond(rhs, refrtag("rhs", rhs), "nullptr") + ); -#ifdef NOPE - if (ppii.upto()) { - return (ppii.pps()->print_upto("print_upto(refrtag("lhs", lhs_)) : true) - && (op_type_ != optype::invalid ? ppii.pps()->print_upto(refrtag("op", op_type_)) : true) - && (rhs_ ? ppii.pps()->print_upto(refrtag("rhs", rhs_)) : true) - && ppii.pps()->print_upto(">")); - } else { - ppii.pps()->write("pretty(refrtag("lhs", lhs_)); - if (op_type_ != optype::invalid) - ppii.pps()->pretty(refrtag("op", op_type_)); - if (rhs_) - ppii.pps()->pretty(refrtag("rhs", rhs_)); - ppii.pps()->write(">"); - return false; - } -#endif } obj diff --git a/src/reader2/ParserStack.cpp b/src/reader2/ParserStack.cpp index 91d8bca9..9af9f339 100644 --- a/src/reader2/ParserStack.cpp +++ b/src/reader2/ParserStack.cpp @@ -73,8 +73,9 @@ namespace xo { char buf[80]; snprintf(buf, sizeof(buf), "[%lu]", i_frame); - auto ssm = FacetRegistry::instance().variant (frame->top()); + auto ssm = (FacetRegistry::instance().variant + (frame->top())); + assert(ssm.data()); pps->newline_pretty_tag(ppii.ci1(), buf, ssm); diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 13f9edff..e584044c 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -117,7 +117,8 @@ namespace xo { return pps->pretty_struct (ppii, "SchematikaParser", - refrtag("stack", psm_.stack())); + refrtag("stack", psm_.stack()) + ); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index a8544687..895aed10 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -16,9 +16,9 @@ namespace xo { using xo::scm::SchematikaParser; using xo::scm::ASyntaxStateMachine; using xo::scm::syntaxstatetype; - using xo::scm::DDefineSsm; +// using xo::scm::DDefineSsm; using xo::scm::DExpectExprSsm; - using xo::scm::defexprstatetype; +// using xo::scm::defexprstatetype; //using xo::scm::ParserResult; //using xo::scm::parser_result_type; using xo::scm::Token; From bbeaadc9e41412b675a780e3fbf295596d331ccd Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 26 Jan 2026 22:40:56 -0500 Subject: [PATCH 135/342] xo-reader2: + DProgressSsm.on_parser_expression_with_semicolon --- src/reader2/DProgressSsm.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index e085f8cf..bd48e58c 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -527,9 +527,25 @@ namespace xo { DProgressSsm::on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm) { - p_psm->illegal_parsed_expression("DProgressSsm::on_parsed_expression_with_semicolon", - expr, - this->get_expect_str()); + scope log(XO_DEBUG(p_psm->debug_flag()), + xtag("expr", expr)); + + if (op_type_ == optype::invalid) { + p_psm->illegal_parsed_expression + ("DProgressSsm::on_parsed_expression_with_semicolon", + expr, + this->get_expect_str()); + return; + } + + this->rhs_ = expr; + + obj expr2 = this->assemble_expr(p_psm); + + if (expr2) { + p_psm->pop_ssm(); + p_psm->on_parsed_expression_with_semicolon(expr2); + } } #ifdef NOT_YET From 3d7c3f8861b577478ffa0ec7ce0653299b8bd8bc Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 27 Jan 2026 10:09:26 -0500 Subject: [PATCH 136/342] xo-expression2: + DIfElseExpr + utest --- src/reader2/DProgressSsm.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index bd48e58c..76574c7b 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -1186,9 +1186,10 @@ namespace xo { case optype::op_multiply: { - auto pm_obj = with_facet::mkobj(&Primitives::s_mul_gco_gco_pm); - - auto fn_expr = DConstant::make(p_psm->expr_alloc(), pm_obj); + auto pm_obj = (with_facet::mkobj + (&Primitives::s_mul_gco_gco_pm)); + auto fn_expr = (DConstant::make + (p_psm->expr_alloc(), pm_obj)); /* note: * 1. don't assume we know lhs_ / rhs_ value types yet. From 53574071514f10c642440da071be53ed0937a0fd Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 27 Jan 2026 15:50:10 -0500 Subject: [PATCH 137/342] xo-reader2: support if-then-else expressions. + detailed utest --- CMakeLists.txt | 26 + idl/IPrintable_DIfElseSsm.json5 | 13 + idl/ISyntaxStateMachine_DIfElseSsm.json5 | 13 + include/xo/reader2/DDefineSsm.hpp | 3 +- include/xo/reader2/DExpectExprSsm.hpp | 52 +- include/xo/reader2/DIfElseSsm.hpp | 221 ++++++++ include/xo/reader2/DProgressSsm.hpp | 13 +- .../xo/reader2/ssm/IPrintable_DIfElseSsm.hpp | 62 ++ .../ssm/ISyntaxStateMachine_DIfElseSsm.hpp | 73 +++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 4 + src/reader2/DExpectExprSsm.cpp | 132 ++--- src/reader2/DExprSeqState.cpp | 17 +- src/reader2/DIfElseSsm.cpp | 530 ++++++++++++++++++ src/reader2/DProgressSsm.cpp | 73 ++- src/reader2/IPrintable_DIfElseSsm.cpp | 28 + .../ISyntaxStateMachine_DIfElseSsm.cpp | 59 ++ src/reader2/reader2_register_facets.cpp | 7 + src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 108 +++- 20 files changed, 1297 insertions(+), 142 deletions(-) create mode 100644 idl/IPrintable_DIfElseSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DIfElseSsm.json5 create mode 100644 include/xo/reader2/DIfElseSsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DIfElseSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp create mode 100644 src/reader2/DIfElseSsm.cpp create mode 100644 src/reader2/IPrintable_DIfElseSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 43c747f6..a4124f45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,32 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-ifelsessm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR IfElseSsm + INPUT idl/ISyntaxStateMachine_DIfElseSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-ifelsessm + FACET_PKG xo_printable2 + FACET Printable + REPR Ifelsessm + INPUT idl/IPrintable_DIfElseSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectsymbolssm diff --git a/idl/IPrintable_DIfElseSsm.json5 b/idl/IPrintable_DIfElseSsm.json5 new file mode 100644 index 00000000..28fab147 --- /dev/null +++ b/idl/IPrintable_DIfElseSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DIfElseSsm", + using_doxygen: true, + repr: "DIfElseSsm", + doc: [ "implement APrintable for DIfElseSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DIfElseSsm.json5 b/idl/ISyntaxStateMachine_DIfElseSsm.json5 new file mode 100644 index 00000000..5e7e828b --- /dev/null +++ b/idl/ISyntaxStateMachine_DIfElseSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DIfElseSsm", + using_doxygen: true, + repr: "DIfElseSsm", + doc: [ "implement ASyntaxStateMachine for DIfElseSsm" ], +} diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 9f707fca..6d15c5ee 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -113,7 +113,7 @@ namespace xo { syntaxstatetype ssm_type() const noexcept; /** text describing expected/allowed input to this ssm in current state. - * Intended to drive error mesages + * Intended to drive error messages **/ std::string_view get_expect_str() const noexcept; @@ -212,6 +212,7 @@ namespace xo { /** @defgroup scm-define-printable-facet printable facet methods **/ ///@{ + /** pretty-printer support **/ bool pretty(const ppindentinfo & ppii) const; ///@} diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 85d4e5e1..b994b498 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -41,6 +41,34 @@ namespace xo { bool allow_defs() const noexcept { return allow_defs_; } bool cxl_on_rightbrace() const noexcept { return cxl_on_rightbrace_; } + ///@} + /** @defgroup scm-expectexpr-methods general methods **/ + ///@{ + + /** step state machine for this syntax on incoming boolean literal token @p tkk + * with overall parser state in @p p_psm + **/ + void on_bool_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming f64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_f64_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming i64 token @p tk, + * overall parser state in @p p_psm + **/ + void on_i64_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming string token @p tk, + * overall parser state in @p p_psm + **/ + void on_string_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expectexpr-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -89,30 +117,6 @@ namespace xo { void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); - /** update state for this syntax on incoming string token @p tk, - * overall parser state in @p p_psm - **/ - void on_string_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming f64 token @p tk, - * overall parser state in @p p_psm - **/ - void on_f64_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming i64 token @p tk, - * overall parser state in @p p_psm - **/ - void on_i64_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming bool token @p tk, - * overall parser state in @p p_psm - **/ - void on_bool_token(const Token & tk, - ParserStateMachine * p_psm); - /** update state for this syntax on incoming semicolon token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DIfElseSsm.hpp b/include/xo/reader2/DIfElseSsm.hpp new file mode 100644 index 00000000..9b3e5d17 --- /dev/null +++ b/include/xo/reader2/DIfElseSsm.hpp @@ -0,0 +1,221 @@ +/** @file DIfElseSsm.hpp + * + * @author Roland Conybeare, Jul 2025 + **/ + +#pragma once + +#include +#include "ParserStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include +#include +#include +//#include "exprstate.hpp" +//#include "xo/indentlog/print/ppdetail_atomic.hpp" + +namespace xo { + namespace scm { + /** + * if test-expr then then-expr else else-expr ; + * ^ ^ ^ ^ ^ ^ ^ + * | | | | | | | + * | if_1 if_2 if_3 if_4 if_5 if_6 + * if_0 + * + * if_0 --on_if_token()--> if_1 + * if_1 --on_expr()--> if_2 + * if_2 --on_then_token()--> if_3 + * if_3 --on_expr()--> if_4 + * if_4 --on_else_token()--> if_5 + * --on_semicolon_token()--> (done) + * if_5 --on_expr()-->if_6 + * if_6 --on_semicolon_token()--> (done) + **/ + enum class ifexprstatetype { + invalid = -1, + + if_0, + if_1, + if_2, + if_3, + if_4, + if_5, + if_6, + + N, + }; + + extern const char * ifexprstatetype_descr(ifexprstatetype x); + + std::ostream & + operator<<(std::ostream & os, ifexprstatetype x); + + /** @class DIfElseSsm + * @brief syntax state machine for parsing a conditional expression + **/ + class DIfElseSsm { + public: + using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; + using TypeDescr = xo::reflect::TypeDescr; + using ppindentinfo = xo::print::ppindentinfo; + + public: + /** @defgroup scm-ifelsessm-expression-ctors constructors **/ + ///@{ + explicit DIfElseSsm(DIfElseExpr * ifelse_expr); + +#ifdef NOT_YET + /** create instance using memory from @p parser_mm + * with initial scaffold @p ifelse_expr + **/ + static obj make(DArena & parser_mm, + DIfElseExpr * ifelse_expr); +#endif + + /** create instance using memory from @p parser_mm + * with initial scaffold @p ifelse_expr. + **/ + static DIfElseSsm * _make(DArena & parser_mm, + DIfElseExpr * ifelse_expr); + + /** start nested parser for an if-else expression + * on top of parser state machine @p p_psm. + * Use @p parser_mm to allocate syntax state machines + * (i.e. temporary memory needed only during parsing) + * Use @p expr_mm to allocate expressions. + **/ + static void start(DArena & parser_mm, + obj expr_mm, + ParserStateMachine * p_psm); + ///@} + /** @defgroup scm-ifelsessm-expression-methods general methods **/ + ///@{ + + /** operate state machine on if-token input @p tk, + * with overall parser state in @p p_psm + **/ + void on_if_token(const Token & tk, + ParserStateMachine * p_psm); + + /** operate state machine on then-token input @p tk, + * with overall parser state in @p p_psm + **/ + void on_then_token(const Token & tk, + ParserStateMachine * p_psm); + + /** operate state machine on else-token input @p tk, + * with overall parser state in @p p_psm + **/ + void on_else_token(const Token & tk, + ParserStateMachine * p_psm); + + /** victory: report completed @ref if_expr_ to parent ssm, + * after removing this ssm from parser stack + **/ + void finish_and_continue(ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-ifelsessm-expression-facet expression facet methods **/ + ///@{ + + /** identifies this state machine **/ + syntaxstatetype ssm_type() const noexcept; + + /** text describing expected/allowed input to this ssm in current state. + * Intended to drive error messages + **/ + std::string_view get_expect_str() const noexcept; + + /** operate state machine for this syntax on incoming token @p tk + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** operate state machine for this syntax on incoming semicolon token @p tk + * with overall parser state in @p p_psm + **/ + void on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax after parsing an expression @p expr, + * overall parser state in @p p_psm. + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + + /** update state for this syntax after parsing a type description @p td; + * overall parser state in @p p_psm + **/ + void on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm); + + /** update state for this syntax after parsing an expression @p expr, + * followed by semicolon, + * with overall parser state in @p p_psm. + **/ + void on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm); + + /** update state for this syntax after parsing a symbol @p sym, + * with overall parser state in @p p_psm + **/ + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-ifelsessm-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + +#ifdef NOT_YET + // ----- inherited from exprstate ----- + + virtual const char * get_expect_str() const override; + + virtual void on_if_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_then_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_else_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_semicolon_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_rightbrace_token(const token_type & tk, + parserstatemachine * p_psm) override; + + virtual void on_expr(bp expr, + parserstatemachine * p_psm) override; + virtual void on_expr_with_semicolon(bp expr, + parserstatemachine * p_psm) override; + + virtual void print(std::ostream & os) const override; +#endif + + private: +#ifdef NOT_YET + static std::unique_ptr make(); + + /** exit this exprstate, + * and deliver @ref if_expr_ to parent exprstate + **/ + void finish_and_continue(parserstatemachine * p_psm); +#endif + + private: + ifexprstatetype ifstate_ = ifexprstatetype::invalid; + /** scaffold ifelse-expression here. + * This will eventually be the output of this ssm + **/ + obj if_expr_; + + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DIfElseSsm.hpp */ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 31b3a55d..788c10ca 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -126,6 +126,17 @@ namespace xo { **/ obj assemble_expr(ParserStateMachine * p_psm); + /** @defgroup scm-progressssm-methods general methods **/ + ///@{ + + void on_if_token(const Token & tk, + ParserStateMachine * p_psm); + void on_then_token(const Token & tk, + ParserStateMachine * p_psm); + void on_else_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} /** @defgroup scm-progressssm-ssm-facet syntaxstatemachine facet methods **/ /// @{ @@ -139,8 +150,6 @@ namespace xo { ParserStateMachine * p_psm); void on_def_token(const Token & tk, ParserStateMachine * p_psm); - void on_if_token(const Token & tk, - ParserStateMachine * p_psm); void on_colon_token(const Token & tk, ParserStateMachine * p_psm); void on_singleassign_token(const Token & tk, diff --git a/include/xo/reader2/ssm/IPrintable_DIfElseSsm.hpp b/include/xo/reader2/ssm/IPrintable_DIfElseSsm.hpp new file mode 100644 index 00000000..e9a40c75 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DIfElseSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DIfElseSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DIfElseSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DIfElseSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DIfElseSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DIfElseSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DIfElseSsm + **/ + class IPrintable_DIfElseSsm { + public: + /** @defgroup scm-printable-difelsessm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-difelsessm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DIfElseSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp new file mode 100644 index 00000000..2101b8e1 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp @@ -0,0 +1,73 @@ +/** @file ISyntaxStateMachine_DIfElseSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DIfElseSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DIfElseSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DIfElseSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DIfElseSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DIfElseSsm + **/ + class ISyntaxStateMachine_DIfElseSsm { + public: + /** @defgroup scm-syntaxstatemachine-difelsessm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-difelsessm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DIfElseSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DIfElseSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DIfElseSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DIfElseSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DIfElseSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + static void on_parsed_expression_with_semicolon(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index d7340b25..796743d7 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -33,6 +33,9 @@ namespace xo { /** handle define-expression. See @ref DDefineSsm **/ defexpr, + /** handle ifelse-expression. See @ref DIfElseSsm **/ + ifelseexpr, + /** rhs expression. state exists to achieve 1-token lookahead **/ progress, diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index e18cce73..2ab9d917 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -25,6 +25,10 @@ set(SELF_SRCS ISyntaxStateMachine_DDefineSsm.cpp IPrintable_DDefineSsm.cpp + DIfElseSsm.cpp + ISyntaxStateMachine_DIfElseSsm.cpp + IPrintable_DIfElseSsm.cpp + DExpectSymbolSsm.cpp ISyntaxStateMachine_DExpectSymbolSsm.cpp IPrintable_DExpectSymbolSsm.cpp diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 7a82ad1c..4f61df72 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -11,8 +11,14 @@ #include "syntaxstatetype.hpp" #include #include +#include +#include +#include +#include #include #include +#include +#include #include #include @@ -233,12 +239,21 @@ namespace xo { } void - DExpectExprSsm::on_string_token(const Token & tk, - ParserStateMachine * p_psm) + DExpectExprSsm::on_bool_token(const Token & tk, + ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token("DExpectExprSsm::on_string_token", - tk, - this->get_expect_str()); + auto flag = DBoolean::box(p_psm->expr_alloc(), + tk.bool_value()); + + auto expr = DConstant::make(p_psm->expr_alloc(), flag); + + // DProgressSsm responsible for resolving cases like + // true; + // true && false; + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); } void @@ -268,18 +283,48 @@ namespace xo { DExpectExprSsm::on_i64_token(const Token & tk, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token("DExpectExprSsm::on_i64_token", - tk, - this->get_expect_str()); + auto i64o = DInteger::box(p_psm->expr_alloc(), + tk.i64_value()); + + auto expr = DConstant::make(p_psm->expr_alloc(), i64o); + + // DProgressSsm responsible for resolving cases like + // 1, + // 1; + // 1 + 2; + // 1 + 2 .. // could be followed by infix + // 1 + 2 * 3; + // 1 + 2 * 3 .. // could be followed by infix + // 1 * (2 + 3) + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); } void - DExpectExprSsm::on_bool_token(const Token & tk, - ParserStateMachine * p_psm) + DExpectExprSsm::on_string_token(const Token & tk, + ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token("DExpectExprSsm::on_bool_token", - tk, - this->get_expect_str()); + auto str = DString::from_str(p_psm->expr_alloc(), + tk.text()); + auto str_o = obj(str); + + auto expr = DConstant::make(p_psm->expr_alloc(), str_o); + + /* e.g. + * def msg = "hello, world"; + * \----tk----/ + * + * DProgressSsm responsible for operators that apply to string + * "foo"; + * "foo" <= "bar" + * "foo" + ", she said"; + */ + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); } void @@ -313,9 +358,8 @@ namespace xo { DExpectExprSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) { - p_psm->illegal_parsed_expression("DExpectExprSsm::on_parsed_expression", - expr, - this->get_expect_str()); + p_psm->pop_ssm(); + p_psm->on_parsed_expression(expr); } void @@ -464,62 +508,6 @@ namespace xo { return; } - void - expect_expr_xs::on_bool_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - progress_xs::start - (Constant::make(tk.bool_value()), - p_psm); - } - - void - expect_expr_xs::on_i64_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag()), - xtag("tk", tk), - xtag("do", "push progress xs w/ tk value")); - - progress_xs::start - (Constant::make(tk.i64_value()), - p_psm); - } - - void - expect_expr_xs::on_f64_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - //constexpr const char * self_name = "exprstate::on_f64_token"; - - /* e.g. - * def pi = 3.14159265; - * \---tk---/ - */ - progress_xs::start - (Constant::make(tk.f64_value()), - p_psm); - } - - void - expect_expr_xs::on_string_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - /* e.g. - * def msg = "hello, world"; - * \----tk----/ - */ - progress_xs::start - (Constant::make(tk.text()), - p_psm); - } - void expect_expr_xs::on_expr(bp expr, parserstatemachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index e926565d..cfd92683 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -7,6 +7,7 @@ #include "DDefineSsm.hpp" #include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" #include +#include #include #include #include @@ -246,20 +247,20 @@ namespace xo { { switch (seqtype_) { case exprseqtype::toplevel_interactive: - p_psm->illegal_input_on_token("DExprSeqState::on_if_token", - tk, - this->get_expect_str()); - //assert(false); // DfElseState::start(p_psm); - break; + DIfElseSsm::start(p_psm->parser_alloc(), + p_psm->expr_alloc(), + p_psm); + return; case exprseqtype::toplevel_batch: - p_psm->illegal_input_on_token("DExprSeqState::on_if_token", - tk, - this->get_expect_str()); break; case exprseqtype::N: assert(false); // unreachable break; } + + p_psm->illegal_input_on_token("DExprSeqState::on_if_token", + tk, + this->get_expect_str()); } void diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp new file mode 100644 index 00000000..eca02910 --- /dev/null +++ b/src/reader2/DIfElseSsm.cpp @@ -0,0 +1,530 @@ +/** @file DIfElseSsm.cpp + * + * @author Roland Conybeare, Jul 2025 + **/ + +#include "DIfElseSsm.hpp" +#include "ssm/ISyntaxStateMachine_DIfElseSsm.hpp" +#include "ssm/IPrintable_DDefineSsm.hpp" +#include "DExpectExprSsm.hpp" +#include +#include +#include +//#include "exprstatestack.hpp" +//#include "parserstatemachine.hpp" +//#include "expect_expr_xs.hpp" +//#include "xo/indentlog/print/ppdetail_atomic.hpp" + +namespace xo { + using xo::print::APrintable; + using xo::facet::FacetRegistry; + using xo::facet::with_facet; + using xo::reflect::typeseq; + + namespace scm { + // ----- ifexprstatetype ----- + + const char * + ifexprstatetype_descr(ifexprstatetype x) { + switch (x) { + case ifexprstatetype::invalid: return "invalid"; + case ifexprstatetype::if_0: return "if_0"; + case ifexprstatetype::if_1: return "if_1"; + case ifexprstatetype::if_2: return "if_2"; + case ifexprstatetype::if_3: return "if_3"; + case ifexprstatetype::if_4: return "if_4"; + case ifexprstatetype::if_5: return "if_5"; + case ifexprstatetype::if_6: return "if_6"; + case ifexprstatetype::N: break; + } + + return "ifexprstatetype?"; + } + + std::ostream & + operator<<(std::ostream & os, ifexprstatetype x) { + os << ifexprstatetype_descr(x); + return os; + } + + // ----- DIfElseSsm ----- + + DIfElseSsm::DIfElseSsm(DIfElseExpr * ifelse_expr) : ifstate_{ifexprstatetype::if_0}, + if_expr_{ifelse_expr} + {} + + DIfElseSsm * + DIfElseSsm::_make(DArena & mm, + DIfElseExpr * ifelse_expr) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DIfElseSsm)); + + return new (mem) DIfElseSsm(ifelse_expr); + } + + void + DIfElseSsm::start(DArena & parser_mm, + obj expr_mm, + ParserStateMachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + DIfElseExpr * if_expr = DIfElseExpr::_make_empty(expr_mm); + DIfElseSsm * if_ssm = DIfElseSsm::_make(parser_mm, if_expr); + + obj ssm + = with_facet::mkobj(if_ssm); + + p_psm->push_ssm(ssm); + + // note: triggers poly dispatch + p_psm->on_token(Token::if_token()); + } + + syntaxstatetype + DIfElseSsm::ssm_type() const noexcept + { + return syntaxstatetype::ifelseexpr; + } + + std::string_view + DIfElseSsm::get_expect_str() const noexcept + { + /** + * if test-expr then then-expr else else-expr ; + * ^ ^ ^ ^ ^ ^ ^ + * | | | | | | | + * | if_1 if_2 if_3 if_4 if_5 if_6 + * if_0 + * + * if_0 --on_if_token()--> if_1 + * if_1 --on_expr()--> if_2 + * if_2 --on_then_token()--> if_3 + * if_3 --on_expr()--> if_4 + * if_4 --on_else_token()--> if_5 + * --on_semicolon_token()--> (done) + * if_5 --on_expr()-->if_6 + * if_6 --on_semicolon_token()--> (done) + **/ + switch (this->ifstate_) { + case ifexprstatetype::invalid: + case ifexprstatetype::N: + assert(false); // unreachable + break; + case ifexprstatetype::if_0: + return "if"; + case ifexprstatetype::if_1: + return "expression"; + case ifexprstatetype::if_2: + return "then"; + case ifexprstatetype::if_3: + return "expression"; + case ifexprstatetype::if_4: + return "else|semicolon"; + case ifexprstatetype::if_5: + return "expression"; + case ifexprstatetype::if_6: + return "semicolon"; + } + + return "?expect"; + } + + void + DIfElseSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); + + switch (tk.tk_type()) { + case tokentype::tk_symbol: + case tokentype::tk_def: + break; + case tokentype::tk_if: + this->on_if_token(tk, p_psm); + return; + case tokentype::tk_then: + this->on_then_token(tk, p_psm); + return; + case tokentype::tk_else: + this->on_else_token(tk, p_psm); + return; + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + p_psm->illegal_input_on_token("DIfElseSsm::on_token", + tk, + this->get_expect_str()); + } + +#ifdef NOT_YET + // ----- if_else_xs ----- + + if_else_xs::if_else_xs(rp if_expr) + : exprstate(exprstatetype::ifexpr), + ifxs_type_{ifexprstatetype::if_0}, + if_expr_{std::move(if_expr)} + {} +#endif + + void + DIfElseSsm::on_if_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("ifstate", ifstate_); + + if (ifstate_ == ifexprstatetype::if_0) { + this->ifstate_ = ifexprstatetype::if_1; + + DExpectExprSsm::start(p_psm->parser_alloc(), + p_psm); + return; + } + + p_psm->illegal_input_on_token("DIfElseSsm::on_if_token", + tk, + this->get_expect_str()); + } + + void + DIfElseSsm::on_then_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("ifstate", ifstate_); + + if (ifstate_ == ifexprstatetype::if_2) { + this->ifstate_ = ifexprstatetype::if_3; + + DExpectExprSsm::start(p_psm->parser_alloc(), p_psm); + return; + } + + p_psm->illegal_input_on_token("DIfElseSsm::on_then_token", + tk, + this->get_expect_str()); + } + +#ifdef NOT_YET + void + if_else_xs::on_else_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("ifxs_type", ifxs_type_); + + if (this->ifxs_type_ == ifexprstatetype::if_4) { + this->ifxs_type_ = ifexprstatetype::if_5; + + expect_expr_xs::start(p_psm); + return; + } + + constexpr const char * c_self_name = "if_else_xs::on_else_token"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } +#endif + + void + DIfElseSsm::on_else_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("ifstate", ifstate_); + + if (ifstate_ == ifexprstatetype::if_4) { + this->ifstate_ = ifexprstatetype::if_5; + + DExpectExprSsm::start(p_psm->parser_alloc(), p_psm); + return; + } + + p_psm->illegal_input_on_token("DIfElseSsm::on_else_token", + tk, + this->get_expect_str()); + } + +#ifdef NOT_YET + void + if_else_xs::finish_and_continue(parserstatemachine * p_psm) + { + rp if_expr = this->if_expr_; + std::unique_ptr self = p_psm->pop_exprstate(); + + if (this->ifxs_type_ == ifexprstatetype::if_4) { + /* if no else-branch, then if-expr can't have valuetype */ + if_expr->assign_valuetype(nullptr); + } + + p_psm->top_exprstate().on_expr(if_expr, p_psm); + } +#endif + + void + DIfElseSsm::finish_and_continue(ParserStateMachine * p_psm) + { + p_psm->pop_ssm(); + + // rp if_expr = this->if_expr_; + // std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->on_parsed_expression(if_expr_); + } + +#ifdef NOT_YET + void + if_else_xs::on_rightbrace_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + this->finish_and_continue(p_psm); + p_psm->on_rightbrace_token(tk); + } + + void + if_else_xs::on_semicolon_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("ifxs_type", ifxs_type_); + + const char * c_self_name = "if_else_xs::on_semicolon_token"; + + switch (this->ifxs_type_) { + case ifexprstatetype::invalid: + case ifexprstatetype::if_0: + case ifexprstatetype::n_ifexprstatetype: + // unreachable + assert(false); + break; + + case ifexprstatetype::if_1: + case ifexprstatetype::if_2: + case ifexprstatetype::if_3: + case ifexprstatetype::if_5: + this->illegal_input_on_token(c_self_name, tk, get_expect_str(), p_psm); + break; + case ifexprstatetype::if_4: + case ifexprstatetype::if_6: { + this->finish_and_continue(p_psm); + break; + } + } + } +#endif + + void + DIfElseSsm::on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("ifstate", ifstate_); + + switch (ifstate_) { + case ifexprstatetype::invalid: + case ifexprstatetype::N: + // unreachable + assert(false); + break; + + case ifexprstatetype::if_0: + case ifexprstatetype::if_1: + case ifexprstatetype::if_2: + case ifexprstatetype::if_3: + case ifexprstatetype::if_5: + break; + case ifexprstatetype::if_4: + case ifexprstatetype::if_6: + this->finish_and_continue(p_psm); + return; + } + + p_psm->illegal_input_on_token("DIfElseSsm::on_semicolon_token", + tk, this->get_expect_str()); + + } + +#ifdef NOT_YET + void + if_else_xs::on_expr(bp expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log(xtag("ifxs_type", ifxs_type_)); + + switch (this->ifxs_type_) { + case ifexprstatetype::invalid: + case ifexprstatetype::if_0: + case ifexprstatetype::n_ifexprstatetype: + assert(false); // unreachable + return; + case ifexprstatetype::if_1: + if_expr_->assign_test(expr.promote()); + ifxs_type_ = ifexprstatetype::if_2; + return; + case ifexprstatetype::if_2: + /** error: expecting 'then' **/ + break; + case ifexprstatetype::if_3: + if_expr_->assign_when_true(expr.promote()); + ifxs_type_ = ifexprstatetype::if_4; + return; + case ifexprstatetype::if_4: + /** error: expecting 'else' or ';' **/ + break; + case ifexprstatetype::if_5: + if_expr_->assign_when_false(expr.promote()); + ifxs_type_ = ifexprstatetype::if_6; + return; + case ifexprstatetype::if_6: + /** error: expecting ';' **/ + break; + } + + constexpr const char* c_self_name = "if_else_xs::on_expr"; + const char * exp = get_expect_str(); + + this->illegal_input_on_expr(c_self_name, expr, exp, p_psm); + } + +#endif + + void + DIfElseSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + log && log(xtag("ifstate", ifstate_)); + + // if (ifstate_ == ...) { .... return; } + + switch (ifstate_) { + case ifexprstatetype::invalid: + case ifexprstatetype::N: + assert(false); + break; + case ifexprstatetype::if_0: + // should be unreachable + break; + case ifexprstatetype::if_1: + if_expr_.data()->assign_test(expr); + this->ifstate_ = ifexprstatetype::if_2; + return; + case ifexprstatetype::if_2: + // error: expecting "then" token here + break; + case ifexprstatetype::if_3: + if_expr_.data()->assign_when_true(expr); + this->ifstate_ = ifexprstatetype::if_4; + return; + case ifexprstatetype::if_4: + // error: expecting "else" or ";" + break; + case ifexprstatetype::if_5: + if_expr_.data()->assign_when_false(expr); + this->ifstate_ = ifexprstatetype::if_6; + return; + case ifexprstatetype::if_6: + // error: expecting ";" + break; + } + + p_psm->illegal_parsed_expression("DIfElseSsm::on_parsed_expression", + expr, + this->get_expect_str()); + } + + void + DIfElseSsm::on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + this->on_parsed_expression(expr, p_psm); + this->on_semicolon_token(Token::semicolon_token(), p_psm); + } + + void + DIfElseSsm::on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol("DIfElseSsm::on_parsed_symbol", + sym, + this->get_expect_str()); + } + + void + DIfElseSsm::on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_typedescr("DIfElseSsm::on_parsed_typedescr", + td, + this->get_expect_str()); + } + + bool + DIfElseSsm::pretty(const ppindentinfo & ppii) const + { + auto expr + = FacetRegistry::instance().variant(if_expr_); + assert(expr.data()); + (void)expr; + + return ppii.pps()->pretty_struct + (ppii, + "DIfElseSsm", + refrtag("ifstate", ifstate_), + refrtag("if_expr", expr)); + } + + } /*namespace scm*/ +} /*namespace xo*/ diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 76574c7b..e773f9a7 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -230,6 +230,14 @@ namespace xo { this->on_if_token(tk, p_psm); return; + case tokentype::tk_then: + this->on_then_token(tk, p_psm); + return; + + case tokentype::tk_else: + this->on_else_token(tk, p_psm); + return; + case tokentype::tk_colon: this->on_colon_token(tk, p_psm); return; @@ -288,8 +296,7 @@ namespace xo { case tokentype::tk_cmpne: case tokentype::tk_type: case tokentype::tk_lambda: - case tokentype::tk_then: - case tokentype::tk_else: + break; case tokentype::tk_let: case tokentype::tk_in: case tokentype::tk_end: @@ -329,6 +336,42 @@ namespace xo { this->get_expect_str()); } + void + DProgressSsm::on_then_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + (void)tk; + + obj expr = this->assemble_expr(p_psm); + + p_psm->pop_ssm(); // completes self + + // TODO: perhaps need to generalize on_parsed_expression_with_semicolon() ..? + p_psm->on_parsed_expression(expr); + p_psm->on_token(tk); + } + + void + DProgressSsm::on_else_token(const Token & tk, + ParserStateMachine * p_psm) + { + // note: common with .on_then_token() + + scope log(XO_DEBUG(p_psm->debug_flag())); + + (void)tk; + + obj expr = this->assemble_expr(p_psm); + + p_psm->pop_ssm(); // completes self + + // TODO: perhaps need to generalize on_parsed_expression_with_semicolon() ..? + p_psm->on_parsed_expression(expr); + p_psm->on_token(tk); + } + void DProgressSsm::on_colon_token(const Token & tk, ParserStateMachine * p_psm) @@ -466,9 +509,7 @@ namespace xo { { obj expr_pr = FacetRegistry::instance().variant(expr); - assert(expr_pr); - log && log(xtag("expr", expr_pr)); } @@ -979,28 +1020,6 @@ namespace xo { p_psm->top_exprstate().on_rightparen_token(tk, p_psm); } - void - progress_xs::on_then_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - rp expr = this->assemble_expr(p_psm); - - log && log(xtag("assembled-expr", expr)); - - std::unique_ptr self = p_psm->pop_exprstate(); - - p_psm->on_expr(expr); - p_psm->on_then_token(tk); - - /* control here on input like: - * - * if a > b then.. - * - */ - } - void progress_xs::on_else_token(const token_type & tk, parserstatemachine * p_psm) @@ -1120,7 +1139,7 @@ namespace xo { bool DProgressSsm::pretty(const xo::print::ppindentinfo & ppii) const { - scope log(XO_DEBUG(true)); + scope log(XO_DEBUG(false)); log && log(xtag("lhs_.tseq", lhs_._typeseq())); log && log(xtag("rhs_.tseq", rhs_._typeseq())); diff --git a/src/reader2/IPrintable_DIfElseSsm.cpp b/src/reader2/IPrintable_DIfElseSsm.cpp new file mode 100644 index 00000000..f2aebf7c --- /dev/null +++ b/src/reader2/IPrintable_DIfElseSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DIfElseSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DIfElseSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DIfElseSsm.json5] +**/ + +#include "ssm/IPrintable_DIfElseSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DIfElseSsm::pretty(const DIfElseSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DIfElseSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp new file mode 100644 index 00000000..66633e88 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp @@ -0,0 +1,59 @@ +/** @file ISyntaxStateMachine_DIfElseSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DIfElseSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DIfElseSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DIfElseSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DIfElseSsm::ssm_type(const DIfElseSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DIfElseSsm::get_expect_str(const DIfElseSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DIfElseSsm::on_token(DIfElseSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DIfElseSsm::on_parsed_symbol(DIfElseSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DIfElseSsm::on_parsed_typedescr(DIfElseSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DIfElseSsm::on_parsed_expression(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DIfElseSsm::on_parsed_expression_with_semicolon(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_semicolon(expr, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DIfElseSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index ab0ebe43..712f5998 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -11,6 +11,9 @@ #include #include +#include +#include + #include #include @@ -45,6 +48,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); @@ -59,6 +65,7 @@ namespace xo { log && log(xtag("DExprSeqState.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); + log && log(xtag("DIfElseSsm.tseq", typeseq::id())); log && log(xtag("DExpectSymbolSsm.tseq", typeseq::id())); log && log(xtag("DExpectTypeSsm.tseq", typeseq::id())); log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index 716c3d7d..1100bdb3 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -23,6 +23,8 @@ namespace xo { return "expect-rhs-expression"; case syntaxstatetype::defexpr: return "defexpr"; + case syntaxstatetype::ifelseexpr: + return "ifelseexpr"; case syntaxstatetype::progress: return "progress"; case syntaxstatetype::N: diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 895aed10..0f8c1a19 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -84,7 +84,7 @@ namespace xo { TEST_CASE("SchematikaParser-batch-def", "[reader2][SchematikaParser]") { - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag)); ArenaConfig config; @@ -98,6 +98,12 @@ namespace xo { parser.begin_batch_session(); + /** Walkthrough parsing input equivalent to: + * + * def foo : f64 = 3.141593 ; + * + **/ + { auto & result = parser.on_token(Token::def_token()); @@ -193,6 +199,9 @@ namespace xo { TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]") { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + ArenaConfig config; config.name_ = "test-arena"; config.size_ = 16 * 1024; @@ -204,16 +213,99 @@ namespace xo { parser.begin_interactive_session(); - auto & result = parser.on_token(Token::if_token()); + /** Walkthrough parsing input equivalent to: + * + * if true then 777 else "fooey" ; + * + **/ - // after begin_interactive_session, parser has toplevel exprseq - // but is still "at toplevel" in the sense of ready for input - REQUIRE(parser.has_incomplete_expr() == false); + { + auto & result = parser.on_token(Token::if_token()); - REQUIRE(result.is_error()); + log && log("after if token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); - // illegal input on token - REQUIRE(result.error_description()); + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::bool_token("true")); + + log && log("after true token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::then_token()); + + log && log("after then token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::i64_token("777")); + + log && log("after i64 token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::else_token()); + + log && log("after else token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::string_token("fooey")); + + log && log("after string token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::semicolon_token()); + + log && log("after semicolon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(!result.is_incomplete()); + } + + //REQUIRE(result.is_error()); + //// illegal input on token + //REQUIRE(result.error_description()); } } /*namespace ut*/ From f0cd32c05f3c2ac1d7e3d29eb520215ba4958b55 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 27 Jan 2026 15:50:10 -0500 Subject: [PATCH 138/342] xo-reader2: support if-then-else expressions. + detailed utest --- include/xo/tokenizer2/Token.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index cc6e13d9..38e73902 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -137,6 +137,8 @@ namespace xo { static Token lambda() { return Token(tokentype::tk_lambda); } /** token representing keyword @c if **/ static Token if_token() { return Token(tokentype::tk_if); } + /** token representing keyword @c then **/ + static Token then_token() { return Token(tokentype::tk_then); } /** token representing keyword @c else **/ static Token else_token() { return Token(tokentype::tk_else); } /** token representing keyword @c let **/ From fdf2cc84399916ea43c2803d10630d03d9546475 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 28 Jan 2026 10:57:55 -0500 Subject: [PATCH 139/342] xo-reader2 xo-expression2: + DLambdaSsm [WIP] --- CMakeLists.txt | 26 ++ idl/IPrintable_DLambdaSsm.json5 | 13 + idl/ISyntaxStateMachine_DLambdaSsm.json5 | 13 + include/xo/reader2/DDefineSsm.hpp | 2 +- include/xo/reader2/DLambdaSsm.hpp | 186 ++++++++ .../xo/reader2/ssm/IPrintable_DLambdaSsm.hpp | 62 +++ .../ssm/ISyntaxStateMachine_DLambdaSsm.hpp | 73 ++++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 4 + src/reader2/DLambdaSsm.cpp | 409 ++++++++++++++++++ src/reader2/IPrintable_DLambdaSsm.cpp | 28 ++ .../ISyntaxStateMachine_DLambdaSsm.cpp | 60 +++ src/reader2/syntaxstatetype.cpp | 2 + 13 files changed, 880 insertions(+), 1 deletion(-) create mode 100644 idl/IPrintable_DLambdaSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DLambdaSsm.json5 create mode 100644 include/xo/reader2/DLambdaSsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DLambdaSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp create mode 100644 src/reader2/DLambdaSsm.cpp create mode 100644 src/reader2/IPrintable_DLambdaSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a4124f45..5ebdf95c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,32 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-lambdassm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR LambdaSsm + INPUT idl/ISyntaxStateMachine_DLambdaSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-lambdassm + FACET_PKG xo_printable2 + FACET Printable + REPR LambdaSsm + INPUT idl/IPrintable_DLambdaSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-ifelsessm diff --git a/idl/IPrintable_DLambdaSsm.json5 b/idl/IPrintable_DLambdaSsm.json5 new file mode 100644 index 00000000..63fad901 --- /dev/null +++ b/idl/IPrintable_DLambdaSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DLambdaSsm", + using_doxygen: true, + repr: "DLambdaSsm", + doc: [ "implement APrintable for DLambdaSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DLambdaSsm.json5 b/idl/ISyntaxStateMachine_DLambdaSsm.json5 new file mode 100644 index 00000000..a24f0147 --- /dev/null +++ b/idl/ISyntaxStateMachine_DLambdaSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DLambdaSsm", + using_doxygen: true, + repr: "DLambdaSsm", + doc: [ "implement ASyntaxStateMachine for DLambdaSsm" ], +} diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 6d15c5ee..41a27b39 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -102,7 +102,7 @@ namespace xo { /** @defgroup scm-definessm-access-methods **/ ///@{ - /** identify define-expression state **/ + /** identify this nested state machine **/ defexprstatetype defstate() const noexcept { return defstate_; } ///@} diff --git a/include/xo/reader2/DLambdaSsm.hpp b/include/xo/reader2/DLambdaSsm.hpp new file mode 100644 index 00000000..bb110165 --- /dev/null +++ b/include/xo/reader2/DLambdaSsm.hpp @@ -0,0 +1,186 @@ +/** @file DLambdaSsm.hpp + * + * Author: Roland Conybeare + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include +#include +//#include + +namespace xo { + namespace scm { + class ParserStateMachine; + + /** + * @text + * + * lambda ( name(1) : type(1), ..., ) : type body-expr ; + * ^ ^ ^ ^ ^ ^ + * | | | | lm_4 lm_5 + * | | | lm_3 + * lm_0 lm_1 lm_2 + * + * lm_0 --on_lambda_token()--> lm_1 + * lm_1 --on_formal_arglist()--> lm_2 + * lm_2 --on_expr()--> lm_3 + * lm_5 --on_semicolon_token()--> (done) + * + * @endtext + **/ + enum class lambdastatetype { + invalid = -1, + + lm_0, + lm_1, + lm_2, + lm_3, + lm_4, + lm_5, + + n_lambdastatetype + }; + + extern const char * + lambdastatetype_descr(lambdastatetype x); + + inline std::ostream & + operator<< (std::ostream & os, lambdastatetype x) { + os << lambdastatetype_descr(x); + return os; + } + + /** @class DLambdaSsm + * @brief parsing state-machine for a lambda-expression + **/ + class DLambdaSsm { + public: + //using DSymbolTable = xo::scm::DSymbolTable; + using DLocalSymtab = xo::scm::DLocalSymtab; + using DArena = xo::mm::DArena; + using TypeDescr = xo::reflect::TypeDescr; + using ppindentinfo = xo::print::ppindentinfo; + + public: + /** @defgroup scm-lambdassm-ctors **/ + ///@{ + + DLambdaSsm(); + + /** create instance using memory from @p parser_mm **/ + static obj make(DArena & parser_mm); + + /** create instance using memory from @p parser_mm **/ + static DLambdaSsm * _make(DArena & parser_mm); + + ///@} + /** @defgroup scm-lambdassm-methods **/ + ///@{ + + static void start(ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-lambdassm-syntaxstatemachine-facet **/ + ///@{ + + /** identify this nested state machine **/ + syntaxstatetype ssm_type() const noexcept; + + /** text describing expected/allowed input to this ssm in current state. + * Intended to drive error messages + **/ + std::string_view get_expect_str() const noexcept; + + /** update this ssm for incoming token @p tk **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update this ssm when nested parser + * emits expression @p expr + **/ + void on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm); + + /** update this ssm when nested parser + * emits expression @p expr + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + + /** update this ssm when nested parser + * emits @p td. + **/ + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); + + /** update this ssm when nested parser + * emits @p td. + **/ + void on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm); + +#ifdef NOT_YET + virtual const char * get_expect_str() const override; + + virtual void on_lambda_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_typedescr(TypeDescr td, + parserstatemachine * p_psm) override; + virtual void on_formal_arglist(const std::vector> & argl, + parserstatemachine * p_psm) override; + virtual void on_expr(bp expr, + parserstatemachine * p_psm) override; + virtual void on_expr_with_semicolon(bp expr, + parserstatemachine * p_psm) override; + virtual void on_leftbrace_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_colon_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_semicolon_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_f64_token(const token_type & tk, + parserstatemachine * p_psm) final override; + + virtual void print(std::ostream & os) const override; + virtual bool pretty_print(const print::ppindentinfo & ppii) const override; +#endif + + ///@} + /** @defgroup scm-lambdassm-printable-facet **/ + ///@{ + + /** pretty-printing support **/ + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + + private: + /** parsing state-machine state **/ + lambdastatetype lmstate_ = lambdastatetype::lm_0; + +#ifdef NOT_YET + /** lambda environment (for formal parameters) **/ + DLocalSymtab * local_symtab_ = nullptr; + + /** explicit return type (if supplied) **/ + TypeDescr explicit_return_td_ = nullptr; + + /** lambda signature (when known) **/ + TypeDescr lambda_td_ = nullptr; +#endif + + /** body expression **/ + obj body_; + + /** parent environment **/ + obj parent_symtab_; + + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DLambdaSsm.hpp */ diff --git a/include/xo/reader2/ssm/IPrintable_DLambdaSsm.hpp b/include/xo/reader2/ssm/IPrintable_DLambdaSsm.hpp new file mode 100644 index 00000000..9d2cad26 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DLambdaSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DLambdaSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DLambdaSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DLambdaSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DLambdaSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DLambdaSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DLambdaSsm + **/ + class IPrintable_DLambdaSsm { + public: + /** @defgroup scm-printable-dlambdassm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dlambdassm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DLambdaSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp new file mode 100644 index 00000000..943400c5 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp @@ -0,0 +1,73 @@ +/** @file ISyntaxStateMachine_DLambdaSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DLambdaSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DLambdaSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DLambdaSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DLambdaSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DLambdaSsm + **/ + class ISyntaxStateMachine_DLambdaSsm { + public: + /** @defgroup scm-syntaxstatemachine-dlambdassm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dlambdassm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DLambdaSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DLambdaSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DLambdaSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DLambdaSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DLambdaSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + static void on_parsed_expression_with_semicolon(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 796743d7..074a5aec 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -33,6 +33,9 @@ namespace xo { /** handle define-expression. See @ref DDefineSsm **/ defexpr, + /** handle lambda-expression. See @ref DLambdaSsm **/ + lambdaexpr, + /** handle ifelse-expression. See @ref DIfElseSsm **/ ifelseexpr, diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 2ab9d917..99384589 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -29,6 +29,10 @@ set(SELF_SRCS ISyntaxStateMachine_DIfElseSsm.cpp IPrintable_DIfElseSsm.cpp + DLambdaSsm.cpp + ISyntaxStateMachine_DLambdaSsm.cpp + IPrintable_DLambdaSsm.cpp + DExpectSymbolSsm.cpp ISyntaxStateMachine_DExpectSymbolSsm.cpp IPrintable_DExpectSymbolSsm.cpp diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp new file mode 100644 index 00000000..ad678af8 --- /dev/null +++ b/src/reader2/DLambdaSsm.cpp @@ -0,0 +1,409 @@ +/** @file lambda_xs.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DLambdaSsm.hpp" +#include "ssm/ISyntaxStateMachine_DLambdaSsm.hpp" +#include "ParserStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include +#include +#include + +#ifdef NOT_YET +#include "define_xs.hpp" +#include "parserstatemachine.hpp" +#include "exprstatestack.hpp" +#include "expect_formal_arglist_xs.hpp" +#include "expect_expr_xs.hpp" +#include "expect_type_xs.hpp" +#include "pretty_expression.hpp" +#include "pretty_variable.hpp" +#include "xo/expression/Lambda.hpp" +#endif + +namespace xo { + using xo::print::APrintable; + using xo::facet::FacetRegistry; + using xo::reflect::typeseq; + + namespace scm { + const char * + lambdastatetype_descr(lambdastatetype x) { + switch(x) { + case lambdastatetype::invalid: return "invalid"; + case lambdastatetype::lm_0: return "lm_0"; + case lambdastatetype::lm_1: return "lm_1"; + case lambdastatetype::lm_2: return "lm_2"; + case lambdastatetype::lm_3: return "lm_3"; + case lambdastatetype::lm_4: return "lm_4"; + case lambdastatetype::lm_5: return "lm_5"; + default: break; + } + + return "???lambdastatetype"; + } + + // ----- lambda_xs - ---- + + DLambdaSsm::DLambdaSsm() + {} + + obj + DLambdaSsm::make(DArena & parser_mm) + { + return obj(_make(parser_mm)); + } + + DLambdaSsm * + DLambdaSsm::_make(DArena & parser_mm) + { + void * mem = parser_mm.alloc(typeseq::id(), + sizeof(DLambdaSsm)); + + return new (mem) DLambdaSsm(); + } + + void + DLambdaSsm::start(ParserStateMachine * p_psm) + { + p_psm->push_ssm(DLambdaSsm::make(p_psm->parser_alloc())); + p_psm->on_token(Token::lambda_token()); + } + + syntaxstatetype + DLambdaSsm::ssm_type() const noexcept + { + return syntaxstatetype::lambdaexpr; + } + + std::string_view + DLambdaSsm::get_expect_str() const noexcept + { + /* + * lambda (x : f64) : f64 { ... } ; + * ^ ^ ^ ^ ^ ^ + * | | | | | lm_5 + * | | | | lm_4:expect_expression + * | | | lm_3 + * | | lm_2 + * | lm_1: + * expect_expression + */ + switch (this->lmstate_) { + case lambdastatetype::invalid: + case lambdastatetype::n_lambdastatetype: + assert(false); // impossible + break; + case lambdastatetype::lm_0: + return "lambda"; + case lambdastatetype::lm_1: + return "lambda-params"; + case lambdastatetype::lm_2: + return "colon|lambda-body"; + case lambdastatetype::lm_3: + return "type"; + case lambdastatetype::lm_4: + return "lambda-body"; + case lambdastatetype::lm_5: + return "semicolon"; + } + + return "?expect"; + } + + void + DLambdaSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DLambdaSsm::on_token", + tk, + this->get_expect_str()); + } + +#ifdef NOT_YET + void + lambda_xs::on_lambda_token(const token_type & tk, + parserstatemachine * p_psm) + { + if (lmxs_type_ == lambdastatetype::lm_0) { + this->lmxs_type_ = lambdastatetype::lm_1; + expect_formal_arglist_xs::start(p_psm); + } else { + exprstate::on_lambda_token(tk, p_psm); + } + } + + void + lambda_xs::on_formal_arglist(const std::vector> & argl, + parserstatemachine * p_psm) + { + if (lmxs_type_ == lambdastatetype::lm_1) { + this->lmxs_type_ = lambdastatetype::lm_2; + this->parent_env_ = p_psm->top_envframe().promote(); + this->local_env_ = LocalSymtab::make(argl, parent_env_); + + p_psm->push_envframe(local_env_); + + //expect_expr_xs::start(p_psm); + } else { + exprstate::on_formal_arglist(argl, p_psm); + } + } + + void + lambda_xs::on_expr_with_semicolon(bp expr, + parserstatemachine * p_psm) + { + this->on_expr(expr, p_psm); + this->on_semicolon_token(token_type::semicolon(), p_psm); + } + + void + lambda_xs::on_colon_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr const char * c_self_name = "lambda_xs::on_colon_token"; + + if (lmxs_type_ == lambdastatetype::lm_2) { + this->lmxs_type_ = lambdastatetype::lm_3; + expect_type_xs::start(p_psm); + /* control reenters via .on_typedescr() */ + } else { + this->illegal_input_on_token(c_self_name, tk, this->get_expect_str(), p_psm); + } + } + + void + lambda_xs::on_leftbrace_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr const char * c_self_name = "lambda_xs::on_leftbrace_token"; + + if (lmxs_type_ == lambdastatetype::lm_2) + this->lmxs_type_ = lambdastatetype::lm_4; + + if (lmxs_type_ == lambdastatetype::lm_4) { + expect_expr_xs::start(p_psm); + /* want { to start expr sequence, that finishes on matching } */ + p_psm->on_leftbrace_token(token_type::leftbrace()); + } else { + this->illegal_input_on_token(c_self_name, tk, this->get_expect_str(), p_psm); + } + } +#endif + + void + DLambdaSsm::on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_typedescr("DLambdaSsm::on_parsed_typedescr", + td, + this->get_expect_str()); + } + +#ifdef NOT_YET + void + lambda_xs::on_typedescr(TypeDescr td, + parserstatemachine * p_psm) + { + constexpr const char * c_self_name = "lambda_xs::on_typedescr"; + scope log(XO_DEBUG(p_psm->debug_flag())); + + assert(td); + + if (lmxs_type_ == lambdastatetype::lm_3) { + this->lmxs_type_ = lambdastatetype::lm_4; + this->explicit_return_td_ = td; + + this->lambda_td_ = Lambda::assemble_lambda_td(local_env_->argv(), + explicit_return_td_); + + /* 1. at this point we know function signature (@ref lambda_td_) + * 2. if this lambda appears on the rhs of a define, + * propagate function signature to the define. + * 3. this makes recursive function definitions like this work + * without relying on type inference: + * def fact = lambda (n : i64) : i64 { + * if (n == 0) then + * 1 + * else + * n * fact(n - 1) + * } + * 4. while parsing the body of the lambda, we want environment + * to already associate the lambda's signature with variable 'fact', + * so that when parser encounters 'fact(n - 1)' the expression has + * known valuetype. + */ + + if ((p_psm->exprstate_stack_size() >= 3) + && (p_psm->lookup_exprstate(1).exs_type() == exprstatetype::expect_rhs_expression) + && (p_psm->lookup_exprstate(2).exs_type() == exprstatetype::defexpr) + && (p_psm->env_stack_size() >= 2) + ) + { + const define_xs * def_xs = dynamic_cast(&(p_psm->lookup_exprstate(2))); + + assert(def_xs); + + bp def_var = def_xs->lhs_variable(); + + if (def_var->valuetype() == nullptr) { + log && log("assign discovered lambda type T to enclosing define", + xtag("lhs", def_var.get()), + xtag("T", print::unq(this->lambda_td_->canonical_name()))); + + def_var->assign_valuetype(lambda_td_); + } else { + /* don't need to unify here. if def already hasa a type, + * that's because it was explicitly specified. + * will discover any conflict after reporting parsed lambda + * to define_xs + */ + } + } + + expect_expr_xs::start(p_psm); + /* control reenters via .on_expr() or .on_expr_with_semicolon() */ + } else { + this->illegal_input_on_type(c_self_name, td, this->get_expect_str(), p_psm); + } + } +#endif + + void + DLambdaSsm::on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol("DLambdaSsm::on_parsed_sybol", + sym, + this->get_expect_str()); + } + + void + DLambdaSsm::on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression + ("DLambdaSsm::on_parsed_expression_with_semicolon", + expr, + this->get_expect_str()); + } + + void + DLambdaSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DLambdaSsm::on_parsed_expression", + expr, + this->get_expect_str()); + } + +#ifdef NOT_YET + void + lambda_xs::on_expr(bp expr, + parserstatemachine * p_psm) + { + constexpr const char * c_self_name = "lambda_xs::on_expr"; + + if (lmxs_type_ == lambdastatetype::lm_4) { + this->lmxs_type_ = lambdastatetype::lm_5; + this->body_ = expr.promote(); + } else { + this->illegal_input_on_expr(c_self_name, expr, this->get_expect_str(), p_psm); + } + } + + void + lambda_xs::on_semicolon_token(const token_type & tk, + parserstatemachine * p_psm) + { + if (lmxs_type_ == lambdastatetype::lm_5) { + /* done! */ + + std::unique_ptr self = p_psm->pop_exprstate(); + + std::string name = Variable::gensym("lambda"); + + /* top env frame recorded arguments to this lambda */ + p_psm->pop_envframe(); + + rp lm; + + /* TODO: unify explicit_return_td_ with body_ */ + + if (lambda_td_) { + lm = Lambda::make(name, lambda_td_, local_env_, body_); + } else { + lm = Lambda::make_from_env(name, local_env_, + explicit_return_td_, body_); + } + + p_psm->top_exprstate().on_expr(lm, p_psm); + p_psm->top_exprstate().on_semicolon_token(tk, p_psm); + + return; + } + + exprstate::on_semicolon_token(tk, p_psm); + } + + void + lambda_xs::on_f64_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr const char * c_self_name = "lambda_xs::on_f64_token"; + + /* f64 literal can begin lambda body, otherwise illegal. + * for example: + * def foo = lambda (x: bool) 3.14; + */ + if (lmxs_type_ == lambdastatetype::lm_2) { + /* omitting return type. + * omitting left brace. + */ + this->lmxs_type_ = lambdastatetype::lm_4; + + expect_expr_xs::start(p_psm); + p_psm->on_f64_token(tk); + } else { + this->illegal_input_on_token(c_self_name, tk, this->get_expect_str(), p_psm); + } + } + + // TODO: on_i64_token, on_bool token + + void + lambda_xs::print(std::ostream & os) const { + os << ""; + } +#endif + + bool + DLambdaSsm::pretty(const ppindentinfo & ppii) const + { + obj body + = FacetRegistry::instance().variant(body_); + + if (body) { + return ppii.pps()->pretty_struct + (ppii, + "DLambdaSsm", + refrtag("lmstate", lmstate_), + refrtag("body", body)); + } else { + return ppii.pps()->pretty_struct + (ppii, + "DLambdaSsm", + refrtag("lmstate", lmstate_)); + } + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DLambdaSsm.cpp */ diff --git a/src/reader2/IPrintable_DLambdaSsm.cpp b/src/reader2/IPrintable_DLambdaSsm.cpp new file mode 100644 index 00000000..6cf5b29a --- /dev/null +++ b/src/reader2/IPrintable_DLambdaSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DLambdaSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DLambdaSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DLambdaSsm.json5] +**/ + +#include "ssm/IPrintable_DLambdaSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DLambdaSsm::pretty(const DLambdaSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DLambdaSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp new file mode 100644 index 00000000..ac4b2d14 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp @@ -0,0 +1,60 @@ +/** @file ISyntaxStateMachine_DLambdaSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DLambdaSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DLambdaSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DLambdaSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DLambdaSsm::ssm_type(const DLambdaSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DLambdaSsm::get_expect_str(const DLambdaSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DLambdaSsm::on_token(DLambdaSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + + auto + ISyntaxStateMachine_DLambdaSsm::on_parsed_symbol(DLambdaSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DLambdaSsm::on_parsed_typedescr(DLambdaSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DLambdaSsm::on_parsed_expression(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DLambdaSsm::on_parsed_expression_with_semicolon(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_semicolon(expr, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DLambdaSsm.cpp */ diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index 1100bdb3..c03667c4 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -23,6 +23,8 @@ namespace xo { return "expect-rhs-expression"; case syntaxstatetype::defexpr: return "defexpr"; + case syntaxstatetype::lambdaexpr: + return "lambdaexpr"; case syntaxstatetype::ifelseexpr: return "ifelseexpr"; case syntaxstatetype::progress: From a28b45e4f2c51d7df9b1397666e9d1d6db808d5d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 28 Jan 2026 10:57:55 -0500 Subject: [PATCH 140/342] xo-reader2 xo-expression2: + DLambdaSsm [WIP] --- include/xo/tokenizer2/Token.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index 38e73902..f9807d05 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -134,7 +134,7 @@ namespace xo { /** token representing keyword @c def **/ static Token def_token() { return Token(tokentype::tk_def); } /** token representing keyword @c lambda **/ - static Token lambda() { return Token(tokentype::tk_lambda); } + static Token lambda_token() { return Token(tokentype::tk_lambda); } /** token representing keyword @c if **/ static Token if_token() { return Token(tokentype::tk_if); } /** token representing keyword @c then **/ From 254d7c179dafc5cc12e12e486ad81b1fadbf2b19 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 28 Jan 2026 15:31:52 -0500 Subject: [PATCH 141/342] xo-reader2: + DExpectFormalArglistSsm [WIP] --- CMakeLists.txt | 26 ++ idl/IPrintable_DExpectFormalArglistSsm.json5 | 13 + ...StateMachine_DExpectFormalArglistSsm.json5 | 13 + .../xo/reader2/DExpectFormalArglistSsm.hpp | 146 +++++++++++ include/xo/reader2/DExprSeqState.hpp | 5 + include/xo/reader2/DLambdaSsm.hpp | 9 +- .../IPrintable_DExpectFormalArglistSsm.hpp | 62 +++++ ...axStateMachine_DExpectFormalArglistSsm.hpp | 73 ++++++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 4 + src/reader2/DExpectFormalArglistSsm.cpp | 227 ++++++++++++++++++ src/reader2/DExprSeqState.cpp | 36 ++- src/reader2/DLambdaSsm.cpp | 73 +++++- .../IPrintable_DExpectFormalArglistSsm.cpp | 28 +++ ...axStateMachine_DExpectFormalArglistSsm.cpp | 59 +++++ src/reader2/reader2_register_facets.cpp | 15 ++ src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 113 +++++++++ 18 files changed, 899 insertions(+), 8 deletions(-) create mode 100644 idl/IPrintable_DExpectFormalArglistSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 create mode 100644 include/xo/reader2/DExpectFormalArglistSsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DExpectFormalArglistSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp create mode 100644 src/reader2/DExpectFormalArglistSsm.cpp create mode 100644 src/reader2/IPrintable_DExpectFormalArglistSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ebdf95c..a1028a18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,6 +112,32 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expectformalarglistssm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ExpectFormalArglistSsm + INPUT idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expectformalarglistssm + FACET_PKG xo_printable2 + FACET Printable + REPR ExpectFormalArglistSsm + INPUT idl/IPrintable_DExpectFormalArglistSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-ifelsessm diff --git a/idl/IPrintable_DExpectFormalArglistSsm.json5 b/idl/IPrintable_DExpectFormalArglistSsm.json5 new file mode 100644 index 00000000..44f474dd --- /dev/null +++ b/idl/IPrintable_DExpectFormalArglistSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectFormalArglistSsm", + using_doxygen: true, + repr: "DExpectFormalArglistSsm", + doc: [ "implement APrintable for DExpectFormalArglistSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 b/idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 new file mode 100644 index 00000000..d3e16953 --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectFormalArglistSsm", + using_doxygen: true, + repr: "DExpectFormalArglistSsm", + doc: [ "implement ASyntaxStateMachine for DExpectFormalArglistSsm" ], +} diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp new file mode 100644 index 00000000..5b32c760 --- /dev/null +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -0,0 +1,146 @@ +/** @file DExpectFormalArglistSsm.hpp + * + * @author Roland Conybeare, Aug 2024 + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include +#include + +#ifdef NOT_YET +#include "exprstate.hpp" +#include "formal_arg.hpp" +#include +#endif + +namespace xo { + namespace scm { + /** + * ( name(1) : type(1) , ..., ) + * ^ ^ ^ ^ ^ + * | | | | | + * | | | | argl_1b + * | argl_1a | argl_1a + * argl_0 argl_1b + * + * argl_0 --on_leftparen_token()--> argl_1a + * argl_1a --on_formal()--> argl_1b + * argl_1b -+-on_comma_token()--> argl_1a + * \-on_rightparen_token()--> (done) + **/ + enum class formalarglstatetype { + invalid = -1, + + argl_0, + argl_1a, + argl_1b, + + n_formalarglstatetype, + }; + + extern const char * + formalarglstatetype_descr(formalarglstatetype x); + + inline std::ostream & + operator<< (std::ostream & os, formalarglstatetype x) { + os << formalarglstatetype_descr(x); + return os; + } + + /** @class expect_formal_arglist + * @brief parser state-machine for a formal parameter list + **/ + class DExpectFormalArglistSsm { + public: + using DArena = xo::mm::DArena; + using TypeDescr = xo::reflect::TypeDescr; + using ppindentinfo = xo::print::ppindentinfo; + using size_type = std::uint32_t; + + public: + DExpectFormalArglistSsm(DArray * argl); + + /** create instance, using memory from @parser_mm **/ + static obj make(DArena & parser_mm); + static DExpectFormalArglistSsm * _make(DArena & parser_mm); + + static void start(ParserStateMachine * p_psm); + + /** @defgroup scm-expectformalarglistssm-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + std::string_view get_expect_str() const; + + /** update state on incoming token @p tk, + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on parsed symbol @p sym emitted by nested ssm, + * with overall parser state in @p p_psm + **/ + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); + + /** update state on parsed typedescr @p td emitted by nested ssm, + * with overall parser state in @p p_psm + **/ + void on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm); + + /** update state on parsed expression emitted by nested ssm + * with overall parser state in @p p_psm + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + + /** update state on parsed expression, along with following semicolon, + * emitted by nested ssm with overall parser state in @p p_psm + **/ + void on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm); + +#ifdef NOT_YET + + virtual void on_leftparen_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_formal(const rp & formal, + parserstatemachine * p_psm) override; + virtual void on_comma_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) override; +#endif + + ///@} + /** @defgroup scm-expectformalarglistssm-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + /** parsing state-machine state **/ + formalarglstatetype fastate_ = formalarglstatetype::argl_0; + /** number of formal parameters encountered. + * Invariant: n_args_ <= argl_->size() + **/ + size_type n_args_ = 0; + /** populate with (parmaeter-name, parameter-type) list + * as they're encountered. + * + * Not using flexible array here since we don't know size + **/ + DArray * argl_ = nullptr; + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectFormalArglistSsm.hpp */ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 72566004..96eea236 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -81,6 +81,11 @@ namespace xo { **/ void on_def_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming lamdba token @p tk, + * overall parser state in @p p_psm + **/ + void on_lambda_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DLambdaSsm.hpp b/include/xo/reader2/DLambdaSsm.hpp index bb110165..d9b0754d 100644 --- a/include/xo/reader2/DLambdaSsm.hpp +++ b/include/xo/reader2/DLambdaSsm.hpp @@ -59,6 +59,7 @@ namespace xo { public: //using DSymbolTable = xo::scm::DSymbolTable; using DLocalSymtab = xo::scm::DLocalSymtab; + using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; using ppindentinfo = xo::print::ppindentinfo; @@ -81,6 +82,12 @@ namespace xo { static void start(ParserStateMachine * p_psm); + /** update ssm on lambda keyword token @p tk, + * with overall parser state in @p p_psm + **/ + void on_lambda_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-lambdassm-syntaxstatemachine-facet **/ ///@{ @@ -124,8 +131,6 @@ namespace xo { #ifdef NOT_YET virtual const char * get_expect_str() const override; - virtual void on_lambda_token(const token_type & tk, - parserstatemachine * p_psm) override; virtual void on_typedescr(TypeDescr td, parserstatemachine * p_psm) override; virtual void on_formal_arglist(const std::vector> & argl, diff --git a/include/xo/reader2/ssm/IPrintable_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectFormalArglistSsm.hpp new file mode 100644 index 00000000..7b5479b7 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DExpectFormalArglistSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectFormalArglistSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectFormalArglistSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectFormalArglistSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectFormalArglistSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectFormalArglistSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectFormalArglistSsm + **/ + class IPrintable_DExpectFormalArglistSsm { + public: + /** @defgroup scm-printable-dexpectformalarglistssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpectformalarglistssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectFormalArglistSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp new file mode 100644 index 00000000..93154f83 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp @@ -0,0 +1,73 @@ +/** @file ISyntaxStateMachine_DExpectFormalArglistSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectFormalArglistSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectFormalArglistSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectFormalArglistSsm + **/ + class ISyntaxStateMachine_DExpectFormalArglistSsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpectformalarglistssm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexpectformalarglistssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectFormalArglistSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectFormalArglistSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectFormalArglistSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectFormalArglistSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectFormalArglistSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + static void on_parsed_expression_with_semicolon(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 074a5aec..2eb34122 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -21,6 +21,9 @@ namespace xo { /** toplevel of some translation unit. See @ref DExprSeqState **/ expect_toplevel_expression_sequence, + /** expecting a formal argument list (sub-syntax within lambda-expression) **/ + expect_formal_arglist, + /** expecting a s symbol. See @ref DExpectSymbolSsm **/ expect_symbol, diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 99384589..949af024 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -33,6 +33,10 @@ set(SELF_SRCS ISyntaxStateMachine_DLambdaSsm.cpp IPrintable_DLambdaSsm.cpp + DExpectFormalArglistSsm.cpp + ISyntaxStateMachine_DExpectFormalArglistSsm.cpp + IPrintable_DExpectFormalArglistSsm.cpp + DExpectSymbolSsm.cpp ISyntaxStateMachine_DExpectSymbolSsm.cpp IPrintable_DExpectSymbolSsm.cpp diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp new file mode 100644 index 00000000..c7d3fffd --- /dev/null +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -0,0 +1,227 @@ +/* @file DExpectFormalArglistSsm.cpp + * + * @author Roland Conybeare, Jan 2026 + */ + +#include "DExpectFormalArglistSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" +#include + +#ifdef NOT_YET +#include "parserstatemachine.hpp" +#include "exprstatestack.hpp" +#include "expect_formal_xs.hpp" +#include "expect_symbol_xs.hpp" +#include "xo/expression/Variable.hpp" +#include "xo/indentlog/print/vector.hpp" +#endif + +namespace xo { + using xo::mm::AAllocator; + using xo::print::ppindentinfo; + using xo::reflect::typeseq; + + namespace scm { + const char * + formalarglstatetype_descr(formalarglstatetype x) { + switch (x) { + case formalarglstatetype::invalid: + return "invalid"; + case formalarglstatetype::argl_0: + return "argl_0"; + case formalarglstatetype::argl_1a: + return "argl_1a"; + case formalarglstatetype::argl_1b: + return "argl_1b"; + case formalarglstatetype::n_formalarglstatetype: + break; + } + + return "?formalarglstatetype"; + } + + DExpectFormalArglistSsm::DExpectFormalArglistSsm(DArray * argl) : argl_{argl} + {} + + DExpectFormalArglistSsm * + DExpectFormalArglistSsm::_make(DArena & arena) + { + obj mm(&arena); + + /* out-of-order so argl follows ssm in arena, + * consistent with any subsequent arglist realloc. + * Not a load-bearing choice however + */ + + void * mem = arena.alloc(typeseq::id(), + sizeof(DExpectFormalArglistSsm)); + + + /* allocate room for 8 arguments (during parsing) + * will re-alloc to expand as needed + */ + DArray * argl = DArray::empty(mm, 8); + + return new (mem) DExpectFormalArglistSsm(argl); + } + + obj + DExpectFormalArglistSsm::make(DArena & arena) + { + obj retval(_make(arena)); + + return retval; + } + + void + DExpectFormalArglistSsm::start(ParserStateMachine * p_psm) + { + p_psm->push_ssm(DExpectFormalArglistSsm::make(p_psm->parser_alloc())); + } + + syntaxstatetype + DExpectFormalArglistSsm::ssm_type() const noexcept { + return syntaxstatetype::expect_formal_arglist; + } + + std::string_view + DExpectFormalArglistSsm::get_expect_str() const { + switch (fastate_) { + case formalarglstatetype::invalid: + case formalarglstatetype::n_formalarglstatetype: + assert(false); // impossible + break; + case formalarglstatetype::argl_0: + return "leftparen"; + case formalarglstatetype::argl_1a: + return "formal-name"; + case formalarglstatetype::argl_1b: + return "comma|rightparen"; + } + + return "?expect"; + } + + void + DExpectFormalArglistSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token("DExpectFormalArglistSsm::on_token", + tk, + this->get_expect_str()); + } + + void + DExpectFormalArglistSsm::on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol("DExpectFormalArglistSsm::on_parsed_symbol", + sym, + this->get_expect_str()); + } + + void + DExpectFormalArglistSsm::on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_typedescr("DExpectFormalArglistSsm::on_parsed_typedescr", + td, + this->get_expect_str()); + } + + void + DExpectFormalArglistSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DExpectFormalArglistSsm::on_parsed_expression", + expr, + this->get_expect_str()); + } + + void + DExpectFormalArglistSsm::on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DExpectFormalArglistSsm::on_parsed_expression_with_semicolon", + expr, + this->get_expect_str()); + } + +#ifdef NOT_YET + expect_formal_arglist_xs::expect_formal_arglist_xs() + : exprstate(exprstatetype::expect_formal_arglist), + farglxs_type_{formalarglstatetype::argl_0} + {} + + void + expect_formal_arglist_xs::on_leftparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + if (farglxs_type_ == formalarglstatetype::argl_0) { + this->farglxs_type_ = formalarglstatetype::argl_1a; + /* TODO: refactor to have setup method on each exprstate */ + expect_formal_xs::start(p_psm); + } else { + exprstate::on_leftparen_token(tk, p_psm); + } + } + + void + expect_formal_arglist_xs::on_formal(const rp & formal, + parserstatemachine * p_psm) + { + if (farglxs_type_ == formalarglstatetype::argl_1a) { + this->farglxs_type_ = formalarglstatetype::argl_1b; + this->argl_.push_back(formal); + } else { + exprstate::on_formal(formal, p_psm); + } + } + + void + expect_formal_arglist_xs::on_comma_token(const token_type & tk, + parserstatemachine * p_psm) + { + if (farglxs_type_ == formalarglstatetype::argl_1b) { + this->farglxs_type_ = formalarglstatetype::argl_1a; + expect_formal_xs::start(p_psm); + } else { + exprstate::on_comma_token(tk, p_psm); + } + } + + void + expect_formal_arglist_xs::on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + if (farglxs_type_ == formalarglstatetype::argl_1b) { + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->top_exprstate().on_formal_arglist(this->argl_, p_psm); + } else { + exprstate::on_rightparen_token(tk, p_psm); + } + } + + void + expect_formal_arglist_xs::print(std::ostream & os) const { + os << ""; + } +#endif + + bool + DExpectFormalArglistSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, + "DExpectFormalArglistSsm"); + } + + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end DExpectFormalArglistSsm.cpp */ diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index cfd92683..28c62354 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -4,10 +4,12 @@ **/ #include "DExprSeqState.hpp" -#include "DDefineSsm.hpp" #include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" -#include -#include +#include "DDefineSsm.hpp" +#include "DLambdaSsm.hpp" +#include "DProgressSsm.hpp" +#include "DIfElseSsm.hpp" + #include #include #include @@ -121,6 +123,10 @@ namespace xo { this->on_def_token(tk, p_psm); return; + case tokentype::tk_lambda: + this->on_lambda_token(tk, p_psm); + return; + case tokentype::tk_if: this->on_if_token(tk, p_psm); return; @@ -177,7 +183,6 @@ namespace xo { case tokentype::tk_cmpeq: case tokentype::tk_cmpne: case tokentype::tk_type: - case tokentype::tk_lambda: case tokentype::tk_then: case tokentype::tk_else: case tokentype::tk_let: @@ -241,6 +246,29 @@ namespace xo { */ } + void + DExprSeqState::on_lambda_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + switch (seqtype_) { + case exprseqtype::toplevel_interactive: + DLambdaSsm::start(p_psm); + return; + case exprseqtype::toplevel_batch: + /* lambda not allowed at top-level in batch mode */ + break; + case exprseqtype::N: + assert(false); // unreachable + break; + } + + p_psm->illegal_input_on_token("DExprSeqState::on_lambda_token", + tk, + this->get_expect_str()); + } + void DExprSeqState::on_if_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index ad678af8..a7db6e11 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -5,6 +5,8 @@ #include "DLambdaSsm.hpp" #include "ssm/ISyntaxStateMachine_DLambdaSsm.hpp" +#include "DExpectFormalArglistSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" #include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" #include @@ -25,6 +27,7 @@ namespace xo { using xo::print::APrintable; + using xo::mm::AAllocator; using xo::facet::FacetRegistry; using xo::reflect::typeseq; @@ -117,11 +120,77 @@ namespace xo { DLambdaSsm::on_token(const Token & tk, ParserStateMachine * p_psm) { + switch (tk.tk_type()) { + case tokentype::tk_lambda: + this->on_lambda_token(tk, p_psm); + return; + + // all the not-yet-handled cases + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_symbol: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + p_psm->illegal_input_on_token("DLambdaSsm::on_token", tk, this->get_expect_str()); } + void + DLambdaSsm::on_lambda_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (lmstate_ == lambdastatetype::lm_0) { + this->lmstate_ = lambdastatetype::lm_1; + + DExpectFormalArglistSsm::start(p_psm); + + return; + } + + p_psm->illegal_input_on_token("DLambdaSsm::on_lambda_token", + tk, + this->get_expect_str()); + } + + #ifdef NOT_YET void lambda_xs::on_lambda_token(const token_type & tk, @@ -386,8 +455,8 @@ namespace xo { DLambdaSsm::pretty(const ppindentinfo & ppii) const { obj body - = FacetRegistry::instance().variant(body_); + = FacetRegistry::instance().try_variant(body_); if (body) { return ppii.pps()->pretty_struct diff --git a/src/reader2/IPrintable_DExpectFormalArglistSsm.cpp b/src/reader2/IPrintable_DExpectFormalArglistSsm.cpp new file mode 100644 index 00000000..d5df450d --- /dev/null +++ b/src/reader2/IPrintable_DExpectFormalArglistSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectFormalArglistSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectFormalArglistSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectFormalArglistSsm.json5] +**/ + +#include "ssm/IPrintable_DExpectFormalArglistSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectFormalArglistSsm::pretty(const DExpectFormalArglistSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectFormalArglistSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp new file mode 100644 index 00000000..91738110 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp @@ -0,0 +1,59 @@ +/** @file ISyntaxStateMachine_DExpectFormalArglistSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectFormalArglistSsm::ssm_type(const DExpectFormalArglistSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectFormalArglistSsm::get_expect_str(const DExpectFormalArglistSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectFormalArglistSsm::on_token(DExpectFormalArglistSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_symbol(DExpectFormalArglistSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_typedescr(DExpectFormalArglistSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_expression(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_expression_with_semicolon(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_semicolon(expr, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectFormalArglistSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 712f5998..1cb37de9 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -11,9 +11,15 @@ #include #include +#include +#include + #include #include +#include +#include + #include #include @@ -48,9 +54,15 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); @@ -65,11 +77,14 @@ namespace xo { log && log(xtag("DExprSeqState.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); + log && log(xtag("DLambdaSsm.tseq", typeseq::id())); log && log(xtag("DIfElseSsm.tseq", typeseq::id())); + log && log(xtag("DExpectFormalArglistSsm.tseq", typeseq::id())); log && log(xtag("DExpectSymbolSsm.tseq", typeseq::id())); log && log(xtag("DExpectTypeSsm.tseq", typeseq::id())); log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); log && log(xtag("DProgressSsm.tseq", typeseq::id())); + log && log(xtag("ASyntaxStateMachine.tseq", typeseq::id())); return true; } diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index c03667c4..7a2ece4c 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -15,6 +15,8 @@ namespace xo { break; case syntaxstatetype::expect_toplevel_expression_sequence: return "expect-toplevel-expression-sequence"; + case syntaxstatetype::expect_formal_arglist: + return "expect-formal-arglist"; case syntaxstatetype::expect_symbol: return "expect-symbol"; case syntaxstatetype::expect_type: diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 0f8c1a19..5b6124a9 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -197,6 +197,119 @@ namespace xo { //REQUIRE(result.error_description()); } + TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]") + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * lambda ; + * + **/ + + { + auto & result = parser.on_token(Token::lambda_token()); + + log && log("after lambda token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + +#ifdef NOT_YET + { + auto & result = parser.on_token(Token::bool_token("true")); + + log && log("after true token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::then_token()); + + log && log("after then token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::i64_token("777")); + + log && log("after i64 token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::else_token()); + + log && log("after else token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::string_token("fooey")); + + log && log("after string token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::semicolon_token()); + + log && log("after semicolon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(!result.is_incomplete()); + } +#endif + + //REQUIRE(result.is_error()); + //// illegal input on token + //REQUIRE(result.error_description()); + } + TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]") { constexpr bool c_debug_flag = true; From 66158551c77fec49ae2bd4d21e2d6f9554a76e21 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 28 Jan 2026 17:40:57 -0500 Subject: [PATCH 142/342] xo-reader2: + DExpectFormalArgSsm [WIP] --- CMakeLists.txt | 14 ++ ...ntaxStateMachine_DExpectFormalArgSsm.json5 | 13 + include/xo/reader2/DExpectFormalArgSsm.hpp | 139 +++++++++++ .../xo/reader2/DExpectFormalArglistSsm.hpp | 11 +- ...SyntaxStateMachine_DExpectFormalArgSsm.hpp | 73 ++++++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 4 + src/reader2/DExpectFormalArgSsm.cpp | 235 ++++++++++++++++++ src/reader2/DExpectFormalArglistSsm.cpp | 136 +++++++++- ...SyntaxStateMachine_DExpectFormalArgSsm.cpp | 59 +++++ src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 6 +- 12 files changed, 679 insertions(+), 16 deletions(-) create mode 100644 idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 create mode 100644 include/xo/reader2/DExpectFormalArgSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp create mode 100644 src/reader2/DExpectFormalArgSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a1028a18..1f6b9d75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,6 +138,20 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expectformalargssm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ExpectFormalArgSsm + INPUT idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-ifelsessm diff --git a/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 b/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 new file mode 100644 index 00000000..4b83866e --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectFormalArgSsm", + using_doxygen: true, + repr: "DExpectFormalArgSsm", + doc: [ "implement ASyntaxStateMachine for DExpectFormalArgSsm" ], +} diff --git a/include/xo/reader2/DExpectFormalArgSsm.hpp b/include/xo/reader2/DExpectFormalArgSsm.hpp new file mode 100644 index 00000000..3c913b90 --- /dev/null +++ b/include/xo/reader2/DExpectFormalArgSsm.hpp @@ -0,0 +1,139 @@ +/** @file DExpectFormalSsm.hpp + * + * @author Roland Conybeare, Aug 2024 + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +//#include +//#include "exprstate.hpp" + +namespace xo { + namespace scm { + /** + * name : type + * ^ ^ ^ + * | | formal_2 + * | formal_1 + * formal_0 + * + * formal_0 --on_symbol()--> formal_1 + * formal_1 --on_colon_token()--> formal_2 + * formal_2 --on_typedescr()--> (done) + **/ + enum class formalstatetype { + invalid = -1, + + formal_0, + formal_1, + formal_2, + + n_formalstatetype, + }; + + extern const char * + formalstatetype_descr(formalstatetype x); + + inline std::ostream & + operator<< (std::ostream & os, formalstatetype x) { + os << formalstatetype_descr(x); + return os; + } + + /** @class expect_formal_xs + * @brief parser state-machine for a typed formal parameter + **/ + class DExpectFormalArgSsm { + public: + using TypeDescr = xo::reflect::TypeDescr; + using DArena = xo::mm::DArena; + + public: + DExpectFormalArgSsm(); + + /** create empty instance using memory from @p mm **/ + DExpectFormalArgSsm * _make(DArena & mm); + + static void start(ParserStateMachine * p_psm); + + /** @defgroup scm-expectformalargssm-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** mnemonic for expected input (for this ssm) in current state **/ + std::string_view get_expect_str() const noexcept; + + /** update state on incoming token @p tk, + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on parsed symbol @p sym emitted by nested ssm, + * with overall parser state in @p p_psm + **/ + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); + + /** update state on parsed typedescr @p td emitted by nested ssm, + * with overall parser state in @p p_psm + **/ + void on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm); + + /** update state on parsed expression emitted by nested ssm + * with overall parser state in @p p_psm + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + + /** update state on parsed expression, along with following semicolon, + * emitted by nested ssm with overall parser state in @p p_psm + **/ + void on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm); + + ///@} + +#ifdef NOT_YET + + virtual void on_symbol(const std::string & symbol_name, + parserstatemachine * p_psm) override; + + virtual void on_colon_token(const token_type & tk, + parserstatemachine * p_psm) override; + + // virtual void on_comma_token(...) override; + +#ifdef PROBABLY_NOT + virtual void on_rightparen_token(const token_type & tk, + exprstatestack * p_stack, + rp * p_emit_expr) override; +#endif + + virtual void on_typedescr(TypeDescr td, + parserstatemachine * p_psm) override; + + virtual void print(std::ostream & os) const override; + + private: + static std::unique_ptr make(); +#endif + + private: + /** parsing state-machine state **/ + formalstatetype fstate_ = formalstatetype::formal_0; + + /** formal parameter name **/ + const DUniqueString * name_ = nullptr; + + /** formal parameter type (if specified) **/ + TypeDescr td_ = nullptr; + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectFormalArgSsm.hpp */ diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index 5b32c760..c9cd2ac5 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -68,12 +68,21 @@ namespace xo { static void start(ParserStateMachine * p_psm); + /** @defgroup scm-expectformalarglistssm-methods general methods **/ + ///@{ + + /** update state on incoming token @p tk, with overall parser state in @p psm **/ + void on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} /** @defgroup scm-expectformalarglistssm-ssm-facet syntaxstatemachine facet methods **/ ///@{ /** identifies the ssm implemented here **/ syntaxstatetype ssm_type() const noexcept; + /** mnemonic for expected input (for this ssm) in current state **/ std::string_view get_expect_str() const; /** update state on incoming token @p tk, @@ -108,8 +117,6 @@ namespace xo { #ifdef NOT_YET - virtual void on_leftparen_token(const token_type & tk, - parserstatemachine * p_psm) override; virtual void on_formal(const rp & formal, parserstatemachine * p_psm) override; virtual void on_comma_token(const token_type & tk, diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp new file mode 100644 index 00000000..39d19b05 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp @@ -0,0 +1,73 @@ +/** @file ISyntaxStateMachine_DExpectFormalArgSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectFormalArgSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectFormalArgSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectFormalArgSsm + **/ + class ISyntaxStateMachine_DExpectFormalArgSsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpectformalargssm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexpectformalargssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectFormalArgSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectFormalArgSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectFormalArgSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectFormalArgSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectFormalArgSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + static void on_parsed_expression_with_semicolon(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 2eb34122..2d87aa25 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -24,6 +24,9 @@ namespace xo { /** expecting a formal argument list (sub-syntax within lambda-expression) **/ expect_formal_arglist, + /** expecting a formal argument (sub-syntax within formal-arglist) **/ + expect_formal_arg, + /** expecting a s symbol. See @ref DExpectSymbolSsm **/ expect_symbol, diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 949af024..49be467b 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -37,6 +37,10 @@ set(SELF_SRCS ISyntaxStateMachine_DExpectFormalArglistSsm.cpp IPrintable_DExpectFormalArglistSsm.cpp + DExpectFormalArgSsm.cpp + ISyntaxStateMachine_DExpectFormalArgSsm.cpp + # IPrintable_DExpectFormalArgSsm.cpp + DExpectSymbolSsm.cpp ISyntaxStateMachine_DExpectSymbolSsm.cpp IPrintable_DExpectSymbolSsm.cpp diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp new file mode 100644 index 00000000..31a26888 --- /dev/null +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -0,0 +1,235 @@ +/** @file DExpectFormalArgSsm.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DExpectFormalArgSsm.hpp" + +#ifdef NOT_YET +#include "expect_symbol_xs.hpp" +#include "expect_type_xs.hpp" +#include "parserstatemachine.hpp" +#include "exprstatestack.hpp" +#include "xo/expression/Variable.hpp" +#endif + +namespace xo { + using xo::scm::DVariable; + using xo::reflect::TypeDescr; + using xo::facet::typeseq; + + namespace scm { + const char * + formalstatetype_descr(formalstatetype x) { + switch (x) { + case formalstatetype::invalid: + case formalstatetype::n_formalstatetype: + return "?formalstatetype"; + case formalstatetype::formal_0: + return "formal_0"; + case formalstatetype::formal_1: + return "formal_1"; + case formalstatetype::formal_2: + return "formal_2"; + } + + return "???formalstatetype"; + } + + DExpectFormalArgSsm::DExpectFormalArgSsm() = default; + + DExpectFormalArgSsm * + DExpectFormalArgSsm::_make(DArena & mm) + { + void * mem = mm.alloc(typeseq::id(), sizeof(DExpectFormalArgSsm)); + + return new (mem) DExpectFormalArgSsm(); + } + + syntaxstatetype + DExpectFormalArgSsm::ssm_type() const noexcept { + return syntaxstatetype::expect_formal_arg; + } + + std::string_view + DExpectFormalArgSsm::get_expect_str() const noexcept + { + switch(fstate_) { + case formalstatetype::invalid: + case formalstatetype::n_formalstatetype: + break; + case formalstatetype::formal_0: + return "formal-name"; + case formalstatetype::formal_1: + return "colon|typename"; + case formalstatetype::formal_2: + return "typename"; + } + + return "?expect"; + } + + /** update state on incoming token @p tk, + * with overall parser state in @p p_psm + **/ + void + DExpectFormalArgSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (tk.tk_type()) { + // all the not-yet-handled cases + case tokentype::tk_leftparen: + case tokentype::tk_lambda: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_symbol: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + p_psm->illegal_input_on_token("DExpectFormalArgSsm::on_token", + tk, + this->get_expect_str()); + } + + void + DExpectFormalArgSsm::on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol("DExpectFormalArgSsm::on_parsed_symbol", + sym, + this->get_expect_str()); + } + + void + DExpectFormalArgSsm::on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_typedescr("DExpectFormalArgSsm::on_parsed_typedescr", + td, + this->get_expect_str()); + } + + void + DExpectFormalArgSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DExpectFormalArgSsm::on_parsed_expression", + expr, + this->get_expect_str()); + } + + void + DExpectFormalArgSsm::on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression("DExpectFormalArgSsm::on_parsed_expression_with_semicolon", + expr, + this->get_expect_str()); + } +#ifdef NOT_YET + void + DExpectFormalSsm::start(ParserStateMachine * p_psm) { + p_psm->push_exprstate(expect_formal_xs::make()); + + expect_symbol_xs::start(p_psm); + } + + expect_formal_xs::expect_formal_xs() + : exprstate(exprstatetype::expect_formal) + {} + + void + expect_formal_xs::on_symbol(const std::string & symbol_name, + parserstatemachine * p_psm) + { + if (this->formalxs_type_ == formalstatetype::formal_0) { + this->formalxs_type_ = formalstatetype::formal_1; + this->result_.assign_name(symbol_name); + } else { + exprstate::on_symbol(symbol_name, p_psm); + } + } + + void + expect_formal_xs::on_colon_token(const token_type & tk, + parserstatemachine * p_psm) + { + if (this->formalxs_type_ == formalstatetype::formal_1) { + this->formalxs_type_ = formalstatetype::formal_2; + expect_type_xs::start(p_psm); + /* control reenters via expect_formal_xs::on_typedescr() */ + } else { + exprstate::on_colon_token(tk, + p_psm); + } + } + + void + expect_formal_xs::on_typedescr(TypeDescr td, + parserstatemachine * p_psm) + { + if (this->formalxs_type_ == formalstatetype::formal_2) { + this->result_.assign_td(td); + + std::unique_ptr self = p_psm->pop_exprstate(); + + rp var = Variable::make(result_.name(), + result_.td()); + + p_psm->top_exprstate().on_formal(var, p_psm); + } else { + exprstate::on_typedescr(td, p_psm); + } + } + + void + expect_formal_xs::print(std::ostream & os) const { + os << ""; + } +#endif + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end DExpectFormalArgSsm.cpp */ diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index c7d3fffd..3912a43d 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -5,7 +5,10 @@ #include "DExpectFormalArglistSsm.hpp" #include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" +#include #include +#include +#include #ifdef NOT_YET #include "parserstatemachine.hpp" @@ -17,8 +20,12 @@ #endif namespace xo { - using xo::mm::AAllocator; + using xo::print::APrintable; + using xo::print::ppstate; using xo::print::ppindentinfo; + using xo::mm::AGCObject; + using xo::mm::AAllocator; + using xo::facet::FacetRegistry; using xo::reflect::typeseq; namespace scm { @@ -106,6 +113,54 @@ namespace xo { DExpectFormalArglistSsm::on_token(const Token & tk, ParserStateMachine * p_psm) { + switch (tk.tk_type()) { + case tokentype::tk_leftparen: + this->on_leftparen_token(tk, p_psm); + return; + + // all the not-yet-handled cases + case tokentype::tk_lambda: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_symbol: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + p_psm->illegal_input_on_token("DExpectFormalArglistSsm::on_token", tk, this->get_expect_str()); @@ -152,20 +207,29 @@ namespace xo { : exprstate(exprstatetype::expect_formal_arglist), farglxs_type_{formalarglstatetype::argl_0} {} +#endif void - expect_formal_arglist_xs::on_leftparen_token(const token_type & tk, - parserstatemachine * p_psm) + DExpectFormalArglistSsm::on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm) { - if (farglxs_type_ == formalarglstatetype::argl_0) { - this->farglxs_type_ = formalarglstatetype::argl_1a; - /* TODO: refactor to have setup method on each exprstate */ - expect_formal_xs::start(p_psm); - } else { - exprstate::on_leftparen_token(tk, p_psm); + scope log(XO_DEBUG(true)); + + if (fastate_ == formalarglstatetype::argl_0) { + this->fastate_ = formalarglstatetype::argl_1a; + + log && log("STUB: DExpectFormalArglistSsm::on_leftparen_token -> DExpectFormalSsm::start()"); + + //DExpectFormalSsm::start(p_psm); + return; } + + p_psm->illegal_input_on_token("DExpectFormalArglistSsm::on_token", + tk, + this->get_expect_str()); } +#ifdef NOT_YET void expect_formal_arglist_xs::on_formal(const rp & formal, parserstatemachine * p_psm) @@ -216,8 +280,58 @@ namespace xo { bool DExpectFormalArglistSsm::pretty(const ppindentinfo & ppii) const { - return ppii.pps()->pretty_struct(ppii, - "DExpectFormalArglistSsm"); + ppstate * pps = ppii.pps(); + + if (ppii.upto()) { + if (!pps->print_upto("print_upto(xrefrtag("fastate", fastate_))) + return false; + + if (!pps->print_upto(xrefrtag("n_args", n_args_))) + return false; + + for (size_type i_arg = 0; i_arg < n_args_; ++i_arg) { + char buf[80]; + snprintf(buf, sizeof(buf), "arg[%ud]", i_arg); + + auto arg_gco = argl_->at(i_arg); + obj arg_pr + = FacetRegistry::instance().try_variant(arg_gco); + + if (!pps->print_upto(xrefrtag(buf, arg_pr))) + return false; + } + + pps->write(">"); + + return true; + } else { + pps->write("newline_indent(ppii.ci1()); + pps->pretty(refrtag("fastate", fastate_)); + + pps->newline_indent(ppii.ci1()); + pps->pretty(refrtag("n_args", n_args_)); + + for (size_type i_arg = 0; i_arg < n_args_; ++i_arg) { + char buf[80]; + snprintf(buf, sizeof(buf), "arg[%ud]", i_arg); + + auto arg_gco = argl_->at(i_arg); + obj arg_pr + = FacetRegistry::instance().try_variant(arg_gco); + + pps->newline_indent(ppii.ci1()); + pps->pretty(refrtag(buf, arg_pr)); + } + + pps->write(">"); + + return false; + } } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp new file mode 100644 index 00000000..ad5678a5 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp @@ -0,0 +1,59 @@ +/** @file ISyntaxStateMachine_DExpectFormalArgSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectFormalArgSsm::ssm_type(const DExpectFormalArgSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectFormalArgSsm::get_expect_str(const DExpectFormalArgSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectFormalArgSsm::on_token(DExpectFormalArgSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_symbol(DExpectFormalArgSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_typedescr(DExpectFormalArgSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_expression(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_expression_with_semicolon(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_semicolon(expr, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectFormalArgSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index 7a2ece4c..e003b27d 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -17,6 +17,8 @@ namespace xo { return "expect-toplevel-expression-sequence"; case syntaxstatetype::expect_formal_arglist: return "expect-formal-arglist"; + case syntaxstatetype::expect_formal_arg: + return "expect-formal-arg"; case syntaxstatetype::expect_symbol: return "expect-symbol"; case syntaxstatetype::expect_type: diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 5b6124a9..0a3ae658 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -231,11 +231,10 @@ namespace xo { REQUIRE(result.is_incomplete()); } -#ifdef NOT_YET { - auto & result = parser.on_token(Token::bool_token("true")); + auto & result = parser.on_token(Token::leftparen_token()); - log && log("after true token:"); + log && log("after lparen token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); @@ -244,6 +243,7 @@ namespace xo { REQUIRE(result.is_incomplete()); } +#ifdef NOT_YET { auto & result = parser.on_token(Token::then_token()); From 0f4e270707dc8a2278d70211b4a4d9b996a58c0f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 28 Jan 2026 17:40:57 -0500 Subject: [PATCH 143/342] xo-reader2: + DExpectFormalArgSsm [WIP] --- include/xo/tokenizer2/Token.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index f9807d05..55a2d57d 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -92,7 +92,7 @@ namespace xo { /** token representing right angle bracket @c ">" **/ static Token rightangle() { return Token(tokentype::tk_rightangle); } /** token representing left parenthesis @c "(" **/ - static Token leftparen() { return Token(tokentype::tk_leftparen); } + static Token leftparen_token() { return Token(tokentype::tk_leftparen); } /** Token representing right parenthesis @c ")" **/ static Token rightparen() { return Token(tokentype::tk_rightparen); } /** token representing left bracket @c "[" **/ From e7d4c4ae28f98ab22fc4ca5711b474cd38de3980 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 28 Jan 2026 18:04:08 -0500 Subject: [PATCH 144/342] xo-reader2: + DFormalArgSsm printable facet --- CMakeLists.txt | 12 ++++ idl/IPrintable_DExpectFormalArgSsm.json5 | 13 ++++ include/xo/reader2/DExpectFormalArgSsm.hpp | 10 ++- .../ssm/IPrintable_DExpectFormalArgSsm.hpp | 62 +++++++++++++++++++ src/reader2/CMakeLists.txt | 2 +- src/reader2/DDefineSsm.cpp | 10 ++- src/reader2/DExpectFormalArgSsm.cpp | 19 +++--- .../IPrintable_DExpectFormalArgSsm.cpp | 28 +++++++++ 8 files changed, 136 insertions(+), 20 deletions(-) create mode 100644 idl/IPrintable_DExpectFormalArgSsm.json5 create mode 100644 include/xo/reader2/ssm/IPrintable_DExpectFormalArgSsm.hpp create mode 100644 src/reader2/IPrintable_DExpectFormalArgSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f6b9d75..4fcbe399 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,18 @@ xo_add_genfacetimpl( OUTPUT_CPP_DIR src/reader2 ) +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expectformalargssm + FACET_PKG xo_printable2 + FACET Printable + REPR ExpectFormalArgSsm + INPUT idl/IPrintable_DExpectFormalArgSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + # ---------------------------------------------------------------- # note: manual target; generated code committed to git diff --git a/idl/IPrintable_DExpectFormalArgSsm.json5 b/idl/IPrintable_DExpectFormalArgSsm.json5 new file mode 100644 index 00000000..854a458e --- /dev/null +++ b/idl/IPrintable_DExpectFormalArgSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectFormalArgSsm", + using_doxygen: true, + repr: "DExpectFormalArgSsm", + doc: [ "implement APrintable for DExpectFormalArgSsm" ], +} diff --git a/include/xo/reader2/DExpectFormalArgSsm.hpp b/include/xo/reader2/DExpectFormalArgSsm.hpp index 3c913b90..540b66c2 100644 --- a/include/xo/reader2/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/DExpectFormalArgSsm.hpp @@ -48,6 +48,7 @@ namespace xo { public: using TypeDescr = xo::reflect::TypeDescr; using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; public: DExpectFormalArgSsm(); @@ -97,6 +98,13 @@ namespace xo { ParserStateMachine * p_psm); ///@} + /** @defgroup scm-expectformalargssm-printable-facet printable facet methods **/ + ///@{ + + /** pretty-printing support **/ + bool pretty(const ppindentinfo & ppii) const; + + ///@} #ifdef NOT_YET @@ -117,8 +125,6 @@ namespace xo { virtual void on_typedescr(TypeDescr td, parserstatemachine * p_psm) override; - virtual void print(std::ostream & os) const override; - private: static std::unique_ptr make(); #endif diff --git a/include/xo/reader2/ssm/IPrintable_DExpectFormalArgSsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectFormalArgSsm.hpp new file mode 100644 index 00000000..21e724e1 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DExpectFormalArgSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectFormalArgSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectFormalArgSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectFormalArgSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectFormalArgSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectFormalArgSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectFormalArgSsm + **/ + class IPrintable_DExpectFormalArgSsm { + public: + /** @defgroup scm-printable-dexpectformalargssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpectformalargssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectFormalArgSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 49be467b..aebe5d77 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -39,7 +39,7 @@ set(SELF_SRCS DExpectFormalArgSsm.cpp ISyntaxStateMachine_DExpectFormalArgSsm.cpp - # IPrintable_DExpectFormalArgSsm.cpp + IPrintable_DExpectFormalArgSsm.cpp DExpectSymbolSsm.cpp ISyntaxStateMachine_DExpectSymbolSsm.cpp diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index c4628c22..af8cee87 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -739,12 +739,10 @@ namespace xo { assert(expr.data()); (void)expr; - return ppii.pps()->pretty_struct - (ppii, - "DDefineSsm", - refrtag("defstate", defstate_), - refrtag("def_expr", expr) - ); + return ppii.pps()->pretty_struct(ppii, + "DDefineSsm", + refrtag("defstate", defstate_), + refrtag("def_expr", expr)); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index 31a26888..7952c8f2 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -216,18 +216,15 @@ namespace xo { exprstate::on_typedescr(td, p_psm); } } - - void - expect_formal_xs::print(std::ostream & os) const { - os << ""; - } #endif + + bool + DExpectFormalArgSsm::pretty(const ppindentinfo & ppii) const { + return ppii.pps()->pretty_struct + (ppii, + "DExpectFormalArgSsm"); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/IPrintable_DExpectFormalArgSsm.cpp b/src/reader2/IPrintable_DExpectFormalArgSsm.cpp new file mode 100644 index 00000000..a38d4d86 --- /dev/null +++ b/src/reader2/IPrintable_DExpectFormalArgSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectFormalArgSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectFormalArgSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectFormalArgSsm.json5] +**/ + +#include "ssm/IPrintable_DExpectFormalArgSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectFormalArgSsm::pretty(const DExpectFormalArgSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectFormalArgSsm.cpp */ \ No newline at end of file From 724a7f1496f8089691c6f454f8ac14842d0352e3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 28 Jan 2026 18:31:10 -0500 Subject: [PATCH 145/342] xo-reader2: + DExpectFormalArglistSsm starts DExpectFormalArgSsm --- include/xo/reader2/DExpectFormalArgSsm.hpp | 6 ++++- include/xo/reader2/DExpectSymbolSsm.hpp | 3 +-- src/reader2/DDefineSsm.cpp | 2 +- src/reader2/DExpectFormalArgSsm.cpp | 30 ++++++++++++++-------- src/reader2/DExpectFormalArglistSsm.cpp | 8 +++--- src/reader2/DExpectSymbolSsm.cpp | 5 ++-- src/reader2/reader2_register_facets.cpp | 7 +++++ 7 files changed, 39 insertions(+), 22 deletions(-) diff --git a/include/xo/reader2/DExpectFormalArgSsm.hpp b/include/xo/reader2/DExpectFormalArgSsm.hpp index 540b66c2..1860853c 100644 --- a/include/xo/reader2/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/DExpectFormalArgSsm.hpp @@ -54,8 +54,12 @@ namespace xo { DExpectFormalArgSsm(); /** create empty instance using memory from @p mm **/ - DExpectFormalArgSsm * _make(DArena & mm); + static obj make(DArena & mm); + /** create empty instance using memory from @p mm **/ + static DExpectFormalArgSsm * _make(DArena & mm); + + /** puah instance of this ssm onto @p p_psm **/ static void start(ParserStateMachine * p_psm); /** @defgroup scm-expectformalargssm-ssm-facet syntaxstatemachine facet methods **/ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 4cb04019..d874e63a 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -38,8 +38,7 @@ namespace xo { * to the state machine on top of the stack * as of when this start() method invoked **/ - static void start(DArena & parser_mm, - ParserStateMachine * p_psm); + static void start(ParserStateMachine * p_psm); /** update state for this syntax on incoming token @p tk, * with overall parser state in @p p_psm diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index af8cee87..f7edd2a3 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -597,7 +597,7 @@ namespace xo { if (defstate_ == defexprstatetype::def_0) { this->defstate_ = defexprstatetype::def_1; - DExpectSymbolSsm::start(p_psm->parser_alloc(), p_psm); + DExpectSymbolSsm::start(p_psm); return; } diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index 7952c8f2..2a19ce62 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -4,12 +4,14 @@ **/ #include "DExpectFormalArgSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" +#include "DExpectSymbolSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp" #ifdef NOT_YET -#include "expect_symbol_xs.hpp" #include "expect_type_xs.hpp" -#include "parserstatemachine.hpp" -#include "exprstatestack.hpp" +//#include "parserstatemachine.hpp" +//#include "exprstatestack.hpp" #include "xo/expression/Variable.hpp" #endif @@ -38,6 +40,12 @@ namespace xo { DExpectFormalArgSsm::DExpectFormalArgSsm() = default; + obj + DExpectFormalArgSsm::make(DArena & mm) + { + return obj(_make(mm)); + } + DExpectFormalArgSsm * DExpectFormalArgSsm::_make(DArena & mm) { @@ -46,6 +54,14 @@ namespace xo { return new (mem) DExpectFormalArgSsm(); } + void + DExpectFormalArgSsm::start(ParserStateMachine * p_psm) + { + p_psm->push_ssm(DExpectFormalArgSsm::make(p_psm->parser_alloc())); + + DExpectSymbolSsm::start(p_psm); + } + syntaxstatetype DExpectFormalArgSsm::ssm_type() const noexcept { return syntaxstatetype::expect_formal_arg; @@ -161,14 +177,8 @@ namespace xo { expr, this->get_expect_str()); } + #ifdef NOT_YET - void - DExpectFormalSsm::start(ParserStateMachine * p_psm) { - p_psm->push_exprstate(expect_formal_xs::make()); - - expect_symbol_xs::start(p_psm); - } - expect_formal_xs::expect_formal_xs() : exprstate(exprstatetype::expect_formal) {} diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 3912a43d..eaad8028 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -5,6 +5,8 @@ #include "DExpectFormalArglistSsm.hpp" #include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" +#include "DExpectFormalArgSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" #include #include #include @@ -213,14 +215,10 @@ namespace xo { DExpectFormalArglistSsm::on_leftparen_token(const Token & tk, ParserStateMachine * p_psm) { - scope log(XO_DEBUG(true)); - if (fastate_ == formalarglstatetype::argl_0) { this->fastate_ = formalarglstatetype::argl_1a; - log && log("STUB: DExpectFormalArglistSsm::on_leftparen_token -> DExpectFormalSsm::start()"); - - //DExpectFormalSsm::start(p_psm); + DExpectFormalArgSsm::start(p_psm); return; } diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index c10678f2..7a86e721 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -29,11 +29,10 @@ namespace xo { } void - DExpectSymbolSsm::start(DArena & parser_alloc, - ParserStateMachine * p_psm) + DExpectSymbolSsm::start(ParserStateMachine * p_psm) { DExpectSymbolSsm * sym_ssm - = DExpectSymbolSsm::make(parser_alloc); + = DExpectSymbolSsm::make(p_psm->parser_alloc()); // note: // relying on [ISyntaxStateMachine_DExpectedSymbolSsm.hpp] diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 1cb37de9..9dc10aa2 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -20,6 +20,9 @@ #include #include +#include +#include + #include #include @@ -63,6 +66,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); @@ -80,6 +86,7 @@ namespace xo { log && log(xtag("DLambdaSsm.tseq", typeseq::id())); log && log(xtag("DIfElseSsm.tseq", typeseq::id())); log && log(xtag("DExpectFormalArglistSsm.tseq", typeseq::id())); + log && log(xtag("DExpectFormalArgSsm.tseq", typeseq::id())); log && log(xtag("DExpectSymbolSsm.tseq", typeseq::id())); log && log(xtag("DExpectTypeSsm.tseq", typeseq::id())); log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); From 6a9d793c74da7c59b40e4a270ae9ecd05909a3ca Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 29 Jan 2026 10:16:52 -0500 Subject: [PATCH 146/342] xo-reader2: lambda ssm progress. incremental [WIP] --- include/xo/reader2/DExpectFormalArgSsm.hpp | 2 ++ src/reader2/DExpectFormalArgSsm.cpp | 21 ++++++++++++-- utest/SchematikaParser.test.cpp | 32 +++++++++++++++++++--- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/include/xo/reader2/DExpectFormalArgSsm.hpp b/include/xo/reader2/DExpectFormalArgSsm.hpp index 1860853c..2ec63834 100644 --- a/include/xo/reader2/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/DExpectFormalArgSsm.hpp @@ -140,8 +140,10 @@ namespace xo { /** formal parameter name **/ const DUniqueString * name_ = nullptr; +#ifdef NOT_YET /** formal parameter type (if specified) **/ TypeDescr td_ = nullptr; +#endif }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index 2a19ce62..ad63fa5d 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -146,6 +146,12 @@ namespace xo { DExpectFormalArgSsm::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { + if (fstate_ == formalstatetype::formal_0) { + this->fstate_ = formalstatetype::formal_1; + this->name_ = p_psm->intern_string(sym); + return; + } + p_psm->illegal_input_on_symbol("DExpectFormalArgSsm::on_parsed_symbol", sym, this->get_expect_str()); @@ -230,9 +236,18 @@ namespace xo { bool DExpectFormalArgSsm::pretty(const ppindentinfo & ppii) const { - return ppii.pps()->pretty_struct - (ppii, - "DExpectFormalArgSsm"); + if (name_) { + return ppii.pps()->pretty_struct + (ppii, + "DExpectFormalArgSsm", + refrtag("fstate", fstate_), + refrtag("name", std::string_view(*name_))); + } else { + return ppii.pps()->pretty_struct + (ppii, + "DExpectFormalArgSsm", + refrtag("fstate", fstate_)); + } } } /*namespace scm*/ diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 0a3ae658..934b26ed 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -215,7 +215,7 @@ namespace xo { /** Walkthrough parsing input equivalent to: * - * lambda ; + * lambda (n : i64; * **/ @@ -243,11 +243,10 @@ namespace xo { REQUIRE(result.is_incomplete()); } -#ifdef NOT_YET { - auto & result = parser.on_token(Token::then_token()); + auto & result = parser.on_token(Token::symbol_token("n")); - log && log("after then token:"); + log && log("after symbol(n) token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); @@ -256,6 +255,31 @@ namespace xo { REQUIRE(result.is_incomplete()); } + { + auto & result = parser.on_token(Token::colon_token()); + + log && log("after colon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("i64")); + + log && log("after symbol(i64) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + +#ifdef NOT_YET { auto & result = parser.on_token(Token::i64_token("777")); From 3e27b8be1ebaeb2b8300ab3a7070b1aaf6ed7f32 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 29 Jan 2026 10:35:13 -0500 Subject: [PATCH 147/342] xo-reader2: in DExpectFormalArgSsm handle colon token --- include/xo/reader2/DExpectFormalArgSsm.hpp | 18 ++++++++-- include/xo/reader2/DExpectTypeSsm.hpp | 4 +-- src/reader2/DDefineSsm.cpp | 3 +- src/reader2/DExpectFormalArgSsm.cpp | 41 ++++++++++++---------- src/reader2/DExpectTypeSsm.cpp | 7 ++-- 5 files changed, 43 insertions(+), 30 deletions(-) diff --git a/include/xo/reader2/DExpectFormalArgSsm.hpp b/include/xo/reader2/DExpectFormalArgSsm.hpp index 2ec63834..f58a09b2 100644 --- a/include/xo/reader2/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/DExpectFormalArgSsm.hpp @@ -51,6 +51,9 @@ namespace xo { using ppindentinfo = xo::print::ppindentinfo; public: + /** @defgroupo scm-expectfromalargssm-ctors constructors **/ + ///@{ + DExpectFormalArgSsm(); /** create empty instance using memory from @p mm **/ @@ -62,6 +65,18 @@ namespace xo { /** puah instance of this ssm onto @p p_psm **/ static void start(ParserStateMachine * p_psm); + ///@} + + /** @defgroup scm-expectformalargssm-methods general methods **/ + ///@{ + + /** update state on incoming colon token @p tk; + * with overall parser state in @p p_psm + **/ + void on_colon_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} /** @defgroup scm-expectformalargssm-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -115,9 +130,6 @@ namespace xo { virtual void on_symbol(const std::string & symbol_name, parserstatemachine * p_psm) override; - virtual void on_colon_token(const token_type & tk, - parserstatemachine * p_psm) override; - // virtual void on_comma_token(...) override; #ifdef PROBABLY_NOT diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 346a6d6c..c2bb4297 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -32,9 +32,7 @@ namespace xo { static DExpectTypeSsm * make(DArena & parser_mm); - static void start(DArena & parser_mm, - //obj expr_mm, - ParserStateMachine * p_psm); + static void start(ParserStateMachine * p_psm); /** @defgroup scm-expecttype-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index f7edd2a3..4a13d41d 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -622,8 +622,7 @@ namespace xo { if (defstate_ == defexprstatetype::def_2) { this->defstate_ = defexprstatetype::def_3; - DExpectTypeSsm::start(p_psm->parser_alloc(), - p_psm); + DExpectTypeSsm::start(p_psm); return; } diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index ad63fa5d..d08858f7 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -7,11 +7,10 @@ #include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" #include "DExpectSymbolSsm.hpp" #include "ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp" +#include "DExpectTypeSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp" #ifdef NOT_YET -#include "expect_type_xs.hpp" -//#include "parserstatemachine.hpp" -//#include "exprstatestack.hpp" #include "xo/expression/Variable.hpp" #endif @@ -93,13 +92,15 @@ namespace xo { ParserStateMachine * p_psm) { switch (tk.tk_type()) { + case tokentype::tk_colon: + this->on_colon_token(tk, p_psm); + return; // all the not-yet-handled cases case tokentype::tk_leftparen: case tokentype::tk_lambda: case tokentype::tk_def: case tokentype::tk_if: case tokentype::tk_symbol: - case tokentype::tk_colon: case tokentype::tk_singleassign: case tokentype::tk_string: case tokentype::tk_f64: @@ -142,6 +143,24 @@ namespace xo { this->get_expect_str()); } + void + DExpectFormalArgSsm::on_colon_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (fstate_ == formalstatetype::formal_1) { + this->fstate_ = formalstatetype::formal_2; + + DExpectTypeSsm::start(p_psm); + + /* control reenters via DExpectFormalArgSsm::on_parsed_typedescr() */ + return; + } + + p_psm->illegal_input_on_token("DExpectFormalArgSsm::on_colon_token", + tk, + this->get_expect_str()); + } + void DExpectFormalArgSsm::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) @@ -201,20 +220,6 @@ namespace xo { } } - void - expect_formal_xs::on_colon_token(const token_type & tk, - parserstatemachine * p_psm) - { - if (this->formalxs_type_ == formalstatetype::formal_1) { - this->formalxs_type_ = formalstatetype::formal_2; - expect_type_xs::start(p_psm); - /* control reenters via expect_formal_xs::on_typedescr() */ - } else { - exprstate::on_colon_token(tk, - p_psm); - } - } - void expect_formal_xs::on_typedescr(TypeDescr td, parserstatemachine * p_psm) diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index d99ff817..8b151c5f 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -32,11 +32,10 @@ namespace xo { } void - DExpectTypeSsm::start(DArena & mm, - //obj expr_mm, - ParserStateMachine * p_psm) + DExpectTypeSsm::start(ParserStateMachine * p_psm) { - DExpectTypeSsm * expect_type_ssm = DExpectTypeSsm::make(mm); + DExpectTypeSsm * expect_type_ssm + = DExpectTypeSsm::make(p_psm->parser_alloc()); auto ssm = with_facet::mkobj(expect_type_ssm); From 753b07499422c1b0ff16f3ee59db395df980bc82 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 29 Jan 2026 10:49:55 -0500 Subject: [PATCH 148/342] xo-reader2: ssm pretty-printers include .expect_str() output --- src/reader2/DDefineSsm.cpp | 1 + src/reader2/DExpectFormalArgSsm.cpp | 5 ++++- src/reader2/DExpectFormalArglistSsm.cpp | 6 ++++++ src/reader2/DLambdaSsm.cpp | 4 +++- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 4a13d41d..4676b3c8 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -741,6 +741,7 @@ namespace xo { return ppii.pps()->pretty_struct(ppii, "DDefineSsm", refrtag("defstate", defstate_), + refrtag("expect", this->get_expect_str()), refrtag("def_expr", expr)); } } /*namespace scm*/ diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index d08858f7..215c9471 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -246,12 +246,15 @@ namespace xo { (ppii, "DExpectFormalArgSsm", refrtag("fstate", fstate_), + refrtag("expect", this->get_expect_str()), refrtag("name", std::string_view(*name_))); } else { return ppii.pps()->pretty_struct (ppii, "DExpectFormalArgSsm", - refrtag("fstate", fstate_)); + refrtag("fstate", fstate_), + refrtag("expect", this->get_expect_str()) + ); } } diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index eaad8028..db8b1f6d 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -287,6 +287,9 @@ namespace xo { if (!pps->print_upto(xrefrtag("fastate", fastate_))) return false; + if (!pps->print_upto(xrefrtag("expect", this->get_expect_str()))) + return false; + if (!pps->print_upto(xrefrtag("n_args", n_args_))) return false; @@ -311,6 +314,9 @@ namespace xo { pps->newline_indent(ppii.ci1()); pps->pretty(refrtag("fastate", fastate_)); + pps->newline_indent(ppii.ci1()); + pps->pretty(refrtag("expect", this->get_expect_str())); + pps->newline_indent(ppii.ci1()); pps->pretty(refrtag("n_args", n_args_)); diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index a7db6e11..1fda9547 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -463,12 +463,14 @@ namespace xo { (ppii, "DLambdaSsm", refrtag("lmstate", lmstate_), + refrtag("expect", this->get_expect_str()), refrtag("body", body)); } else { return ppii.pps()->pretty_struct (ppii, "DLambdaSsm", - refrtag("lmstate", lmstate_)); + refrtag("lmstate", lmstate_), + refrtag("expect", this->get_expect_str())); } } From 35a49810e47639823d3092de920278c941bacb08 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 29 Jan 2026 12:24:46 -0500 Subject: [PATCH 149/342] xo-reader2: use DUniqueString* to report parsed formal --- idl/SyntaxStateMachine.json5 | 10 +++++ include/xo/reader2/DDefineSsm.hpp | 7 ++++ include/xo/reader2/DExpectExprSsm.hpp | 7 ++++ include/xo/reader2/DExpectFormalArgSsm.hpp | 13 ++++--- .../xo/reader2/DExpectFormalArglistSsm.hpp | 10 +++-- include/xo/reader2/DExpectSymbolSsm.hpp | 7 ++++ include/xo/reader2/DExpectTypeSsm.hpp | 7 ++++ include/xo/reader2/DExprSeqState.hpp | 7 ++++ include/xo/reader2/DIfElseSsm.hpp | 27 +++++++++----- include/xo/reader2/DLambdaSsm.hpp | 37 ++++++++++--------- include/xo/reader2/DProgressSsm.hpp | 3 ++ include/xo/reader2/ParserStateMachine.hpp | 15 ++++++++ .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 + .../xo/reader2/ssm/IPrintable_DLambdaSsm.hpp | 2 +- .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 + .../ISyntaxStateMachine_DExpectExprSsm.hpp | 2 + ...SyntaxStateMachine_DExpectFormalArgSsm.hpp | 2 + ...axStateMachine_DExpectFormalArglistSsm.hpp | 2 + .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 + .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 + .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 + .../ssm/ISyntaxStateMachine_DIfElseSsm.hpp | 2 + .../ssm/ISyntaxStateMachine_DLambdaSsm.hpp | 4 +- .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 2 + .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 ++ .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 ++ src/reader2/DDefineSsm.cpp | 11 ++++++ src/reader2/DExpectExprSsm.cpp | 15 +++++++- src/reader2/DExpectFormalArgSsm.cpp | 27 ++++++++++++++ src/reader2/DExpectFormalArglistSsm.cpp | 11 ++++++ src/reader2/DExpectSymbolSsm.cpp | 11 ++++++ src/reader2/DExpectTypeSsm.cpp | 17 +++++++-- src/reader2/DExprSeqState.cpp | 11 ++++++ src/reader2/DIfElseSsm.cpp | 11 ++++++ src/reader2/DLambdaSsm.cpp | 35 +++++++++--------- src/reader2/DProgressSsm.cpp | 11 ++++++ src/reader2/IPrintable_DLambdaSsm.cpp | 2 +- src/reader2/ISyntaxStateMachine_Any.cpp | 6 +++ .../ISyntaxStateMachine_DDefineSsm.cpp | 5 +++ .../ISyntaxStateMachine_DExpectExprSsm.cpp | 5 +++ ...SyntaxStateMachine_DExpectFormalArgSsm.cpp | 5 +++ ...axStateMachine_DExpectFormalArglistSsm.cpp | 5 +++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 +++ .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 +++ .../ISyntaxStateMachine_DExprSeqState.cpp | 5 +++ .../ISyntaxStateMachine_DIfElseSsm.cpp | 5 +++ .../ISyntaxStateMachine_DLambdaSsm.cpp | 10 +++-- .../ISyntaxStateMachine_DProgressSsm.cpp | 5 +++ src/reader2/ParserStateMachine.cpp | 36 ++++++++++++++++++ 50 files changed, 377 insertions(+), 65 deletions(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 15a36f12..fba93437 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -72,6 +72,16 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_parsed_formal", + doc: ["operate state machine for formal emitted by nested ssm"], + return_type: "void", + args: [ + {type: "const DUniqueString *", name: "param_name"}, + {type: "TypeDescr", name: "param_type"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_parsed_expression", doc: ["update state machine for incoming parsed expression @p expr"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 41a27b39..bf0a3ffb 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -195,6 +195,13 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** update state for this ssm to consume param (name,value) + * emitted by nested @p_psm + **/ + void on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index b994b498..8e51124d 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -135,6 +135,13 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** update state to consume parsed formal (name, value) from nested ssm, + * with overall parser state in @p p_psm + **/ + void on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectFormalArgSsm.hpp b/include/xo/reader2/DExpectFormalArgSsm.hpp index f58a09b2..ee5eb0ea 100644 --- a/include/xo/reader2/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/DExpectFormalArgSsm.hpp @@ -104,6 +104,14 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** consume parsed formal (name,type) = (@p sym, @p td) from nested ssm + * with overall parser state in @p p_psm. + * (In practice not reachable) + **/ + void on_parsed_formal(const DUniqueString * sym, + TypeDescr td, + ParserStateMachine * p_psm); + /** update state on parsed expression emitted by nested ssm * with overall parser state in @p p_psm **/ @@ -151,11 +159,6 @@ namespace xo { /** formal parameter name **/ const DUniqueString * name_ = nullptr; - -#ifdef NOT_YET - /** formal parameter type (if specified) **/ - TypeDescr td_ = nullptr; -#endif }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index c9cd2ac5..f4c24303 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -103,6 +103,13 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** update state to consume parsed param (name,type) emitted by + * nested ssm, with overall parser state in @p p_psm + **/ + void on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm); + /** update state on parsed expression emitted by nested ssm * with overall parser state in @p p_psm **/ @@ -116,9 +123,6 @@ namespace xo { ParserStateMachine * p_psm); #ifdef NOT_YET - - virtual void on_formal(const rp & formal, - parserstatemachine * p_psm) override; virtual void on_comma_token(const token_type & tk, parserstatemachine * p_psm) override; virtual void on_rightparen_token(const token_type & tk, diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index d874e63a..080380b9 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -78,6 +78,13 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** update state to consume param (name, value) emitted + * by nested ssm + **/ + void on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr * in nested state machine. * (provided to satisfy ASyntaxStateMachine api. not reachable) diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index c2bb4297..3ca99815 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -129,6 +129,13 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine to consume formal param (name,value) + * emitted by nested ssm + **/ + void on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm); + /** operate state machine for this syntax on receiving expression * from nested parser. * (provided to satisfy ASyntaxStateMachine api. not reachable) diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 96eea236..c718cbef 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -138,6 +138,13 @@ namespace xo { **/ void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** update this ssm to consume parsed formal param (name, value) + * emitted by nested ssm, with overall parser state in @p p_psm + **/ + void on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm); + /** update state for this syntax on parsed expression @p expr * from nested ssm. * overall parser state in @p p_psm diff --git a/include/xo/reader2/DIfElseSsm.hpp b/include/xo/reader2/DIfElseSsm.hpp index 9b3e5d17..647a5e34 100644 --- a/include/xo/reader2/DIfElseSsm.hpp +++ b/include/xo/reader2/DIfElseSsm.hpp @@ -140,11 +140,11 @@ namespace xo { void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm); - /** update state for this syntax after parsing an expression @p expr, - * overall parser state in @p p_psm. + /** update state for this syntax after parsing a symbol @p sym, + * with overall parser state in @p p_psm **/ - void on_parsed_expression(obj expr, - ParserStateMachine * p_psm); + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); /** update state for this syntax after parsing a type description @p td; * overall parser state in @p p_psm @@ -152,6 +152,19 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** update state to consume formal param (name,value) + * from nested ssm + **/ + void on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm); + + /** update state for this syntax after parsing an expression @p expr, + * overall parser state in @p p_psm. + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr, * followed by semicolon, * with overall parser state in @p p_psm. @@ -159,12 +172,6 @@ namespace xo { void on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm); - /** update state for this syntax after parsing a symbol @p sym, - * with overall parser state in @p p_psm - **/ - void on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm); - ///@} /** @defgroup scm-ifelsessm-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DLambdaSsm.hpp b/include/xo/reader2/DLambdaSsm.hpp index d9b0754d..69cb3322 100644 --- a/include/xo/reader2/DLambdaSsm.hpp +++ b/include/xo/reader2/DLambdaSsm.hpp @@ -104,18 +104,6 @@ namespace xo { void on_token(const Token & tk, ParserStateMachine * p_psm); - /** update this ssm when nested parser - * emits expression @p expr - **/ - void on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm); - - /** update this ssm when nested parser - * emits expression @p expr - **/ - void on_parsed_expression(obj expr, - ParserStateMachine * p_psm); - /** update this ssm when nested parser * emits @p td. **/ @@ -128,17 +116,30 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + /** update this ssm to consume parsed formal (name,value) + * from nested (and now expired) ssm + **/ + void on_parsed_formal(const DUniqueString * sym, + TypeDescr td, + ParserStateMachine * p_psm); + + /** update this ssm when nested parser + * emits expression @p expr + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + + /** update this ssm when nested parser + * emits expression @p expr + **/ + void on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm); + #ifdef NOT_YET virtual const char * get_expect_str() const override; - virtual void on_typedescr(TypeDescr td, - parserstatemachine * p_psm) override; virtual void on_formal_arglist(const std::vector> & argl, parserstatemachine * p_psm) override; - virtual void on_expr(bp expr, - parserstatemachine * p_psm) override; - virtual void on_expr_with_semicolon(bp expr, - parserstatemachine * p_psm) override; virtual void on_leftbrace_token(const token_type & tk, parserstatemachine * p_psm) override; virtual void on_colon_token(const token_type & tk, diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 788c10ca..fa0ec733 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -170,6 +170,9 @@ namespace xo { ParserStateMachine * p_psm); void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); + void on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm); void on_parsed_expression(obj, ParserStateMachine * p_psm); void on_parsed_expression_with_semicolon(obj expr, diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index a674e7e2..74f27876 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -102,6 +102,12 @@ namespace xo { **/ void on_parsed_typedescr(TypeDescr td); + /** update state to consume param (name, value) emitted by + * nested (but not popped) parsing state + **/ + void on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type); + /** update state to respond to parsed expression @p expr * (from nested parsing state) **/ @@ -163,6 +169,15 @@ namespace xo { TypeDescr td, std::string_view expect_str); + /** report illegal parsed formal (param_name, param_type) from nested ssm. + * Introducing as placeholder; not expected to be reachable in + * full parser + **/ + void illegal_parsed_formal(std::string_view ssm_name, + const DUniqueString * param_name, + TypeDescr param_type, + std::string_view expect_str); + /** report illegal parsed expression from nested ssm. * Introducing as placeholder; not clear if this will be reachable * in full parser diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index 3115d692..6cc3b829 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -63,6 +63,8 @@ public: virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; /** operate state machine for incoming type description @p td **/ virtual void on_parsed_typedescr(Opaque data, TypeDescr td, ParserStateMachine * p_psm) = 0; + /** operate state machine for formal emitted by nested ssm **/ + virtual void on_parsed_formal(Opaque data, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) = 0; /** update state machine for incoming parsed expression @p expr **/ virtual void on_parsed_expression(Opaque data, obj expr, ParserStateMachine * p_psm) = 0; /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/IPrintable_DLambdaSsm.hpp b/include/xo/reader2/ssm/IPrintable_DLambdaSsm.hpp index 9d2cad26..6d9681ee 100644 --- a/include/xo/reader2/ssm/IPrintable_DLambdaSsm.hpp +++ b/include/xo/reader2/ssm/IPrintable_DLambdaSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DLambdaSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 45be148e..3faa0f67 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -63,6 +63,7 @@ namespace scm { [[noreturn]] void on_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; + [[noreturn]] void on_parsed_formal(Opaque, const DUniqueString *, TypeDescr, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression(Opaque, obj, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression_with_semicolon(Opaque, obj, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index dad8ff29..f4d0da9d 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -60,6 +60,8 @@ namespace xo { static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 7250cec7..3ff00e07 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -60,6 +60,8 @@ namespace xo { static void on_parsed_symbol(DExpectExprSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectExprSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectExprSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp index 39d19b05..adce6eb9 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp @@ -60,6 +60,8 @@ namespace xo { static void on_parsed_symbol(DExpectFormalArgSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectFormalArgSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectFormalArgSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp index 93154f83..b8a3b416 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp @@ -60,6 +60,8 @@ namespace xo { static void on_parsed_symbol(DExpectFormalArglistSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectFormalArglistSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectFormalArglistSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 7e83d0e4..d778e293 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -60,6 +60,8 @@ namespace xo { static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectSymbolSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectSymbolSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index c8c4cc9f..9d6f153a 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -60,6 +60,8 @@ namespace xo { static void on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectTypeSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index 2a86db05..d958f1f8 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -60,6 +60,8 @@ namespace xo { static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExprSeqState & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExprSeqState & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExprSeqState & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp index 2101b8e1..88a8b7d8 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp @@ -60,6 +60,8 @@ namespace xo { static void on_parsed_symbol(DIfElseSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DIfElseSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DIfElseSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp index 943400c5..02582d0b 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DLambdaSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -60,6 +60,8 @@ namespace xo { static void on_parsed_symbol(DLambdaSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DLambdaSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DLambdaSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 3d70afed..ee2dfbaf 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -60,6 +60,8 @@ namespace xo { static void on_parsed_symbol(DProgressSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DProgressSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DProgressSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DProgressSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 36c2ff83..51ab0f30 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -61,6 +61,9 @@ namespace scm { void on_parsed_typedescr(Opaque data, TypeDescr td, ParserStateMachine * p_psm) override { return I::on_parsed_typedescr(_dcast(data), td, p_psm); } + void on_parsed_formal(Opaque data, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) override { + return I::on_parsed_formal(_dcast(data), param_name, param_type, p_psm); + } void on_parsed_expression(Opaque data, obj expr, ParserStateMachine * p_psm) override { return I::on_parsed_expression(_dcast(data), expr, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index fb1fb496..3de33f8e 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -65,6 +65,9 @@ public: void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm) { return O::iface()->on_parsed_typedescr(O::data(), td, p_psm); } + void on_parsed_formal(const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) { + return O::iface()->on_parsed_formal(O::data(), param_name, param_type, p_psm); + } void on_parsed_expression(obj expr, ParserStateMachine * p_psm) { return O::iface()->on_parsed_expression(O::data(), expr, p_psm); } diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 4676b3c8..65df6349 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -704,6 +704,17 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal("DDefineSsm::on_parsed_formal", + param_name, + param_type, + this->get_expect_str()); + } + void DDefineSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 4f61df72..2a836e87 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -340,7 +340,7 @@ namespace xo { DExpectExprSsm::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_symbol("DExpectExprSsm", + p_psm->illegal_input_on_symbol("DExpectExprSsm::on_parsed_symbol", sym, this->get_expect_str()); } @@ -349,11 +349,22 @@ namespace xo { DExpectExprSsm::on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_typedescr("DExpectExprSsm", + p_psm->illegal_input_on_typedescr("DExpectExprSsm::on_parsed_typedescr", td, this->get_expect_str()); } + void + DExpectExprSsm::on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal("DExpectExprSsm::on_parsed_formal", + param_name, + param_type, + this->get_expect_str()); + } + void DExpectExprSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index 215c9471..eb174fc9 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -166,6 +166,10 @@ namespace xo { ParserStateMachine * p_psm) { if (fstate_ == formalstatetype::formal_0) { + // parsed symbol @c sym is stored in tokenizer memory; + // must be copied to storage with expression lifetime, + // hence call to intern_string() + this->fstate_ = formalstatetype::formal_1; this->name_ = p_psm->intern_string(sym); return; @@ -180,11 +184,34 @@ namespace xo { DExpectFormalArgSsm::on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm) { + if (fstate_ == formalstatetype::formal_2) { + assert(name_); + + p_psm->pop_ssm(); + p_psm->on_parsed_formal(name_, td); + + return; + } + p_psm->illegal_input_on_typedescr("DExpectFormalArgSsm::on_parsed_typedescr", td, this->get_expect_str()); } + void + DExpectFormalArgSsm::on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm) + { + // NOTE: (param_name,param_type) *produced* by this SSM, + // but never *consumed* + + p_psm->illegal_parsed_formal("DExpectFormalArgSsm::on_parsed_formal", + param_name, + param_type, + this->get_expect_str()); + } + void DExpectFormalArgSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index db8b1f6d..a5b77c4d 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -186,6 +186,17 @@ namespace xo { this->get_expect_str()); } + void + DExpectFormalArglistSsm::on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal("DExpectFormalArglistSsm::on_parsed_formal", + param_name, + param_type, + this->get_expect_str()); + } + void DExpectFormalArglistSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 7a86e721..cee3a08c 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -73,6 +73,17 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal("DExpectSymbolSsm::on_parsed_formal", + param_name, + param_type, + this->get_expect_str()); + } + void DExpectSymbolSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 8b151c5f..8f848269 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -247,7 +247,7 @@ namespace xo { td = Reflect::require(); if (!td) { - p_psm->illegal_input_on_token("DExpectTypeSsm", + p_psm->illegal_input_on_token("DExpectTypeSsm::on_symbol_token", tk, this->get_expect_str()); } @@ -260,7 +260,7 @@ namespace xo { DExpectTypeSsm::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_symbol("ExpectTypeSsm", + p_psm->illegal_input_on_symbol("ExpectTypeSsm::on_parsed_symbol", sym, this->get_expect_str()); } @@ -269,11 +269,22 @@ namespace xo { DExpectTypeSsm::on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_typedescr("ExpectTypeSsm", + p_psm->illegal_input_on_typedescr("ExpectTypeSsm::on_parsed_typedescr", td, this->get_expect_str()); } + void + DExpectTypeSsm::on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal("DExpectTypeSsm::on_parsed_formal", + param_name, + param_type, + this->get_expect_str()); + } + void DExpectTypeSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 28c62354..5d9fe9b1 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -449,6 +449,17 @@ namespace xo { this->get_expect_str()); } + void + DExprSeqState::on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal("DExprSeqState::on_parsed_formal", + param_name, + param_type, + this->get_expect_str()); + } + void DExprSeqState::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index eca02910..9f7d7167 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -510,6 +510,17 @@ namespace xo { this->get_expect_str()); } + void + DIfElseSsm::on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal("DIfElseSsm::on_parsed_formal", + param_name, + param_type, + this->get_expect_str()); + } + bool DIfElseSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 1fda9547..f9fcd6ae 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -192,18 +192,6 @@ namespace xo { #ifdef NOT_YET - void - lambda_xs::on_lambda_token(const token_type & tk, - parserstatemachine * p_psm) - { - if (lmxs_type_ == lambdastatetype::lm_0) { - this->lmxs_type_ = lambdastatetype::lm_1; - expect_formal_arglist_xs::start(p_psm); - } else { - exprstate::on_lambda_token(tk, p_psm); - } - } - void lambda_xs::on_formal_arglist(const std::vector> & argl, parserstatemachine * p_psm) @@ -351,13 +339,14 @@ namespace xo { } void - DLambdaSsm::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) + DLambdaSsm::on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm) { - p_psm->illegal_parsed_expression - ("DLambdaSsm::on_parsed_expression_with_semicolon", - expr, - this->get_expect_str()); + p_psm->illegal_parsed_formal("DLambdaSsm::on_parsed_formal", + param_name, + param_type, + this->get_expect_str()); } void @@ -369,6 +358,16 @@ namespace xo { this->get_expect_str()); } + void + DLambdaSsm::on_parsed_expression_with_semicolon(obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression + ("DLambdaSsm::on_parsed_expression_with_semicolon", + expr, + this->get_expect_str()); + } + #ifdef NOT_YET void lambda_xs::on_expr(bp expr, diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index e773f9a7..1233c198 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -555,6 +555,17 @@ namespace xo { this->get_expect_str()); } + void + DProgressSsm::on_parsed_formal(const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal("DProgressSsm::on_parsed_formal", + param_name, + param_type, + this->get_expect_str()); + } + void DProgressSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/IPrintable_DLambdaSsm.cpp b/src/reader2/IPrintable_DLambdaSsm.cpp index 6cf5b29a..93a703aa 100644 --- a/src/reader2/IPrintable_DLambdaSsm.cpp +++ b/src/reader2/IPrintable_DLambdaSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DLambdaSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 4cfb72a7..2a16a292 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -52,6 +52,12 @@ ISyntaxStateMachine_Any::on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachi _fatal(); } +auto +ISyntaxStateMachine_Any::on_parsed_formal(Opaque, const DUniqueString *, TypeDescr, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_parsed_expression(Opaque, obj, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index 85c2a8f0..7117484b 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DDefineSsm::on_parsed_formal(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto ISyntaxStateMachine_DDefineSsm::on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index e545eedd..b0f5861d 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectExprSsm::on_parsed_formal(DExpectExprSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto ISyntaxStateMachine_DExpectExprSsm::on_parsed_expression(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp index ad5678a5..a242df29 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_formal(DExpectFormalArgSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_expression(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp index 91738110..006d122b 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_formal(DExpectFormalArglistSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_expression(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 0a35bb71..b7f208e8 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_formal(DExpectSymbolSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_expression(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 4b6950ab..473bd4b7 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectTypeSsm::on_parsed_formal(DExpectTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto ISyntaxStateMachine_DExpectTypeSsm::on_parsed_expression(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index af5d3cc9..d11ab3b7 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExprSeqState::on_parsed_formal(DExprSeqState & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto ISyntaxStateMachine_DExprSeqState::on_parsed_expression(DExprSeqState & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp index 66633e88..39a3abb2 100644 --- a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DIfElseSsm::on_parsed_formal(DIfElseSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto ISyntaxStateMachine_DIfElseSsm::on_parsed_expression(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp index ac4b2d14..e59546c8 100644 --- a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DLambdaSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -32,7 +32,6 @@ namespace xo { { self.on_token(tk, p_psm); } - auto ISyntaxStateMachine_DLambdaSsm::on_parsed_symbol(DLambdaSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void { @@ -44,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DLambdaSsm::on_parsed_formal(DLambdaSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto ISyntaxStateMachine_DLambdaSsm::on_parsed_expression(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); @@ -57,4 +61,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end ISyntaxStateMachine_DLambdaSsm.cpp */ +/* end ISyntaxStateMachine_DLambdaSsm.cpp */ \ No newline at end of file diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 1fdd6c90..6fe3f822 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DProgressSsm::on_parsed_formal(DProgressSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto ISyntaxStateMachine_DProgressSsm::on_parsed_expression(DProgressSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 2d9e4970..911b594a 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -129,6 +129,17 @@ namespace xo { this->stack_->top().on_parsed_typedescr(td, this); } + void + ParserStateMachine::on_parsed_formal(const DUniqueString * sym, + TypeDescr td) + { + scope log(XO_DEBUG(debug_flag_), xtag("sym", std::string_view(*sym)), xtag("td", td)); + + assert(stack_); + + this->stack_->top().on_parsed_formal(sym, td, this); + } + void ParserStateMachine::on_parsed_expression(obj expr) { @@ -248,6 +259,31 @@ namespace xo { this->capture_error(ssm_name, errmsg); } + void + ParserStateMachine::illegal_parsed_formal(std::string_view ssm_name, + const DUniqueString * param_name, + TypeDescr param_type, + std::string_view expect_str) + { + // TODO: + // - want to write error message using DArena + // - need something like log_streambuf and/or tostr() that's arena-aware + + auto errmsg_string = tostr("Unexpected expression", + xtag("param_name", std::string_view(*param_name)), + xtag("param_type", param_type), + xtag("expecting", expect_str), + xtag("ssm", ssm_name), + xtag("via", "ParserStateMachine::illegal_parsed_expression")); + + assert(expr_alloc_); + + auto errmsg = DString::from_view(expr_alloc_, + std::string_view(errmsg_string)); + + this->capture_error(ssm_name, errmsg); + } + void ParserStateMachine::illegal_parsed_expression(std::string_view ssm_name, obj expr, From eaf224bba013390b9675c73da9c35eef5f233aac Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 29 Jan 2026 13:28:30 -0500 Subject: [PATCH 150/342] xo-reader2: DExpectFormalArglistSsm handles+stores parsed formals --- .../xo/reader2/DExpectFormalArglistSsm.hpp | 2 +- src/reader2/DExpectFormalArglistSsm.cpp | 67 +++++++++++++++---- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index f4c24303..ac7bc643 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -147,7 +147,7 @@ namespace xo { /** populate with (parmaeter-name, parameter-type) list * as they're encountered. * - * Not using flexible array here since we don't know size + * Not using flexible array here since we don't know size at construction time **/ DArray * argl_ = nullptr; }; diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index a5b77c4d..555ab275 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -7,6 +7,8 @@ #include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" #include "DExpectFormalArgSsm.hpp" #include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" +#include +#include #include #include #include @@ -191,12 +193,65 @@ namespace xo { TypeDescr param_type, ParserStateMachine * p_psm) { + if (fastate_ == formalarglstatetype::argl_1a) { + this->fastate_ = formalarglstatetype::argl_1b; + + TypeRef typeref = TypeRef::dwim(TypeRef::prefix_type::from_chars("formal"), param_type); + + DVariable * var = DVariable::make(p_psm->expr_alloc(), + param_name, + typeref); + + // need AGCObject facet to use DArray here. + // May want to have gc feature that allows it to use + // FacetRegistry on memory that stores obj + // + // In this case doesn't matter since DExpectFormalArglistSsm not actually collected! + + obj var_o(var); + + if (argl_->size() == argl_->capacity()) { + // need to expand argl_ capacity. + // If DArena were to allow it (i.e. offer a realloc() feature, + // could do this in place since this SSM is at the top of the parser stack. + + obj mm(&(p_psm->parser_alloc())); + + DArray * argl_2x = DArray::empty(mm, 2 * argl_->capacity()); + + for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { + // TODO: prefer non-bounds-checked access here + argl_2x->push_back(argl_->at(i)); + } + + // update in place + this->argl_ = argl_2x; + } + + this->argl_->push_back(var_o); + return; + } + p_psm->illegal_parsed_formal("DExpectFormalArglistSsm::on_parsed_formal", param_name, param_type, this->get_expect_str()); } +#ifdef NOT_YET + void + expect_formal_arglist_xs::on_formal(const rp & formal, + parserstatemachine * p_psm) + { + if (farglxs_type_ == formalarglstatetype::argl_1a) { + this->farglxs_type_ = formalarglstatetype::argl_1b; + this->argl_.push_back(formal); + } else { + exprstate::on_formal(formal, p_psm); + } + } +#endif + void DExpectFormalArglistSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) @@ -239,18 +294,6 @@ namespace xo { } #ifdef NOT_YET - void - expect_formal_arglist_xs::on_formal(const rp & formal, - parserstatemachine * p_psm) - { - if (farglxs_type_ == formalarglstatetype::argl_1a) { - this->farglxs_type_ = formalarglstatetype::argl_1b; - this->argl_.push_back(formal); - } else { - exprstate::on_formal(formal, p_psm); - } - } - void expect_formal_arglist_xs::on_comma_token(const token_type & tk, parserstatemachine * p_psm) From 2f9d49b083399b1f722bde4ae639e646476dd1db Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 29 Jan 2026 13:48:24 -0500 Subject: [PATCH 151/342] xo-reader2: DExpectFormalArglistSsm parses multiple formals --- .../xo/reader2/DExpectFormalArglistSsm.hpp | 8 +-- src/reader2/DExpectFormalArglistSsm.cpp | 67 ++++++------------- utest/SchematikaParser.test.cpp | 44 ++++++++++-- 3 files changed, 66 insertions(+), 53 deletions(-) diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index ac7bc643..2898fa7c 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -75,6 +75,10 @@ namespace xo { void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); + /** update state on incoming token @p tk, with overall parser state in @p psm **/ + void on_comma_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expectformalarglistssm-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -140,10 +144,6 @@ namespace xo { private: /** parsing state-machine state **/ formalarglstatetype fastate_ = formalarglstatetype::argl_0; - /** number of formal parameters encountered. - * Invariant: n_args_ <= argl_->size() - **/ - size_type n_args_ = 0; /** populate with (parmaeter-name, parameter-type) list * as they're encountered. * diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 555ab275..676e0a9e 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -122,6 +122,10 @@ namespace xo { this->on_leftparen_token(tk, p_psm); return; + case tokentype::tk_comma: + this->on_comma_token(tk, p_psm); + return; + // all the not-yet-handled cases case tokentype::tk_lambda: case tokentype::tk_def: @@ -145,7 +149,6 @@ namespace xo { case tokentype::tk_lessequal: case tokentype::tk_greatequal: case tokentype::tk_dot: - case tokentype::tk_comma: case tokentype::tk_doublecolon: case tokentype::tk_assign: case tokentype::tk_yields: @@ -238,20 +241,6 @@ namespace xo { this->get_expect_str()); } -#ifdef NOT_YET - void - expect_formal_arglist_xs::on_formal(const rp & formal, - parserstatemachine * p_psm) - { - if (farglxs_type_ == formalarglstatetype::argl_1a) { - this->farglxs_type_ = formalarglstatetype::argl_1b; - this->argl_.push_back(formal); - } else { - exprstate::on_formal(formal, p_psm); - } - } -#endif - void DExpectFormalArglistSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) @@ -270,13 +259,6 @@ namespace xo { this->get_expect_str()); } -#ifdef NOT_YET - expect_formal_arglist_xs::expect_formal_arglist_xs() - : exprstate(exprstatetype::expect_formal_arglist), - farglxs_type_{formalarglstatetype::argl_0} - {} -#endif - void DExpectFormalArglistSsm::on_leftparen_token(const Token & tk, ParserStateMachine * p_psm) @@ -293,19 +275,23 @@ namespace xo { this->get_expect_str()); } -#ifdef NOT_YET void - expect_formal_arglist_xs::on_comma_token(const token_type & tk, - parserstatemachine * p_psm) + DExpectFormalArglistSsm::on_comma_token(const Token & tk, + ParserStateMachine * p_psm) { - if (farglxs_type_ == formalarglstatetype::argl_1b) { - this->farglxs_type_ = formalarglstatetype::argl_1a; - expect_formal_xs::start(p_psm); - } else { - exprstate::on_comma_token(tk, p_psm); + if (fastate_ == formalarglstatetype::argl_1b) { + this->fastate_ = formalarglstatetype::argl_1a; + + DExpectFormalArgSsm::start(p_psm); + return; } + + p_psm->illegal_input_on_token("DExpectFormalArglistSsm::on_comma_token", + tk, + this->get_expect_str()); } +#ifdef NOT_YET void expect_formal_arglist_xs::on_rightparen_token(const token_type & tk, parserstatemachine * p_psm) @@ -318,15 +304,6 @@ namespace xo { exprstate::on_rightparen_token(tk, p_psm); } } - - void - expect_formal_arglist_xs::print(std::ostream & os) const { - os << ""; - } #endif bool @@ -344,12 +321,12 @@ namespace xo { if (!pps->print_upto(xrefrtag("expect", this->get_expect_str()))) return false; - if (!pps->print_upto(xrefrtag("n_args", n_args_))) + if (!pps->print_upto(xrefrtag("n_args", argl_->size()))) return false; - for (size_type i_arg = 0; i_arg < n_args_; ++i_arg) { + for (size_type i_arg = 0; i_arg < argl_->size(); ++i_arg) { char buf[80]; - snprintf(buf, sizeof(buf), "arg[%ud]", i_arg); + snprintf(buf, sizeof(buf), "arg[%u]", i_arg); auto arg_gco = argl_->at(i_arg); obj arg_pr @@ -372,11 +349,11 @@ namespace xo { pps->pretty(refrtag("expect", this->get_expect_str())); pps->newline_indent(ppii.ci1()); - pps->pretty(refrtag("n_args", n_args_)); + pps->pretty(refrtag("n_args", argl_->size())); - for (size_type i_arg = 0; i_arg < n_args_; ++i_arg) { + for (size_type i_arg = 0, n_arg = argl_->size(); i_arg < n_arg; ++i_arg) { char buf[80]; - snprintf(buf, sizeof(buf), "arg[%ud]", i_arg); + snprintf(buf, sizeof(buf), "arg[%u]", i_arg); auto arg_gco = argl_->at(i_arg); obj arg_pr diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 934b26ed..cedb4c1d 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -215,7 +215,7 @@ namespace xo { /** Walkthrough parsing input equivalent to: * - * lambda (n : i64; + * lambda (n : i64, * **/ @@ -279,11 +279,10 @@ namespace xo { REQUIRE(result.is_incomplete()); } -#ifdef NOT_YET { - auto & result = parser.on_token(Token::i64_token("777")); + auto & result = parser.on_token(Token::comma_token()); - log && log("after i64 token:"); + log && log("after comma token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); @@ -292,6 +291,43 @@ namespace xo { REQUIRE(result.is_incomplete()); } + { + auto & result = parser.on_token(Token::symbol_token("r")); + + log && log("after symbol(r) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::colon_token()); + + log && log("after colon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("i64")); + + log && log("after symbol(i64) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + +#ifdef NOT_YET { auto & result = parser.on_token(Token::else_token()); From 83d210b96824d863690b2dffd5f5fddb215aad65 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 29 Jan 2026 13:48:24 -0500 Subject: [PATCH 152/342] xo-reader2: DExpectFormalArglistSsm parses multiple formals --- include/xo/tokenizer2/Token.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index 55a2d57d..607bc0a4 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -106,7 +106,7 @@ namespace xo { /** token representing period @c "." **/ static Token dot() { return Token(tokentype::tk_dot); } /** token representing comma @c "," **/ - static Token comma() { return Token(tokentype::tk_comma); } + static Token comma_token() { return Token(tokentype::tk_comma); } /** token representing colon @c ":" **/ static Token colon_token() { return Token(tokentype::tk_colon); } /** token representing double-colo @c "::" **/ From 554c01ffadfcb0eec4ce3f20b4ffe99f5e026f1a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 29 Jan 2026 15:17:57 -0500 Subject: [PATCH 153/342] xo-reader2: + PSM,SSM on_parsed_formal_arglist() --- idl/SyntaxStateMachine.json5 | 9 ++++++ include/xo/reader2/DDefineSsm.hpp | 6 ++++ include/xo/reader2/DExpectExprSsm.hpp | 6 ++++ include/xo/reader2/DExpectFormalArgSsm.hpp | 6 ++++ .../xo/reader2/DExpectFormalArglistSsm.hpp | 8 ++++- include/xo/reader2/DExpectSymbolSsm.hpp | 6 ++++ include/xo/reader2/DExpectTypeSsm.hpp | 6 ++++ include/xo/reader2/DExprSeqState.hpp | 6 ++++ include/xo/reader2/DIfElseSsm.hpp | 6 ++++ include/xo/reader2/DLambdaSsm.hpp | 6 ++++ include/xo/reader2/DProgressSsm.hpp | 2 ++ include/xo/reader2/ParserStateMachine.hpp | 14 ++++++++- .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 ++ .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectExprSsm.hpp | 2 ++ ...SyntaxStateMachine_DExpectFormalArgSsm.hpp | 2 ++ ...axStateMachine_DExpectFormalArglistSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DIfElseSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DLambdaSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 2 ++ .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 ++ .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 ++ src/reader2/DDefineSsm.cpp | 9 ++++++ src/reader2/DExpectExprSsm.cpp | 9 ++++++ src/reader2/DExpectFormalArgSsm.cpp | 9 ++++++ src/reader2/DExpectFormalArglistSsm.cpp | 9 ++++++ src/reader2/DExpectSymbolSsm.cpp | 9 ++++++ src/reader2/DExpectTypeSsm.cpp | 9 ++++++ src/reader2/DExprSeqState.cpp | 9 ++++++ src/reader2/DIfElseSsm.cpp | 9 ++++++ src/reader2/DLambdaSsm.cpp | 9 ++++++ src/reader2/DProgressSsm.cpp | 9 ++++++ src/reader2/ISyntaxStateMachine_Any.cpp | 6 ++++ .../ISyntaxStateMachine_DDefineSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectExprSsm.cpp | 5 ++++ ...SyntaxStateMachine_DExpectFormalArgSsm.cpp | 5 ++++ ...axStateMachine_DExpectFormalArglistSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExprSeqState.cpp | 5 ++++ .../ISyntaxStateMachine_DIfElseSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DLambdaSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DProgressSsm.cpp | 5 ++++ src/reader2/ParserStateMachine.cpp | 30 ++++++++++++++++++- 48 files changed, 283 insertions(+), 3 deletions(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index fba93437..716b7268 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -82,6 +82,15 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_parsed_formal_arglist", + doc: ["consume formal arglist emitted by nested ssm"], + return_type: "void", + args: [ + {type: "DArray *", name: "arglist"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_parsed_expression", doc: ["update state machine for incoming parsed expression @p expr"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index bf0a3ffb..ebd454c0 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -202,6 +202,12 @@ namespace xo { TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal params @p arglist from completed nested ssm, + * with overall parser state in @p p_psm. + **/ + void on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 8e51124d..ae4154ef 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -142,6 +142,12 @@ namespace xo { TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal params @p arglist from completed nested ssm, + * with overall parser state in @p p_psm. + **/ + void on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectFormalArgSsm.hpp b/include/xo/reader2/DExpectFormalArgSsm.hpp index ee5eb0ea..51eb6536 100644 --- a/include/xo/reader2/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/DExpectFormalArgSsm.hpp @@ -112,6 +112,12 @@ namespace xo { TypeDescr td, ParserStateMachine * p_psm); + /** consume formal params @p arglist from completed nested ssm, + * with overall parser state in @p p_psm. + **/ + void on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm); + /** update state on parsed expression emitted by nested ssm * with overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index 2898fa7c..289b7cf5 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -114,6 +114,12 @@ namespace xo { TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal params @p arglist from completed nested ssm, + * with overall parser state in @p p_psm. + **/ + void on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm); + /** update state on parsed expression emitted by nested ssm * with overall parser state in @p p_psm **/ @@ -144,7 +150,7 @@ namespace xo { private: /** parsing state-machine state **/ formalarglstatetype fastate_ = formalarglstatetype::argl_0; - /** populate with (parmaeter-name, parameter-type) list + /** populate with (parameter-name, parameter-type) list * as they're encountered. * * Not using flexible array here since we don't know size at construction time diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 080380b9..accfa936 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -85,6 +85,12 @@ namespace xo { TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal params @p arglist from completed nested ssm, + * with overall parser state in @p p_psm. + **/ + void on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr * in nested state machine. * (provided to satisfy ASyntaxStateMachine api. not reachable) diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 3ca99815..729eac83 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -136,6 +136,12 @@ namespace xo { TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal params @p arglist from completed nested ssm, + * with overall parser state in @p p_psm. + **/ + void on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm); + /** operate state machine for this syntax on receiving expression * from nested parser. * (provided to satisfy ASyntaxStateMachine api. not reachable) diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index c718cbef..a7b19c28 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -145,6 +145,12 @@ namespace xo { TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal params @p arglist from completed nested ssm, + * with overall parser state in @p p_psm. + **/ + void on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm); + /** update state for this syntax on parsed expression @p expr * from nested ssm. * overall parser state in @p p_psm diff --git a/include/xo/reader2/DIfElseSsm.hpp b/include/xo/reader2/DIfElseSsm.hpp index 647a5e34..62f7d137 100644 --- a/include/xo/reader2/DIfElseSsm.hpp +++ b/include/xo/reader2/DIfElseSsm.hpp @@ -159,6 +159,12 @@ namespace xo { TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal params @p arglist from completed nested ssm, + * with overall parser state in @p p_psm. + **/ + void on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm); + /** update state for this syntax after parsing an expression @p expr, * overall parser state in @p p_psm. **/ diff --git a/include/xo/reader2/DLambdaSsm.hpp b/include/xo/reader2/DLambdaSsm.hpp index 69cb3322..8800ad1c 100644 --- a/include/xo/reader2/DLambdaSsm.hpp +++ b/include/xo/reader2/DLambdaSsm.hpp @@ -123,6 +123,12 @@ namespace xo { TypeDescr td, ParserStateMachine * p_psm); + /** consume formal params @p arglist from completed nested ssm, + * with overall parser state in @p p_psm. + **/ + void on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm); + /** update this ssm when nested parser * emits expression @p expr **/ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index fa0ec733..ae9c2244 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -173,6 +173,8 @@ namespace xo { void on_parsed_formal(const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + void on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm); void on_parsed_expression(obj, ParserStateMachine * p_psm); void on_parsed_expression_with_semicolon(obj expr, diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 74f27876..1c5729a6 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -103,11 +104,16 @@ namespace xo { void on_parsed_typedescr(TypeDescr td); /** update state to consume param (name, value) emitted by - * nested (but not popped) parsing state + * nested (expired) parsing state **/ void on_parsed_formal(const DUniqueString * param_name, TypeDescr param_type); + /** update state to consume formal arugment list + * emitted by nested (expired) parsing state + **/ + void on_parsed_formal_arglist(DArray * arglist); + /** update state to respond to parsed expression @p expr * (from nested parsing state) **/ @@ -178,6 +184,12 @@ namespace xo { TypeDescr param_type, std::string_view expect_str); + /** @p arglist stores obj pointers. + **/ + void illegal_parsed_formal_arglist(std::string_view ssm_name, + DArray * arglist, + std::string_view expect_str); + /** report illegal parsed expression from nested ssm. * Introducing as placeholder; not clear if this will be reachable * in full parser diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index 6cc3b829..b9df6e6d 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -65,6 +65,8 @@ public: virtual void on_parsed_typedescr(Opaque data, TypeDescr td, ParserStateMachine * p_psm) = 0; /** operate state machine for formal emitted by nested ssm **/ virtual void on_parsed_formal(Opaque data, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) = 0; + /** consume formal arglist emitted by nested ssm **/ + virtual void on_parsed_formal_arglist(Opaque data, DArray * arglist, ParserStateMachine * p_psm) = 0; /** update state machine for incoming parsed expression @p expr **/ virtual void on_parsed_expression(Opaque data, obj expr, ParserStateMachine * p_psm) = 0; /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 3faa0f67..e239c46b 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -64,6 +64,7 @@ namespace scm { [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; [[noreturn]] void on_parsed_formal(Opaque, const DUniqueString *, TypeDescr, ParserStateMachine *) override; + [[noreturn]] void on_parsed_formal_arglist(Opaque, DArray *, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression(Opaque, obj, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression_with_semicolon(Opaque, obj, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index f4d0da9d..42616a38 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DDefineSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 3ff00e07..53669967 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DExpectExprSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectExprSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExpectExprSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp index adce6eb9..99d6c9a9 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DExpectFormalArgSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectFormalArgSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExpectFormalArgSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp index b8a3b416..570ee3a4 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DExpectFormalArglistSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectFormalArglistSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExpectFormalArglistSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index d778e293..2003db8a 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DExpectSymbolSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectSymbolSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExpectSymbolSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index 9d6f153a..acb752fe 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DExpectTypeSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExpectTypeSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index d958f1f8..3c160d00 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DExprSeqState & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExprSeqState & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExprSeqState & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExprSeqState & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp index 88a8b7d8..462172d2 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DIfElseSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DIfElseSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DIfElseSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp index 02582d0b..fa0cb0a2 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DLambdaSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DLambdaSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DLambdaSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index ee2dfbaf..ddd0c06e 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DProgressSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DProgressSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DProgressSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DProgressSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr followed by semicolon **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 51ab0f30..e89357ab 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -64,6 +64,9 @@ namespace scm { void on_parsed_formal(Opaque data, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) override { return I::on_parsed_formal(_dcast(data), param_name, param_type, p_psm); } + void on_parsed_formal_arglist(Opaque data, DArray * arglist, ParserStateMachine * p_psm) override { + return I::on_parsed_formal_arglist(_dcast(data), arglist, p_psm); + } void on_parsed_expression(Opaque data, obj expr, ParserStateMachine * p_psm) override { return I::on_parsed_expression(_dcast(data), expr, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 3de33f8e..0e2b8636 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -68,6 +68,9 @@ public: void on_parsed_formal(const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) { return O::iface()->on_parsed_formal(O::data(), param_name, param_type, p_psm); } + void on_parsed_formal_arglist(DArray * arglist, ParserStateMachine * p_psm) { + return O::iface()->on_parsed_formal_arglist(O::data(), arglist, p_psm); + } void on_parsed_expression(obj expr, ParserStateMachine * p_psm) { return O::iface()->on_parsed_expression(O::data(), expr, p_psm); } diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 65df6349..1636c4b0 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -715,6 +715,15 @@ namespace xo { this->get_expect_str()); } + void + DDefineSsm::on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal_arglist("DDefineSsm::on_parsed_formal_arglist", + arglist, + this->get_expect_str()); + } + void DDefineSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 2a836e87..c7fe298a 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -365,6 +365,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectExprSsm::on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal_arglist("DExpectExprSsm::on_parsed_formal_arglist", + arglist, + this->get_expect_str()); + } + void DExpectExprSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index eb174fc9..4aaf7c4b 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -212,6 +212,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectFormalArgSsm::on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal_arglist("DExpectFormalArgSsm::on_parsed_formal_arglist", + arglist, + this->get_expect_str()); + } + void DExpectFormalArgSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 676e0a9e..63113f4e 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -241,6 +241,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectFormalArglistSsm::on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal_arglist("DExpectFormalArglistSsm::on_parsed_formal_arglist", + arglist, + this->get_expect_str()); + } + void DExpectFormalArglistSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index cee3a08c..60985cae 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -84,6 +84,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectSymbolSsm::on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal_arglist("DExpectSymbolSsm::on_parsed_formal_arglist", + arglist, + this->get_expect_str()); + } + void DExpectSymbolSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 8f848269..5e42f758 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -285,6 +285,15 @@ namespace xo { this->get_expect_str()); } + void + DExpectTypeSsm::on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal_arglist("DExpectTypeSsm::on_parsed_formal_arglist", + arglist, + this->get_expect_str()); + } + void DExpectTypeSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 5d9fe9b1..12847350 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -460,6 +460,15 @@ namespace xo { this->get_expect_str()); } + void + DExprSeqState::on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal_arglist("DExprSeqState::on_parsed_formal_arglist", + arglist, + this->get_expect_str()); + } + void DExprSeqState::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index 9f7d7167..f0bf9556 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -391,6 +391,15 @@ namespace xo { } + void + DIfElseSsm::on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal_arglist("DIfElseSsm::on_parsed_formal_arglist", + arglist, + this->get_expect_str()); + } + #ifdef NOT_YET void if_else_xs::on_expr(bp expr, diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index f9fcd6ae..99e01ffd 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -349,6 +349,15 @@ namespace xo { this->get_expect_str()); } + void + DLambdaSsm::on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal_arglist("DLambdaSsm::on_parsed_formal_arglist", + arglist, + this->get_expect_str()); + } + void DLambdaSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 1233c198..57e21ec8 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -566,6 +566,15 @@ namespace xo { this->get_expect_str()); } + void + DProgressSsm::on_parsed_formal_arglist(DArray * arglist, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal_arglist("DProgressSsm::on_parsed_formal_arglist", + arglist, + this->get_expect_str()); + } + void DProgressSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 2a16a292..18510abb 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -58,6 +58,12 @@ ISyntaxStateMachine_Any::on_parsed_formal(Opaque, const DUniqueString *, TypeDes _fatal(); } +auto +ISyntaxStateMachine_Any::on_parsed_formal_arglist(Opaque, DArray *, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_parsed_expression(Opaque, obj, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index 7117484b..80dc0c81 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DDefineSsm::on_parsed_formal_arglist(DDefineSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto ISyntaxStateMachine_DDefineSsm::on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index b0f5861d..d6b44995 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DExpectExprSsm::on_parsed_formal_arglist(DExpectExprSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto ISyntaxStateMachine_DExpectExprSsm::on_parsed_expression(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp index a242df29..b3337d4e 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_formal_arglist(DExpectFormalArgSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_expression(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp index 006d122b..318283a3 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_formal_arglist(DExpectFormalArglistSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_expression(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index b7f208e8..77b083d6 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_formal_arglist(DExpectSymbolSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_expression(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 473bd4b7..ffd0b209 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DExpectTypeSsm::on_parsed_formal_arglist(DExpectTypeSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto ISyntaxStateMachine_DExpectTypeSsm::on_parsed_expression(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index d11ab3b7..5a9c2e3a 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DExprSeqState::on_parsed_formal_arglist(DExprSeqState & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto ISyntaxStateMachine_DExprSeqState::on_parsed_expression(DExprSeqState & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp index 39a3abb2..94aa8be5 100644 --- a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DIfElseSsm::on_parsed_formal_arglist(DIfElseSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto ISyntaxStateMachine_DIfElseSsm::on_parsed_expression(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp index e59546c8..2a03a774 100644 --- a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DLambdaSsm::on_parsed_formal_arglist(DLambdaSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto ISyntaxStateMachine_DLambdaSsm::on_parsed_expression(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 6fe3f822..1f161ffc 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DProgressSsm::on_parsed_formal_arglist(DProgressSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto ISyntaxStateMachine_DProgressSsm::on_parsed_expression(DProgressSsm & self, obj expr, ParserStateMachine * p_psm) -> void { self.on_parsed_expression(expr, p_psm); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 911b594a..0316515e 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -6,6 +6,8 @@ #include "ParserStateMachine.hpp" #include "ParserStack.hpp" #include "SyntaxStateMachine.hpp" +#include +#include #include #include #include @@ -13,6 +15,7 @@ #include namespace xo { + using xo::print::APrintable; using xo::facet::with_facet; namespace scm { @@ -140,6 +143,17 @@ namespace xo { this->stack_->top().on_parsed_formal(sym, td, this); } + void + ParserStateMachine::on_parsed_formal_arglist(DArray * arglist) + { + scope log(XO_DEBUG(debug_flag_), + xtag("arglist", obj(arglist))); + + assert(stack_); + + this->stack_->top().on_parsed_formal_arglist(arglist, this); + } + void ParserStateMachine::on_parsed_expression(obj expr) { @@ -269,7 +283,7 @@ namespace xo { // - want to write error message using DArena // - need something like log_streambuf and/or tostr() that's arena-aware - auto errmsg_string = tostr("Unexpected expression", + auto errmsg_string = tostr("Unexpected formal", xtag("param_name", std::string_view(*param_name)), xtag("param_type", param_type), xtag("expecting", expect_str), @@ -284,6 +298,20 @@ namespace xo { this->capture_error(ssm_name, errmsg); } + void + ParserStateMachine::illegal_parsed_formal_arglist(std::string_view ssm_name, + DArray * arglist, + std::string_view expect_str) + { + obj arglist_pr(arglist); + + auto errmsg_string = tostr("Unexpected formal arglist", + xtag("arglist", arglist_pr), + xtag("expecting", expect_str), + xtag("ssm", ssm_name), + xtag("via", "ParserStateMachine::illegal_parsed_formal_arglist")); + } + void ParserStateMachine::illegal_parsed_expression(std::string_view ssm_name, obj expr, From 985e572b21322b56fe3d101669fd20d7fef60a85 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 29 Jan 2026 15:19:35 -0500 Subject: [PATCH 154/342] xo-object2: missed generated (Printable,Array) code + .json5 --- include/xo/reader2/DSyntaxStateMachine.hpp | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 include/xo/reader2/DSyntaxStateMachine.hpp diff --git a/include/xo/reader2/DSyntaxStateMachine.hpp b/include/xo/reader2/DSyntaxStateMachine.hpp new file mode 100644 index 00000000..4aa35f4d --- /dev/null +++ b/include/xo/reader2/DSyntaxStateMachine.hpp @@ -0,0 +1,42 @@ +/** @file DSyntaxStateMachine.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include + +namespace xo { + namespace scm { + + /** @class DSyntaxStateMachine + * @brief static interface for implementing ASyntaxStateMachine + * + * Using CRTP to collect methods common to ASyntaxStateMachine + * implementations. + * + * Deliberately unusable through base class pointer. + * For runtime polymorphism use something like: + * @code + * Derived * d = ...; + * auto obj = with_facet::mkobj(d); + * // or + * obj(d) + * @endcode + **/ + template + class DSyntaxStateMachine { + friend Derived; + + /** arglist is DArray of obj **/ + void on_parsed_formal_arglist(this auto&& self, DArray * arglist, ParserStateMachine * p_psm) { + p_psm->illegal_parsed_formal_arglist( + + } + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DSyntaxStateMachine.hpp */ From f5ccd99dd2a6ae71219d78d13944343b3056726b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 10:26:35 -0500 Subject: [PATCH 155/342] xo-expression2 xo-reader2: local symtab stack in PSM --- .../xo/reader2/DExpectFormalArglistSsm.hpp | 8 ++- include/xo/reader2/DLambdaSsm.hpp | 4 +- include/xo/reader2/ParserStateMachine.hpp | 31 ++++++++++- src/reader2/DExpectFormalArglistSsm.cpp | 25 +++++---- src/reader2/DLambdaSsm.cpp | 52 +++++++++++++++++++ src/reader2/ParserStack.cpp | 2 +- src/reader2/ParserStateMachine.cpp | 20 +++++++ utest/SchematikaParser.test.cpp | 6 +-- 8 files changed, 127 insertions(+), 21 deletions(-) diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index 289b7cf5..81d7e85d 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -71,14 +71,18 @@ namespace xo { /** @defgroup scm-expectformalarglistssm-methods general methods **/ ///@{ - /** update state on incoming token @p tk, with overall parser state in @p psm **/ + /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); - /** update state on incoming token @p tk, with overall parser state in @p psm **/ + /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ void on_comma_token(const Token & tk, ParserStateMachine * p_psm); + /** update state on incoming rightparen token @p tk, with overall parser state in @p p_psm **/ + void on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expectformalarglistssm-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/include/xo/reader2/DLambdaSsm.hpp b/include/xo/reader2/DLambdaSsm.hpp index 8800ad1c..22185269 100644 --- a/include/xo/reader2/DLambdaSsm.hpp +++ b/include/xo/reader2/DLambdaSsm.hpp @@ -144,8 +144,6 @@ namespace xo { #ifdef NOT_YET virtual const char * get_expect_str() const override; - virtual void on_formal_arglist(const std::vector> & argl, - parserstatemachine * p_psm) override; virtual void on_leftbrace_token(const token_type & tk, parserstatemachine * p_psm) override; virtual void on_colon_token(const token_type & tk, @@ -173,10 +171,10 @@ namespace xo { /** parsing state-machine state **/ lambdastatetype lmstate_ = lambdastatetype::lm_0; -#ifdef NOT_YET /** lambda environment (for formal parameters) **/ DLocalSymtab * local_symtab_ = nullptr; +#ifdef NOT_YET /** explicit return type (if supplied) **/ TypeDescr explicit_return_td_ = nullptr; diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 1c5729a6..fbf636e3 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -6,6 +6,8 @@ #pragma once #include "ParserResult.hpp" +#include +#include #include #include #include @@ -47,6 +49,7 @@ namespace xo { bool debug_flag() const noexcept { return debug_flag_; } ParserStack * stack() const noexcept { return stack_; } obj expr_alloc() const noexcept { return expr_alloc_; } + DLocalSymtab * local_symtab() const noexcept { return local_symtab_; } const ParserResult & result() const noexcept { return result_; } /** true iff state machine is currently idle (at top-level) **/ @@ -79,6 +82,15 @@ namespace xo { **/ const DUniqueString * intern_string(std::string_view str); + /** push nested local symtab while parsing the body of a lambda expression; + * restore previous symtab at the end of lambda-expression definition. + * See @ref pop_local_symtab + **/ + void push_local_symtab(DLocalSymtab * symtab); + + /** pop nested symbol table from symbol-table stack **/ + void pop_local_symtab(); + /** add variable to current local environment (innermost lexical scope) **/ void upsert_var(DVariable * var); @@ -219,8 +231,10 @@ namespace xo { * after encountering a parsing error. **/ DArena::Checkpoint parser_alloc_ckp_; - - /** parser stack. Memory from @ref parser_alloc_ **/ + /** parser stack. Memory always from @ref parser_alloc_; + * elements that should survive parsing allocate from + * @ref expr_alloc_, see below. + **/ ParserStack * stack_ = nullptr; /** Allocator for parsed expressions. @@ -239,6 +253,19 @@ namespace xo { **/ obj expr_alloc_; + /** symbol table with local bindings. + * non-null during parsing of lambda expressions. + * Always allocated from @p expr_alloc_. + * Push local symbol table here to remember local params + * during the body of a lambda expression. + **/ + DLocalSymtab * local_symtab_ = nullptr; + + /** global symbol table. + * Toplevel definitions go here. + **/ + DGlobalSymtab * global_symtab_ = nullptr; + /** current output from parser **/ ParserResult result_; diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 63113f4e..bebe4108 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -126,6 +126,10 @@ namespace xo { this->on_comma_token(tk, p_psm); return; + case tokentype::tk_rightparen: + this->on_rightparen_token(tk, p_psm); + return; + // all the not-yet-handled cases case tokentype::tk_lambda: case tokentype::tk_def: @@ -139,7 +143,6 @@ namespace xo { case tokentype::tk_bool: case tokentype::tk_semicolon: case tokentype::tk_invalid: - case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: @@ -300,20 +303,22 @@ namespace xo { this->get_expect_str()); } -#ifdef NOT_YET void - expect_formal_arglist_xs::on_rightparen_token(const token_type & tk, - parserstatemachine * p_psm) + DExpectFormalArglistSsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) { - if (farglxs_type_ == formalarglstatetype::argl_1b) { - std::unique_ptr self = p_psm->pop_exprstate(); + if (fastate_ == formalarglstatetype::argl_1b) { + DArray * args = argl_; - p_psm->top_exprstate().on_formal_arglist(this->argl_, p_psm); - } else { - exprstate::on_rightparen_token(tk, p_psm); + p_psm->pop_ssm(); + p_psm->on_parsed_formal_arglist(args); + return; } + + p_psm->illegal_input_on_token("DExpectFormalArglistSsm::on_rightparen_token", + tk, + this->get_expect_str()); } -#endif bool DExpectFormalArglistSsm::pretty(const ppindentinfo & ppii) const diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 99e01ffd..4bcbb844 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -9,6 +9,9 @@ #include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" #include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" +#include +#include +//#include #include #include #include @@ -28,6 +31,7 @@ namespace xo { using xo::print::APrintable; using xo::mm::AAllocator; + using xo::mm::AGCObject; using xo::facet::FacetRegistry; using xo::reflect::typeseq; @@ -353,6 +357,54 @@ namespace xo { DLambdaSsm::on_parsed_formal_arglist(DArray * arglist, ParserStateMachine * p_psm) { + if (lmstate_ == lambdastatetype::lm_1) { + this->lmstate_ = lambdastatetype::lm_2; + /// something with top env frame ? + + /// TODO: arena-friendly non-gc-aware vector; + // use instead of DArray for arglist. + // something like DTypedArray + + /// create LocalSymtab from arglist + + DLocalSymtab * symtab + = DLocalSymtab::_make_empty(p_psm->expr_alloc(), + p_psm->local_symtab(), + arglist->size()); + assert(symtab); + + for (DArray::size_type i = 0, n = arglist->size(); i < n; ++i) { + obj param = arglist->at(i); + + // sad! runtime poly conversion from obj + // We on need this because of (suboptimally) using DArray to store arglist + + obj param_expr + = FacetRegistry::instance().variant(param); + obj param_var + = obj::from(param_expr); + + assert(param_expr.data()); + assert(param_var.data()); + + Binding b = symtab->append_var(p_psm->expr_alloc(), + param_var.data()->name(), + param_var.data()->typeref()); + + assert(b.is_local()); + + this->local_symtab_ = symtab; + } + + // stash env frame: records local variables while we handle lambda body + + p_psm->push_local_symtab(symtab); + + // control reenters via .on_colon_token() / .on_leftbrace_token() + + return; + } + p_psm->illegal_parsed_formal_arglist("DLambdaSsm::on_parsed_formal_arglist", arglist, this->get_expect_str()); diff --git a/src/reader2/ParserStack.cpp b/src/reader2/ParserStack.cpp index 9af9f339..e3ffb290 100644 --- a/src/reader2/ParserStack.cpp +++ b/src/reader2/ParserStack.cpp @@ -70,7 +70,7 @@ namespace xo { std::size_t i_frame = 0; while (frame) { - char buf[80]; + char buf[32]; snprintf(buf, sizeof(buf), "[%lu]", i_frame); auto ssm = (FacetRegistry::instance().variant diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 0316515e..085cce56 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -88,6 +88,20 @@ namespace xo { return stringtable_.intern(str); } + void + ParserStateMachine::push_local_symtab(DLocalSymtab * symtab) + { + this->local_symtab_ = symtab; + } + + void + ParserStateMachine::pop_local_symtab() + { + assert(local_symtab_); + + this->local_symtab_ = local_symtab_->parent(); + } + void ParserStateMachine::upsert_var(DVariable * var) { @@ -310,6 +324,12 @@ namespace xo { xtag("expecting", expect_str), xtag("ssm", ssm_name), xtag("via", "ParserStateMachine::illegal_parsed_formal_arglist")); + + assert(expr_alloc_); + + auto errmsg = DString::from_str(expr_alloc_, errmsg_string); + + this->capture_error(ssm_name, errmsg); } void diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index cedb4c1d..cc1e51fa 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -327,11 +327,10 @@ namespace xo { REQUIRE(result.is_incomplete()); } -#ifdef NOT_YET { - auto & result = parser.on_token(Token::else_token()); + auto & result = parser.on_token(Token::rightparen_token()); - log && log("after else token:"); + log && log("after rightparen token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); @@ -340,6 +339,7 @@ namespace xo { REQUIRE(result.is_incomplete()); } +#ifdef NOT_YET { auto & result = parser.on_token(Token::string_token("fooey")); From 900d675caac058e24e5113d78dc5e7d99c99be93 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 10:26:35 -0500 Subject: [PATCH 156/342] xo-expression2 xo-reader2: local symtab stack in PSM --- include/xo/tokenizer2/Token.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index 607bc0a4..66427c3e 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -94,7 +94,7 @@ namespace xo { /** token representing left parenthesis @c "(" **/ static Token leftparen_token() { return Token(tokentype::tk_leftparen); } /** Token representing right parenthesis @c ")" **/ - static Token rightparen() { return Token(tokentype::tk_rightparen); } + static Token rightparen_token() { return Token(tokentype::tk_rightparen); } /** token representing left bracket @c "[" **/ static Token leftbracket() { return Token(tokentype::tk_leftbracket); } /** token representing right bracket @c "]" **/ From fcf171dfb64aeb51e26c972baae722a3d17a8f87 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 12:41:09 -0500 Subject: [PATCH 157/342] xo-reader2: + assemble lambda function type in DLambdaSsm --- include/xo/reader2/DExpectExprSsm.hpp | 3 +- include/xo/reader2/DLambdaSsm.hpp | 8 +- src/reader2/DDefineSsm.cpp | 3 +- src/reader2/DExpectExprSsm.cpp | 5 +- src/reader2/DIfElseSsm.cpp | 7 +- src/reader2/DLambdaSsm.cpp | 164 +++++++------------------- src/reader2/DProgressSsm.cpp | 8 +- utest/SchematikaParser.test.cpp | 36 ++++++ 8 files changed, 97 insertions(+), 137 deletions(-) diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index ae4154ef..accdbff3 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -32,8 +32,7 @@ namespace xo { bool allow_defs, bool cxl_on_rightparen, ParserStateMachine * p_psm); - static void start(DArena & parser_mm, - ParserStateMachine * p_psm); + static void start(ParserStateMachine * p_psm); /** @defgroup scm-expectexpr-access-methods access methods **/ ///@{ diff --git a/include/xo/reader2/DLambdaSsm.hpp b/include/xo/reader2/DLambdaSsm.hpp index 22185269..1be39031 100644 --- a/include/xo/reader2/DLambdaSsm.hpp +++ b/include/xo/reader2/DLambdaSsm.hpp @@ -88,6 +88,12 @@ namespace xo { void on_lambda_token(const Token & tk, ParserStateMachine * p_psm); + /** update ssm on yield token @p tk, + * with overall parser state in @p p_psm + **/ + void on_yields_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-lambdassm-syntaxstatemachine-facet **/ ///@{ @@ -174,13 +180,11 @@ namespace xo { /** lambda environment (for formal parameters) **/ DLocalSymtab * local_symtab_ = nullptr; -#ifdef NOT_YET /** explicit return type (if supplied) **/ TypeDescr explicit_return_td_ = nullptr; /** lambda signature (when known) **/ TypeDescr lambda_td_ = nullptr; -#endif /** body expression **/ obj body_; diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 1636c4b0..4e2bcf97 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -643,8 +643,7 @@ namespace xo { { this->defstate_ = defexprstatetype::def_5; - DExpectExprSsm::start(p_psm->parser_alloc(), - p_psm); + DExpectExprSsm::start(p_psm); return; } diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index c7fe298a..3f99daca 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -83,10 +83,9 @@ namespace xo { } void - DExpectExprSsm::start(DArena & mm, - ParserStateMachine * p_psm) + DExpectExprSsm::start(ParserStateMachine * p_psm) { - start(mm, + start(p_psm->parser_alloc(), false /*!allow_defs*/, false /*!cxl_on_rightbrace*/, p_psm); diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index f0bf9556..fb66701a 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -215,8 +215,7 @@ namespace xo { if (ifstate_ == ifexprstatetype::if_0) { this->ifstate_ = ifexprstatetype::if_1; - DExpectExprSsm::start(p_psm->parser_alloc(), - p_psm); + DExpectExprSsm::start(p_psm); return; } @@ -236,7 +235,7 @@ namespace xo { if (ifstate_ == ifexprstatetype::if_2) { this->ifstate_ = ifexprstatetype::if_3; - DExpectExprSsm::start(p_psm->parser_alloc(), p_psm); + DExpectExprSsm::start(p_psm); return; } @@ -279,7 +278,7 @@ namespace xo { if (ifstate_ == ifexprstatetype::if_4) { this->ifstate_ = ifexprstatetype::if_5; - DExpectExprSsm::start(p_psm->parser_alloc(), p_psm); + DExpectExprSsm::start(p_psm); return; } diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 4bcbb844..3e33c627 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -7,6 +7,8 @@ #include "ssm/ISyntaxStateMachine_DLambdaSsm.hpp" #include "DExpectFormalArglistSsm.hpp" #include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" +#include "DExpectTypeSsm.hpp" +#include "DExpectExprSsm.hpp" #include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" #include @@ -89,11 +91,11 @@ namespace xo { DLambdaSsm::get_expect_str() const noexcept { /* - * lambda (x : f64) : f64 { ... } ; - * ^ ^ ^ ^ ^ ^ - * | | | | | lm_5 - * | | | | lm_4:expect_expression - * | | | lm_3 + * lambda (x : f64) -> f64 { ... } ; + * ^ ^ ^ ^ ^ ^ + * | | | | | lm_5 + * | | | | lm_4:expect_expression + * | | | lm_3 * | | lm_2 * | lm_1: * expect_expression @@ -108,7 +110,7 @@ namespace xo { case lambdastatetype::lm_1: return "lambda-params"; case lambdastatetype::lm_2: - return "colon|lambda-body"; + return "yields|lambda-body"; case lambdastatetype::lm_3: return "type"; case lambdastatetype::lm_4: @@ -129,6 +131,10 @@ namespace xo { this->on_lambda_token(tk, p_psm); return; + case tokentype::tk_yields: + this->on_yields_token(tk, p_psm); + return; + // all the not-yet-handled cases case tokentype::tk_def: case tokentype::tk_if: @@ -155,7 +161,6 @@ namespace xo { case tokentype::tk_comma: case tokentype::tk_doublecolon: case tokentype::tk_assign: - case tokentype::tk_yields: case tokentype::tk_plus: case tokentype::tk_minus: case tokentype::tk_star: @@ -194,25 +199,44 @@ namespace xo { this->get_expect_str()); } - -#ifdef NOT_YET void - lambda_xs::on_formal_arglist(const std::vector> & argl, - parserstatemachine * p_psm) + DLambdaSsm::on_yields_token(const Token & tk, + ParserStateMachine * p_psm) { - if (lmxs_type_ == lambdastatetype::lm_1) { - this->lmxs_type_ = lambdastatetype::lm_2; - this->parent_env_ = p_psm->top_envframe().promote(); - this->local_env_ = LocalSymtab::make(argl, parent_env_); + if (lmstate_ == lambdastatetype::lm_2) { + this->lmstate_ = lambdastatetype::lm_3; - p_psm->push_envframe(local_env_); + DExpectTypeSsm::start(p_psm); - //expect_expr_xs::start(p_psm); - } else { - exprstate::on_formal_arglist(argl, p_psm); + /* control reenters via .on_parsed_typedescr() */ + return; } + + p_psm->illegal_input_on_token("DLambdaSsm::on_yields_token", + tk, + this->get_expect_str()); } + + void + DLambdaSsm::on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm) + { + if (lmstate_ == lambdastatetype::lm_3) { + this->lmstate_ = lambdastatetype::lm_4; + this->explicit_return_td_ = td; + this->lambda_td_ = DLambdaExpr::assemble_lambda_td(local_symtab_, td); + + DExpectExprSsm::start(p_psm); + return; + } + + p_psm->illegal_input_on_typedescr("DLambdaSsm::on_parsed_typedescr", + td, + this->get_expect_str()); + } + +#ifdef NOT_YET void lambda_xs::on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) @@ -221,21 +245,6 @@ namespace xo { this->on_semicolon_token(token_type::semicolon(), p_psm); } - void - lambda_xs::on_colon_token(const token_type & tk, - parserstatemachine * p_psm) - { - constexpr const char * c_self_name = "lambda_xs::on_colon_token"; - - if (lmxs_type_ == lambdastatetype::lm_2) { - this->lmxs_type_ = lambdastatetype::lm_3; - expect_type_xs::start(p_psm); - /* control reenters via .on_typedescr() */ - } else { - this->illegal_input_on_token(c_self_name, tk, this->get_expect_str(), p_psm); - } - } - void lambda_xs::on_leftbrace_token(const token_type & tk, parserstatemachine * p_psm) @@ -255,84 +264,6 @@ namespace xo { } #endif - void - DLambdaSsm::on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_typedescr("DLambdaSsm::on_parsed_typedescr", - td, - this->get_expect_str()); - } - -#ifdef NOT_YET - void - lambda_xs::on_typedescr(TypeDescr td, - parserstatemachine * p_psm) - { - constexpr const char * c_self_name = "lambda_xs::on_typedescr"; - scope log(XO_DEBUG(p_psm->debug_flag())); - - assert(td); - - if (lmxs_type_ == lambdastatetype::lm_3) { - this->lmxs_type_ = lambdastatetype::lm_4; - this->explicit_return_td_ = td; - - this->lambda_td_ = Lambda::assemble_lambda_td(local_env_->argv(), - explicit_return_td_); - - /* 1. at this point we know function signature (@ref lambda_td_) - * 2. if this lambda appears on the rhs of a define, - * propagate function signature to the define. - * 3. this makes recursive function definitions like this work - * without relying on type inference: - * def fact = lambda (n : i64) : i64 { - * if (n == 0) then - * 1 - * else - * n * fact(n - 1) - * } - * 4. while parsing the body of the lambda, we want environment - * to already associate the lambda's signature with variable 'fact', - * so that when parser encounters 'fact(n - 1)' the expression has - * known valuetype. - */ - - if ((p_psm->exprstate_stack_size() >= 3) - && (p_psm->lookup_exprstate(1).exs_type() == exprstatetype::expect_rhs_expression) - && (p_psm->lookup_exprstate(2).exs_type() == exprstatetype::defexpr) - && (p_psm->env_stack_size() >= 2) - ) - { - const define_xs * def_xs = dynamic_cast(&(p_psm->lookup_exprstate(2))); - - assert(def_xs); - - bp def_var = def_xs->lhs_variable(); - - if (def_var->valuetype() == nullptr) { - log && log("assign discovered lambda type T to enclosing define", - xtag("lhs", def_var.get()), - xtag("T", print::unq(this->lambda_td_->canonical_name()))); - - def_var->assign_valuetype(lambda_td_); - } else { - /* don't need to unify here. if def already hasa a type, - * that's because it was explicitly specified. - * will discover any conflict after reporting parsed lambda - * to define_xs - */ - } - } - - expect_expr_xs::start(p_psm); - /* control reenters via .on_expr() or .on_expr_with_semicolon() */ - } else { - this->illegal_input_on_type(c_self_name, td, this->get_expect_str(), p_psm); - } - } -#endif - void DLambdaSsm::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) @@ -376,8 +307,9 @@ namespace xo { for (DArray::size_type i = 0, n = arglist->size(); i < n; ++i) { obj param = arglist->at(i); + // TODO: // sad! runtime poly conversion from obj - // We on need this because of (suboptimally) using DArray to store arglist + // We need this because of (suboptimally) using DArray to store arglist obj param_expr = FacetRegistry::instance().variant(param); @@ -503,12 +435,6 @@ namespace xo { // TODO: on_i64_token, on_bool token - void - lambda_xs::print(std::ostream & os) const { - os << ""; - } #endif bool diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 57e21ec8..5a6317a3 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -398,7 +398,7 @@ namespace xo { // tk is the operator this instance was waiting for this->op_type_ = tk2op(tk.tk_type()); - DExpectExprSsm::start(p_psm->parser_alloc(), p_psm); + DExpectExprSsm::start(p_psm); return; } else if (rhs_) { optype op_type2 = tk2op(tk.tk_type()); @@ -441,15 +441,13 @@ namespace xo { lhs_, op_type_, p_psm); - DExpectExprSsm::start(p_psm->parser_alloc(), - p_psm); + DExpectExprSsm::start(p_psm); /* (b * ..) */ DProgressSsm::start(p_psm->parser_alloc(), rhs_, op_type2, p_psm); - DExpectExprSsm::start(p_psm->parser_alloc(), - p_psm); + DExpectExprSsm::start(p_psm); return; } } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index cc1e51fa..0d7dbba4 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -339,7 +339,43 @@ namespace xo { REQUIRE(result.is_incomplete()); } + { + auto & result = parser.on_token(Token::yields_token()); + + log && log("after yields token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("i64")); + + log && log("after symbol(i64) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + #ifdef NOT_YET + { + auto & result = parser.on_token(Token::leftbrace_token()); + + log && log("after leftbrace token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + { auto & result = parser.on_token(Token::string_token("fooey")); From e3006f32666983e2040811f5512a1b93d9b35f15 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 12:41:09 -0500 Subject: [PATCH 158/342] xo-reader2: + assemble lambda function type in DLambdaSsm --- include/xo/tokenizer2/Token.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index 66427c3e..fc5dfc9a 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -100,7 +100,7 @@ namespace xo { /** token representing right bracket @c "]" **/ static Token rightbracket() { return Token(tokentype::tk_rightbracket); } /** token representing left brace @c "{" **/ - static Token leftbrace() { return Token(tokentype::tk_leftbrace); } + static Token leftbrace_token() { return Token(tokentype::tk_leftbrace); } /** token representing right brace @c "}" **/ static Token rightbrace() { return Token(tokentype::tk_rightbrace); } /** token representing period @c "." **/ @@ -117,8 +117,8 @@ namespace xo { static Token singleassign_token() { return Token(tokentype::tk_singleassign); } /** token representing unrestricted assignment @c ":=" **/ static Token assign_token() { return Token(tokentype::tk_assign); } - /** token representing indirection @c "->" **/ - static Token yields() { return Token(tokentype::tk_yields); } + /** token representing indirection @c "->" / function return type **/ + static Token yields_token() { return Token(tokentype::tk_yields); } /** token for @c "+" **/ static Token plus_token() { return Token(tokentype::tk_plus); } From f6b92e18858793826ac100677849ddc3523ee9ff Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 13:23:44 -0500 Subject: [PATCH 159/342] xo-reader2: refactor: crtp to share code across SSM impls --- CMakeLists.txt | 5 ++ include/xo/reader2/DLambdaSsm.hpp | 12 ++- include/xo/reader2/DSyntaxStateMachine.hpp | 94 ++++++++++++++++++++-- src/reader2/DLambdaSsm.cpp | 45 ++++------- 4 files changed, 116 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4fcbe399..ff842708 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.10) +# relying on +# this auto&& +# +set(CMAKE_CXX_STANDARD 23) + project(xo_reader2 VERSION 1.0) enable_language(CXX) diff --git a/include/xo/reader2/DLambdaSsm.hpp b/include/xo/reader2/DLambdaSsm.hpp index 1be39031..7f29e946 100644 --- a/include/xo/reader2/DLambdaSsm.hpp +++ b/include/xo/reader2/DLambdaSsm.hpp @@ -5,7 +5,7 @@ #pragma once -#include "SyntaxStateMachine.hpp" +#include "DSyntaxStateMachine.hpp" #include #include //#include @@ -55,9 +55,9 @@ namespace xo { /** @class DLambdaSsm * @brief parsing state-machine for a lambda-expression **/ - class DLambdaSsm { + class DLambdaSsm : public DSyntaxStateMachine { public: - //using DSymbolTable = xo::scm::DSymbolTable; + using Super = DSyntaxStateMachine; using DLocalSymtab = xo::scm::DLocalSymtab; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; @@ -80,6 +80,8 @@ namespace xo { /** @defgroup scm-lambdassm-methods **/ ///@{ + const char * ssm_classname() const noexcept { return "DLambdaSsm"; } + static void start(ParserStateMachine * p_psm); /** update ssm on lambda keyword token @p tk, @@ -110,11 +112,13 @@ namespace xo { void on_token(const Token & tk, ParserStateMachine * p_psm); +#ifdef OBSOLETE /** update this ssm when nested parser * emits @p td. **/ void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm); +#endif /** update this ssm when nested parser * emits @p td. @@ -122,12 +126,14 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); +#ifdef OBSOLETE /** update this ssm to consume parsed formal (name,value) * from nested (and now expired) ssm **/ void on_parsed_formal(const DUniqueString * sym, TypeDescr td, ParserStateMachine * p_psm); +#endif /** consume formal params @p arglist from completed nested ssm, * with overall parser state in @p p_psm. diff --git a/include/xo/reader2/DSyntaxStateMachine.hpp b/include/xo/reader2/DSyntaxStateMachine.hpp index 4aa35f4d..1f5b2642 100644 --- a/include/xo/reader2/DSyntaxStateMachine.hpp +++ b/include/xo/reader2/DSyntaxStateMachine.hpp @@ -5,16 +5,16 @@ #pragma once +#include "SyntaxStateMachine.hpp" #include namespace xo { namespace scm { /** @class DSyntaxStateMachine - * @brief static interface for implementing ASyntaxStateMachine + * @brief static helper interface for ASyntaxStateMachine implementations * - * Using CRTP to collect methods common to ASyntaxStateMachine - * implementations. + * Using CRTP. * * Deliberately unusable through base class pointer. * For runtime polymorphism use something like: @@ -27,11 +27,91 @@ namespace xo { **/ template class DSyntaxStateMachine { - friend Derived; + public: + using TypeDescr = xo::reflect::TypeDescr; - /** arglist is DArray of obj **/ - void on_parsed_formal_arglist(this auto&& self, DArray * arglist, ParserStateMachine * p_psm) { - p_psm->illegal_parsed_formal_arglist( + /** Default implementation for required SyntaxStateMachine facet method + **/ + void on_token(this auto&& self, + const Token & tk, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_token(self.ssm_classname(), + tk, + self.get_expect_str()); + } + + void on_parsed_symbol(this auto&& self, + std::string_view sym, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_symbol(self.ssm_classname(), + sym, + self.get_expect_str()); + } + + /** Default implementation for required SyntaxStateMachine facet method + **/ + void on_parsed_typedescr(this auto&& self, + TypeDescr td, + ParserStateMachine * p_psm) + { + p_psm->illegal_input_on_typedescr(self.ssm_classname(), + td, + self.get_expect_str()); + } + + /** Default implementation for required SyntaxStateMachine facet method + **/ + void on_parsed_formal(this auto&& self, + const DUniqueString * param_name, + TypeDescr param_type, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal(self.ssm_classname(), + param_name, + param_type, + self.get_expect_str()); + } + + /** Default implementation for required SyntaxStateMachine facet method + * + * arglist is DArray of obj + **/ + void on_parsed_formal_arglist(this auto&& self, + DArray * arglist, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_formal_arglist(self.ssm_classname(), + arglist, + self.get_expect_str()); + } + + /** Default implementation for required SyntaxStateMachine facet method + **/ + void on_parsed_expression(this auto&& self, + obj expr, + ParserStateMachine * p_psm) + { + p_psm->illegal_parsed_expression(self.ssm_classname(), + expr, + self.get_expect_str()); + + } + + /** Default implementation for required SyntaxStateMachine facet method + **/ + void on_parsed_expression_with_semicolon(this auto&& self, + obj expr, + ParserStateMachine * p_psm) + { + // We don't need a separate entry point, + // since the semicolon isn't relevant to problem with syntax + // + + p_psm->illegal_parsed_expression(self.ssm_classname(), + expr, + self.get_expect_str()); } }; diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 3e33c627..4866cd66 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -177,9 +177,12 @@ namespace xo { break; } + Super::on_token(tk, p_psm); +#ifdef OBSOLETE p_psm->illegal_input_on_token("DLambdaSsm::on_token", tk, this->get_expect_str()); +#endif } void @@ -194,9 +197,12 @@ namespace xo { return; } + Super::on_token(tk, p_psm); +#ifdef OBSOLETE p_psm->illegal_input_on_token("DLambdaSsm::on_lambda_token", tk, this->get_expect_str()); +#endif } void @@ -212,9 +218,12 @@ namespace xo { return; } + Super::on_token(tk, p_psm); +#ifdef OBSOLETE p_psm->illegal_input_on_token("DLambdaSsm::on_yields_token", tk, this->get_expect_str()); +#endif } @@ -231,9 +240,7 @@ namespace xo { return; } - p_psm->illegal_input_on_typedescr("DLambdaSsm::on_parsed_typedescr", - td, - this->get_expect_str()); + Super::on_parsed_typedescr(td, p_psm); } #ifdef NOT_YET @@ -264,26 +271,6 @@ namespace xo { } #endif - void - DLambdaSsm::on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_symbol("DLambdaSsm::on_parsed_sybol", - sym, - this->get_expect_str()); - } - - void - DLambdaSsm::on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal("DLambdaSsm::on_parsed_formal", - param_name, - param_type, - this->get_expect_str()); - } - void DLambdaSsm::on_parsed_formal_arglist(DArray * arglist, ParserStateMachine * p_psm) @@ -337,28 +324,26 @@ namespace xo { return; } + Super::on_parsed_formal_arglist(arglist, p_psm); +#ifdef OBSOLETE p_psm->illegal_parsed_formal_arglist("DLambdaSsm::on_parsed_formal_arglist", arglist, this->get_expect_str()); +#endif } void DLambdaSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) { - p_psm->illegal_parsed_expression("DLambdaSsm::on_parsed_expression", - expr, - this->get_expect_str()); + Super::on_parsed_expression(expr, p_psm); } void DLambdaSsm::on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm) { - p_psm->illegal_parsed_expression - ("DLambdaSsm::on_parsed_expression_with_semicolon", - expr, - this->get_expect_str()); + Super::on_parsed_expression_with_semicolon(expr, p_psm); } #ifdef NOT_YET From ff62b4e568040d14c85d28757d51370953925178 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 13:38:43 -0500 Subject: [PATCH 160/342] xo-reader2: streamline DExpectSymbolSsm w/ DSyntaxStateMachine --- include/xo/reader2/DExpectSymbolSsm.hpp | 110 +----------- include/xo/reader2/DSyntaxStateMachine.hpp | 1 + src/reader2/DExpectSymbolSsm.cpp | 189 ++------------------- 3 files changed, 17 insertions(+), 283 deletions(-) diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index accfa936..f06cf94b 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -5,8 +5,7 @@ #pragma once -#include "ParserStateMachine.hpp" -//#include "SyntaxStateMachine.hpp" +#include "DSyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" #include #include @@ -19,8 +18,9 @@ namespace xo { * For example: * - lhs in a define-expression **/ - class DExpectSymbolSsm { + class DExpectSymbolSsm : public DSyntaxStateMachine { public: + using Super = DSyntaxStateMachine; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; using ppindentinfo = xo::print::ppindentinfo; @@ -46,6 +46,8 @@ namespace xo { static void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); + const char * ssm_classname() const noexcept { return "DExpectSymbolSsm"; } + /** @defgroup scm-expectsymbol-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -57,114 +59,12 @@ namespace xo { **/ std::string_view get_expect_str() const noexcept; - /** update state for this syntax after parsing a symbol @p sym; - * overall parser state in @p p_psm. - * - * NOTE: - * might not be obvious that this is unreachable. - * DExpectSymbolSsm converts a symbol token, - * and delivers it to parent ssm using this entry point. - * This method would only be called if consecutive - * DExpectSymbolSsm instances on parser stack; - * which scenario never occurs in Schematika syntax - **/ - void on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm); - - /** update state for this syntax after parsing a type-description @p td - * in nested state machine. - * (provided to satisfy ASyntaxStateMachine api. not reachable) - **/ - void on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm); - - /** update state to consume param (name, value) emitted - * by nested ssm - **/ - void on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm); - - /** consume formal params @p arglist from completed nested ssm, - * with overall parser state in @p p_psm. - **/ - void on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm); - - /** update state for this syntax after parsing an expression @p expr - * in nested state machine. - * (provided to satisfy ASyntaxStateMachine api. not reachable) - **/ - void on_parsed_expression(obj expr, - ParserStateMachine * p_psm); - - /** update state for this syntax after parsing an expression @p expr - * followed by semicolon in nested state machine. - * (provided to satisfy ASyntaxStateMachine api. not reachable) - **/ - void on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm); - /** operate state machine for this syntax on incoming token @p tk * with overall parser state in @p p_psm **/ void on_token(const Token & tk, ParserStateMachine * p_psm); - /** update state for this syntax on incoming token @p tk, - * overall parser state in @p p_psm. - **/ - void on_def_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming token @p tk, - * overall parser state in @p p_psm - **/ - void on_if_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming colon token @p tk, - * overall parser state in @p p_psm - **/ - void on_colon_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming singleassign token @p tk, - * overall parser state in @p p_psm - **/ - void on_singleassign_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming string token @p tk, - * overall parser state in @p p_psm - **/ - void on_string_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming f64 token @p tk, - * overall parser state in @p p_psm - **/ - void on_f64_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming i64 token @p tk, - * overall parser state in @p p_psm - **/ - void on_i64_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming bool token @p tk, - * overall parser state in @p p_psm - **/ - void on_bool_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming semicolon token @p tk, - * overall parser state in @p p_psm - **/ - void on_semicolon_token(const Token & tk, - ParserStateMachine * p_psm); - ///@} /** @defgroup scm-expectsymbol-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DSyntaxStateMachine.hpp b/include/xo/reader2/DSyntaxStateMachine.hpp index 1f5b2642..ee4fca98 100644 --- a/include/xo/reader2/DSyntaxStateMachine.hpp +++ b/include/xo/reader2/DSyntaxStateMachine.hpp @@ -6,6 +6,7 @@ #pragma once #include "SyntaxStateMachine.hpp" +#include "ParserStateMachine.hpp" #include namespace xo { diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 60985cae..b252055b 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -55,62 +55,6 @@ namespace xo { return "symbol"; } - void - DExpectSymbolSsm::on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_symbol("DExpectSymbolSsm::on_parsed_symbol", - sym, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_typedescr("DExpectSymbolSsm::on_parsed_typedescr", - td, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal("DExpectSymbolSsm::on_parsed_formal", - param_name, - param_type, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal_arglist("DExpectSymbolSsm::on_parsed_formal_arglist", - arglist, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_parsed_expression(obj expr, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_expression("DExpectSymbolSsm::on_parsed_expression", - expr, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_expression("DExpectSymbolSsm::on_parsed_expression_with_semicolon", - expr, - this->get_expect_str()); - } - void DExpectSymbolSsm::on_token(const Token & tk, ParserStateMachine * p_psm) @@ -120,46 +64,19 @@ namespace xo { switch (tk.tk_type()) { case tokentype::tk_symbol: this->on_symbol_token(tk, p_psm); - break; - - case tokentype::tk_def: - this->on_def_token(tk, p_psm); - break; - - case tokentype::tk_if: - this->on_if_token(tk, p_psm); - break; - - case tokentype::tk_colon: - this->on_colon_token(tk, p_psm); - break; - - case tokentype::tk_singleassign: - this->on_singleassign_token(tk, p_psm); - break; - - case tokentype::tk_string: - this->on_string_token(tk, p_psm); - break; - - case tokentype::tk_f64: - this->on_f64_token(tk, p_psm); - break; - - case tokentype::tk_i64: - this->on_i64_token(tk, p_psm); - break; - - case tokentype::tk_bool: - this->on_bool_token(tk, p_psm); - break; - - case tokentype::tk_semicolon: - this->on_semicolon_token(tk, p_psm); - break; + return; // all the not-yet handled cases case tokentype::tk_invalid: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_singleassign: + case tokentype::tk_colon: + case tokentype::tk_semicolon: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: @@ -189,12 +106,10 @@ namespace xo { case tokentype::tk_in: case tokentype::tk_end: case tokentype::N: - p_psm->illegal_input_on_token("DExpectSymbolSsm::on_token", - tk, - this->get_expect_str()); break; } + Super::on_token(tk, p_psm); } void @@ -214,91 +129,9 @@ namespace xo { * the o.g. symbol-requester */ p_psm->pop_ssm(); - p_psm->on_parsed_symbol(std::string_view(tk.text())); } - void - DExpectSymbolSsm::on_def_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectSymbolSsm::on_def_token", - tk, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_if_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectSymbolSsm::on_if_token", - tk, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_colon_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectSymbolSsm::on_colon_token", - tk, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_singleassign_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectSymbolSsm::on_singleassign_token", - tk, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_string_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectSymbolSsm::on_string_token", - tk, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_f64_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectSymbolSsm::on_f64_token", - tk, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_i64_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectSymbolSsm::on_i64_token", - tk, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_bool_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectSymbolSsm::on_bool_token", - tk, - this->get_expect_str()); - } - - void - DExpectSymbolSsm::on_semicolon_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectSymbolSsm::on_semicolon_token", - tk, - this->get_expect_str()); - } - bool DExpectSymbolSsm::pretty(const ppindentinfo & ppii) const { From 9f173949ffbbe66bf896bad3a7612077a1648426 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 13:49:57 -0500 Subject: [PATCH 161/342] xo-reader2: streamline DIfElseSsm w/ DSyntaxStateMachine --- include/xo/reader2/DIfElseSsm.hpp | 18 ++--- src/reader2/DIfElseSsm.cpp | 126 ++---------------------------- 2 files changed, 14 insertions(+), 130 deletions(-) diff --git a/include/xo/reader2/DIfElseSsm.hpp b/include/xo/reader2/DIfElseSsm.hpp index 62f7d137..2e3533cd 100644 --- a/include/xo/reader2/DIfElseSsm.hpp +++ b/include/xo/reader2/DIfElseSsm.hpp @@ -5,14 +5,12 @@ #pragma once +#include "DSyntaxStateMachine.hpp" #include -#include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" #include #include #include -//#include "exprstate.hpp" -//#include "xo/indentlog/print/ppdetail_atomic.hpp" namespace xo { namespace scm { @@ -54,8 +52,9 @@ namespace xo { /** @class DIfElseSsm * @brief syntax state machine for parsing a conditional expression **/ - class DIfElseSsm { + class DIfElseSsm : public DSyntaxStateMachine { public: + using Super = DSyntaxStateMachine; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -89,6 +88,9 @@ namespace xo { static void start(DArena & parser_mm, obj expr_mm, ParserStateMachine * p_psm); + + const char * ssm_classname() const noexcept { return "DIfElseSsm"; } + ///@} /** @defgroup scm-ifelsessm-expression-methods general methods **/ ///@{ @@ -140,6 +142,7 @@ namespace xo { void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm); +#ifdef OBSOLETE /** update state for this syntax after parsing a symbol @p sym, * with overall parser state in @p p_psm **/ @@ -158,12 +161,7 @@ namespace xo { void on_parsed_formal(const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); - - /** consume formal params @p arglist from completed nested ssm, - * with overall parser state in @p p_psm. - **/ - void on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm); +#endif /** update state for this syntax after parsing an expression @p expr, * overall parser state in @p p_psm. diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index fb66701a..8551e1fe 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -189,21 +189,9 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DIfElseSsm::on_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } -#ifdef NOT_YET - // ----- if_else_xs ----- - - if_else_xs::if_else_xs(rp if_expr) - : exprstate(exprstatetype::ifexpr), - ifxs_type_{ifexprstatetype::if_0}, - if_expr_{std::move(if_expr)} - {} -#endif - void DIfElseSsm::on_if_token(const Token & tk, ParserStateMachine * p_psm) @@ -219,9 +207,7 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DIfElseSsm::on_if_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -239,34 +225,9 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DIfElseSsm::on_then_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } -#ifdef NOT_YET - void - if_else_xs::on_else_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - log && log("ifxs_type", ifxs_type_); - - if (this->ifxs_type_ == ifexprstatetype::if_4) { - this->ifxs_type_ = ifexprstatetype::if_5; - - expect_expr_xs::start(p_psm); - return; - } - - constexpr const char * c_self_name = "if_else_xs::on_else_token"; - const char * exp = this->get_expect_str(); - - this->illegal_input_on_token(c_self_name, tk, exp, p_psm); - } -#endif - void DIfElseSsm::on_else_token(const Token & tk, ParserStateMachine * p_psm) @@ -282,9 +243,7 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DIfElseSsm::on_else_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } #ifdef NOT_YET @@ -325,37 +284,6 @@ namespace xo { p_psm->on_rightbrace_token(tk); } - void - if_else_xs::on_semicolon_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - log && log("ifxs_type", ifxs_type_); - - const char * c_self_name = "if_else_xs::on_semicolon_token"; - - switch (this->ifxs_type_) { - case ifexprstatetype::invalid: - case ifexprstatetype::if_0: - case ifexprstatetype::n_ifexprstatetype: - // unreachable - assert(false); - break; - - case ifexprstatetype::if_1: - case ifexprstatetype::if_2: - case ifexprstatetype::if_3: - case ifexprstatetype::if_5: - this->illegal_input_on_token(c_self_name, tk, get_expect_str(), p_psm); - break; - case ifexprstatetype::if_4: - case ifexprstatetype::if_6: { - this->finish_and_continue(p_psm); - break; - } - } - } #endif void @@ -385,18 +313,7 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DIfElseSsm::on_semicolon_token", - tk, this->get_expect_str()); - - } - - void - DIfElseSsm::on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal_arglist("DIfElseSsm::on_parsed_formal_arglist", - arglist, - this->get_expect_str()); + Super::on_token(tk, p_psm); } #ifdef NOT_YET @@ -485,9 +402,7 @@ namespace xo { break; } - p_psm->illegal_parsed_expression("DIfElseSsm::on_parsed_expression", - expr, - this->get_expect_str()); + Super::on_parsed_expression(expr, p_psm); } void @@ -500,35 +415,6 @@ namespace xo { this->on_semicolon_token(Token::semicolon_token(), p_psm); } - void - DIfElseSsm::on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_symbol("DIfElseSsm::on_parsed_symbol", - sym, - this->get_expect_str()); - } - - void - DIfElseSsm::on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_typedescr("DIfElseSsm::on_parsed_typedescr", - td, - this->get_expect_str()); - } - - void - DIfElseSsm::on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal("DIfElseSsm::on_parsed_formal", - param_name, - param_type, - this->get_expect_str()); - } - bool DIfElseSsm::pretty(const ppindentinfo & ppii) const { From a3cb9b6d8d247d650f1b0abb74f32dae9aee1708 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 14:11:46 -0500 Subject: [PATCH 162/342] xo-reader2: simplify DDefineSsm w/ DSyntaxStateMachine --- include/xo/reader2/DDefineSsm.hpp | 40 ++-------- src/reader2/DDefineSsm.cpp | 120 ++++-------------------------- 2 files changed, 22 insertions(+), 138 deletions(-) diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index ebd454c0..939d5479 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -5,12 +5,13 @@ #pragma once -#include "ParserStateMachine.hpp" +#include "DSyntaxStateMachine.hpp" //#include "SyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" #include #include #include +#include namespace xo { namespace scm { @@ -69,8 +70,9 @@ namespace xo { /** @class DDefineSsm * @brief state machine for parsing a define expression **/ - class DDefineSsm { + class DDefineSsm : public DSyntaxStateMachine { public: + using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; @@ -102,6 +104,8 @@ namespace xo { /** @defgroup scm-definessm-access-methods **/ ///@{ + const char * ssm_classname() const noexcept { return "DDefineSsm"; } + /** identify this nested state machine **/ defexprstatetype defstate() const noexcept { return defstate_; } @@ -135,12 +139,6 @@ namespace xo { void on_def_token(const Token & tk, ParserStateMachine * p_psm); - /** update state for this syntax on incoming token @p tk, - * overall parser state in @p p_psm - **/ - void on_if_token(const Token & tk, - ParserStateMachine * p_psm); - /** update state for this syntax on incoming colon token @p tk, * overall parser state in @p p_psm **/ @@ -153,30 +151,6 @@ namespace xo { void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); - /** update state for this syntax on incoming string tokne @p tk, - * overall parser state in @p p_psm - **/ - void on_string_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming f64 token @p tk, - * overall parser state in @p p_psm - **/ - void on_f64_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming i64 token @p tk, - * overall parser state in @p p_psm - **/ - void on_i64_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming bool token @p tk, - * overall parser state in @p p_psm - **/ - void on_bool_token(const Token & tk, - ParserStateMachine * p_psm); - /** update state for this syntax on incoming semicolon token @p tk, * overall parser state in @p p_psm **/ @@ -195,6 +169,7 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); +#ifdef OBSOLETE /** update state for this ssm to consume param (name,value) * emitted by nested @p_psm **/ @@ -207,6 +182,7 @@ namespace xo { **/ void on_parsed_formal_arglist(DArray * arglist, ParserStateMachine * p_psm); +#endif /** update state for this syntax after parsing an expression @p expr, * overall parser state in @p p_psm diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 4e2bcf97..4ad36f4f 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -506,10 +506,6 @@ namespace xo { this->on_def_token(tk, p_psm); return; - case tokentype::tk_if: - this->on_if_token(tk, p_psm); - return; - case tokentype::tk_colon: this->on_colon_token(tk, p_psm); return; @@ -518,28 +514,17 @@ namespace xo { this->on_singleassign_token(tk, p_psm); return; - case tokentype::tk_string: - this->on_string_token(tk, p_psm); - return; - - case tokentype::tk_f64: - this->on_f64_token(tk, p_psm); - return; - - case tokentype::tk_i64: - this->on_i64_token(tk, p_psm); - return; - - case tokentype::tk_bool: - this->on_bool_token(tk, p_psm); - return; - case tokentype::tk_semicolon: this->on_semicolon_token(tk, p_psm); return; // all the not-yet handled cases case tokentype::tk_invalid: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_if: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: @@ -569,11 +554,11 @@ namespace xo { case tokentype::tk_in: case tokentype::tk_end: case tokentype::N: - p_psm->illegal_input_on_token("DDefineSsm::on_token", - tk, - this->get_expect_str()); + break; return; } + + Super::on_token(tk, p_psm); } void @@ -585,9 +570,7 @@ namespace xo { // symbol token arriving here means encountered symbol while // in some other, which can't happen for valid Schematika input - p_psm->illegal_input_on_token("DDefineSssm::on_symbol_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -601,18 +584,7 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DDefineSsm::on_define_token", - tk, - this->get_expect_str()); - } - - void - DDefineSsm::on_if_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DDefineSsm::on_if_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -627,9 +599,7 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DDefineSsm::on_colon_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -647,45 +617,7 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DDefineSsm::on_singleassign_token", - tk, - this->get_expect_str()); - } - - void - DDefineSsm::on_string_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DDefineSsm::on_string_token", - tk, - this->get_expect_str()); - } - - void - DDefineSsm::on_f64_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DDefineSsm::on_f64_token", - tk, - this->get_expect_str()); - } - - void - DDefineSsm::on_i64_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DDefineSsm::on_i64_token", - tk, - this->get_expect_str()); - } - - void - DDefineSsm::on_bool_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DDefineSsm::on_bool_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -698,29 +630,7 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DDefineSsm::on_semicolon_token", - tk, - this->get_expect_str()); - } - - void - DDefineSsm::on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal("DDefineSsm::on_parsed_formal", - param_name, - param_type, - this->get_expect_str()); - } - - void - DDefineSsm::on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal_arglist("DDefineSsm::on_parsed_formal_arglist", - arglist, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -735,9 +645,7 @@ namespace xo { return; } - p_psm->illegal_parsed_expression("DDefineSsm::on_parsed_expression", - expr, - this->get_expect_str()); + Super::on_parsed_expression(expr, p_psm); } void From 5b21490c689faada748902e5fb372211cf599375 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 14:21:27 -0500 Subject: [PATCH 163/342] xo-reader2: simplify DExpectExprSsm w/ DSyntaxStateMachine --- include/xo/reader2/DExpectExprSsm.hpp | 57 +----- src/reader2/DExpectExprSsm.cpp | 249 +++++++++----------------- 2 files changed, 87 insertions(+), 219 deletions(-) diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index accdbff3..424afb99 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -5,17 +5,18 @@ #pragma once -#include "ParserStateMachine.hpp" +#include "DSyntaxStateMachine.hpp" +//#include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" -//#include #include #include namespace xo { namespace scm { - class DExpectExprSsm { + class DExpectExprSsm : public DSyntaxStateMachine { public: + using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -37,6 +38,7 @@ namespace xo { /** @defgroup scm-expectexpr-access-methods access methods **/ ///@{ + const char * ssm_classname() const noexcept { return "DExpectExprSsm"; } bool allow_defs() const noexcept { return allow_defs_; } bool cxl_on_rightbrace() const noexcept { return cxl_on_rightbrace_; } @@ -98,55 +100,6 @@ namespace xo { void on_def_token(const Token & tk, ParserStateMachine * p_psm); - /** update state for this syntax on incoming token @p tk, - * overall parser state in @p p_psm - **/ - void on_if_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming colon token @p tk, - * overall parser state in @p p_psm - **/ - void on_colon_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming singleassign token @p tk, - * overall parser state in @p p_psm - **/ - void on_singleassign_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming semicolon token @p tk, - * overall parser state in @p p_psm - **/ - void on_semicolon_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax after parsing a symbol @p sym; - * overall parser state in @p p_psm - **/ - void on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm); - - /** update state for this syntax after parsing a type-description @p td, - * overall parser state in @p p_psm - **/ - void on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm); - - /** update state to consume parsed formal (name, value) from nested ssm, - * with overall parser state in @p p_psm - **/ - void on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm); - - /** consume formal params @p arglist from completed nested ssm, - * with overall parser state in @p p_psm. - **/ - void on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm); - /** update state for this syntax after parsing an expression @p expr, * overall parser state in @p p_psm **/ diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 3f99daca..899731a3 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -116,46 +116,34 @@ namespace xo { switch (tk.tk_type()) { case tokentype::tk_symbol: this->on_symbol_token(tk, p_psm); - break; + return; case tokentype::tk_def: this->on_def_token(tk, p_psm); - break; - - case tokentype::tk_if: - this->on_if_token(tk, p_psm); - break; - - case tokentype::tk_colon: - this->on_colon_token(tk, p_psm); - break; - - case tokentype::tk_singleassign: - this->on_singleassign_token(tk, p_psm); - break; + return; case tokentype::tk_string: this->on_string_token(tk, p_psm); - break; + return; case tokentype::tk_f64: this->on_f64_token(tk, p_psm); - break; + return; case tokentype::tk_i64: this->on_i64_token(tk, p_psm); - break; + return; case tokentype::tk_bool: this->on_bool_token(tk, p_psm); - break; - - case tokentype::tk_semicolon: - this->on_semicolon_token(tk, p_psm); - break; + return; // all the not-yet handled cases case tokentype::tk_invalid: + case tokentype::tk_if: + case tokentype::tk_singleassign: + case tokentype::tk_colon: + case tokentype::tk_semicolon: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: @@ -185,11 +173,10 @@ namespace xo { case tokentype::tk_in: case tokentype::tk_end: case tokentype::N: - p_psm->illegal_input_on_token("DExpectExprSsm::on_token", - tk, - this->get_expect_str()); break; } + + Super::on_token(tk, p_psm); } void @@ -201,40 +188,80 @@ namespace xo { this->get_expect_str()); } +#ifdef NOT_YET + void + expect_expr_xs::on_symbol_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log(xtag("tk", tk)); + + constexpr const char * c_self_name = "expect_expr_xs::on_symbol_token"; + + /* various possibilities when looking for rhs expression: + * + * x := y // (1) + * x := f(a) // (2) + * x := f(a,b) // (3) + * + * need lookahead token following symbol to distinguish + * between (1) (symbol completes rhs expression) + * and {(2), (3)} (symbol is function call) + */ + + bp var = p_psm->lookup_var(tk.text()); + + if (!var) { + this->unknown_variable_error(c_self_name, tk, p_psm); + return; + } + + /* e.g. + * def pi = 3.14159265; + * def mypi = pi; + * ^ + * def pi2 = pi * 2; + * ^ + * def y = foo(pi2); + * ^ + */ + progress_xs::start(var.promote(), p_psm); + + #ifdef NOT_YET + p_stack->push_exprstate(exprstate(exprstatetype::expr_progress, + Variable::make(name, type))); +#endif + +#ifdef LATER + p_psm->pop_exprstate(); + p_psm->top_exprstate().on_symbol(tk.text(), + p_stack, p_emit_expr); +#endif + return; + } +#endif + +#ifdef NOT_YET + void + expect_expr_xs::on_def_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + if (allow_defs_) { + define_xs::start(p_psm); + } else { + exprstate::on_def_token(tk, p_psm); + } + } +#endif + void DExpectExprSsm::on_def_token(const Token & tk, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token("DExpectExprSsm", - tk, - this->get_expect_str()); - } - - void - DExpectExprSsm::on_if_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectExprSsm", - tk, - this->get_expect_str()); - } - - void - DExpectExprSsm::on_colon_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectExprSsm", - tk, - this->get_expect_str()); - } - - void - DExpectExprSsm::on_singleassign_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectExprSsm", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -326,53 +353,6 @@ namespace xo { p_psm); } - void - DExpectExprSsm::on_semicolon_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectExprSsm::on_semicolon_token", - tk, - this->get_expect_str()); - } - - void - DExpectExprSsm::on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_symbol("DExpectExprSsm::on_parsed_symbol", - sym, - this->get_expect_str()); - } - - void - DExpectExprSsm::on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_typedescr("DExpectExprSsm::on_parsed_typedescr", - td, - this->get_expect_str()); - } - - void - DExpectExprSsm::on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal("DExpectExprSsm::on_parsed_formal", - param_name, - param_type, - this->get_expect_str()); - } - - void - DExpectExprSsm::on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal_arglist("DExpectExprSsm::on_parsed_formal_arglist", - arglist, - this->get_expect_str()); - } - void DExpectExprSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) @@ -404,19 +384,6 @@ namespace xo { } #ifdef NOT_YET - void - expect_expr_xs::on_def_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - if (allow_defs_) { - define_xs::start(p_psm); - } else { - exprstate::on_def_token(tk, p_psm); - } - } - void expect_expr_xs::on_lambda_token(const token_type & /*tk*/, parserstatemachine * p_psm) @@ -475,58 +442,6 @@ namespace xo { } } - void - expect_expr_xs::on_symbol_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - log && log(xtag("tk", tk)); - - constexpr const char * c_self_name = "expect_expr_xs::on_symbol_token"; - - /* various possibilities when looking for rhs expression: - * - * x := y // (1) - * x := f(a) // (2) - * x := f(a,b) // (3) - * - * need lookahead token following symbol to distinguish - * between (1) (symbol completes rhs expression) - * and {(2), (3)} (symbol is function call) - */ - - bp var = p_psm->lookup_var(tk.text()); - - if (!var) { - this->unknown_variable_error(c_self_name, tk, p_psm); - return; - } - - /* e.g. - * def pi = 3.14159265; - * def mypi = pi; - * ^ - * def pi2 = pi * 2; - * ^ - * def y = foo(pi2); - * ^ - */ - progress_xs::start(var.promote(), p_psm); - - #ifdef NOT_YET - p_stack->push_exprstate(exprstate(exprstatetype::expr_progress, - Variable::make(name, type))); -#endif - -#ifdef LATER - p_psm->pop_exprstate(); - p_psm->top_exprstate().on_symbol(tk.text(), - p_stack, p_emit_expr); -#endif - return; - } - void expect_expr_xs::on_expr(bp expr, parserstatemachine * p_psm) From 4614843864f4e00ce4a2c099414b8da5a5fcc028 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 14:27:32 -0500 Subject: [PATCH 164/342] xo-reader2: simplify DExpectFormalArgSsm using DSyntaxStateMachine --- include/xo/reader2/DExpectFormalArgSsm.hpp | 47 ++---------------- src/reader2/DExpectFormalArgSsm.cpp | 57 ++-------------------- 2 files changed, 9 insertions(+), 95 deletions(-) diff --git a/include/xo/reader2/DExpectFormalArgSsm.hpp b/include/xo/reader2/DExpectFormalArgSsm.hpp index 51eb6536..5308c701 100644 --- a/include/xo/reader2/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/DExpectFormalArgSsm.hpp @@ -5,7 +5,7 @@ #pragma once -#include "SyntaxStateMachine.hpp" +#include "DSyntaxStateMachine.hpp" //#include //#include "exprstate.hpp" @@ -44,8 +44,9 @@ namespace xo { /** @class expect_formal_xs * @brief parser state-machine for a typed formal parameter **/ - class DExpectFormalArgSsm { + class DExpectFormalArgSsm : public DSyntaxStateMachine { public: + using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -70,6 +71,8 @@ namespace xo { /** @defgroup scm-expectformalargssm-methods general methods **/ ///@{ + const char * ssm_classname() const noexcept { return "DExpectFormalArgSsm"; } + /** update state on incoming colon token @p tk; * with overall parser state in @p p_psm **/ @@ -104,32 +107,6 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); - /** consume parsed formal (name,type) = (@p sym, @p td) from nested ssm - * with overall parser state in @p p_psm. - * (In practice not reachable) - **/ - void on_parsed_formal(const DUniqueString * sym, - TypeDescr td, - ParserStateMachine * p_psm); - - /** consume formal params @p arglist from completed nested ssm, - * with overall parser state in @p p_psm. - **/ - void on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm); - - /** update state on parsed expression emitted by nested ssm - * with overall parser state in @p p_psm - **/ - void on_parsed_expression(obj expr, - ParserStateMachine * p_psm); - - /** update state on parsed expression, along with following semicolon, - * emitted by nested ssm with overall parser state in @p p_psm - **/ - void on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm); - ///@} /** @defgroup scm-expectformalargssm-printable-facet printable facet methods **/ ///@{ @@ -139,26 +116,12 @@ namespace xo { ///@} -#ifdef NOT_YET - - virtual void on_symbol(const std::string & symbol_name, - parserstatemachine * p_psm) override; - - // virtual void on_comma_token(...) override; - #ifdef PROBABLY_NOT virtual void on_rightparen_token(const token_type & tk, exprstatestack * p_stack, rp * p_emit_expr) override; #endif - virtual void on_typedescr(TypeDescr td, - parserstatemachine * p_psm) override; - - private: - static std::unique_ptr make(); -#endif - private: /** parsing state-machine state **/ formalstatetype fstate_ = formalstatetype::formal_0; diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index 4aaf7c4b..d865cd71 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -138,9 +138,7 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DExpectFormalArgSsm::on_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -156,9 +154,7 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DExpectFormalArgSsm::on_colon_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -175,9 +171,7 @@ namespace xo { return; } - p_psm->illegal_input_on_symbol("DExpectFormalArgSsm::on_parsed_symbol", - sym, - this->get_expect_str()); + Super::on_parsed_symbol(sym, p_psm); } void @@ -193,50 +187,7 @@ namespace xo { return; } - p_psm->illegal_input_on_typedescr("DExpectFormalArgSsm::on_parsed_typedescr", - td, - this->get_expect_str()); - } - - void - DExpectFormalArgSsm::on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm) - { - // NOTE: (param_name,param_type) *produced* by this SSM, - // but never *consumed* - - p_psm->illegal_parsed_formal("DExpectFormalArgSsm::on_parsed_formal", - param_name, - param_type, - this->get_expect_str()); - } - - void - DExpectFormalArgSsm::on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal_arglist("DExpectFormalArgSsm::on_parsed_formal_arglist", - arglist, - this->get_expect_str()); - } - - void - DExpectFormalArgSsm::on_parsed_expression(obj expr, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_expression("DExpectFormalArgSsm::on_parsed_expression", - expr, - this->get_expect_str()); - } - - void - DExpectFormalArgSsm::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_expression("DExpectFormalArgSsm::on_parsed_expression_with_semicolon", - expr, - this->get_expect_str()); + Super::on_parsed_typedescr(td, p_psm); } #ifdef NOT_YET From 2fc57b147852a2f5d1ff91737b4e73e40d2d89d5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 14:33:44 -0500 Subject: [PATCH 165/342] xo-reader2: simplify DSyntaxStateMachine w/ DExpectFormalArglistSsm --- .../xo/reader2/DExpectFormalArglistSsm.hpp | 44 ++----------- src/reader2/DExpectFormalArglistSsm.cpp | 66 ++----------------- 2 files changed, 10 insertions(+), 100 deletions(-) diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index 81d7e85d..716dfc28 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -5,7 +5,7 @@ #pragma once -#include "SyntaxStateMachine.hpp" +#include "DSyntaxStateMachine.hpp" #include #include @@ -52,8 +52,9 @@ namespace xo { /** @class expect_formal_arglist * @brief parser state-machine for a formal parameter list **/ - class DExpectFormalArglistSsm { + class DExpectFormalArglistSsm : public DSyntaxStateMachine { public: + using Super = DSyntaxStateMachine; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; using ppindentinfo = xo::print::ppindentinfo; @@ -71,6 +72,8 @@ namespace xo { /** @defgroup scm-expectformalarglistssm-methods general methods **/ ///@{ + const char * ssm_classname() const noexcept { return "DExpectFormalArglistSsm"; } + /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); @@ -99,18 +102,6 @@ namespace xo { void on_token(const Token & tk, ParserStateMachine * p_psm); - /** update state on parsed symbol @p sym emitted by nested ssm, - * with overall parser state in @p p_psm - **/ - void on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm); - - /** update state on parsed typedescr @p td emitted by nested ssm, - * with overall parser state in @p p_psm - **/ - void on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm); - /** update state to consume parsed param (name,type) emitted by * nested ssm, with overall parser state in @p p_psm **/ @@ -118,31 +109,6 @@ namespace xo { TypeDescr param_type, ParserStateMachine * p_psm); - /** consume formal params @p arglist from completed nested ssm, - * with overall parser state in @p p_psm. - **/ - void on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm); - - /** update state on parsed expression emitted by nested ssm - * with overall parser state in @p p_psm - **/ - void on_parsed_expression(obj expr, - ParserStateMachine * p_psm); - - /** update state on parsed expression, along with following semicolon, - * emitted by nested ssm with overall parser state in @p p_psm - **/ - void on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm); - -#ifdef NOT_YET - virtual void on_comma_token(const token_type & tk, - parserstatemachine * p_psm) override; - virtual void on_rightparen_token(const token_type & tk, - parserstatemachine * p_psm) override; -#endif - ///@} /** @defgroup scm-expectformalarglistssm-printable-facet printable facet methods **/ ///@{ diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index bebe4108..b34ad135 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -171,27 +171,7 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DExpectFormalArglistSsm::on_token", - tk, - this->get_expect_str()); - } - - void - DExpectFormalArglistSsm::on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_symbol("DExpectFormalArglistSsm::on_parsed_symbol", - sym, - this->get_expect_str()); - } - - void - DExpectFormalArglistSsm::on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_typedescr("DExpectFormalArglistSsm::on_parsed_typedescr", - td, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -238,37 +218,7 @@ namespace xo { return; } - p_psm->illegal_parsed_formal("DExpectFormalArglistSsm::on_parsed_formal", - param_name, - param_type, - this->get_expect_str()); - } - - void - DExpectFormalArglistSsm::on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal_arglist("DExpectFormalArglistSsm::on_parsed_formal_arglist", - arglist, - this->get_expect_str()); - } - - void - DExpectFormalArglistSsm::on_parsed_expression(obj expr, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_expression("DExpectFormalArglistSsm::on_parsed_expression", - expr, - this->get_expect_str()); - } - - void - DExpectFormalArglistSsm::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_expression("DExpectFormalArglistSsm::on_parsed_expression_with_semicolon", - expr, - this->get_expect_str()); + Super::on_parsed_formal(param_name, param_type, p_psm); } void @@ -282,9 +232,7 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DExpectFormalArglistSsm::on_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -298,9 +246,7 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DExpectFormalArglistSsm::on_comma_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -315,9 +261,7 @@ namespace xo { return; } - p_psm->illegal_input_on_token("DExpectFormalArglistSsm::on_rightparen_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } bool From ed9733937e562b4d18e4c949b04cc6cfd33e6809 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 14:53:49 -0500 Subject: [PATCH 166/342] xo-reader2: simplify DExpectTypeSsm w/ DSyntaxStateMachine --- include/xo/reader2/DExpectTypeSsm.hpp | 106 +-------------- src/reader2/DExpectTypeSsm.cpp | 187 ++------------------------ 2 files changed, 16 insertions(+), 277 deletions(-) diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 729eac83..421e3019 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -5,7 +5,7 @@ #pragma once -#include "SyntaxStateMachine.hpp" +#include "DSyntaxStateMachine.hpp" #include namespace xo { @@ -21,8 +21,9 @@ namespace xo { * * @endpre **/ - class DExpectTypeSsm { + class DExpectTypeSsm : public DSyntaxStateMachine { public: + using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -34,6 +35,8 @@ namespace xo { static void start(ParserStateMachine * p_psm); + const char * ssm_classname() const noexcept { return "DExpectTypeSsm"; } + /** @defgroup scm-expecttype-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -57,105 +60,6 @@ namespace xo { void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); - /** operate state machine for this syntax on incoming define-token @p tk - * with overall parser state in @p p_psm - **/ - void on_def_token(const Token & tk, - ParserStateMachine * p_psm); - - /** operate state machine for this syntax on incoming if-token @p tk - * with overall parser state in @p p_psm - **/ - void on_if_token(const Token & tk, - ParserStateMachine * p_psm); - - /** operate state machine for this syntax on incoming colon-token @p tk - * with overall parser state in @p p_psm - **/ - void on_colon_token(const Token & tk, - ParserStateMachine * p_psm); - - /** operate state machine for this syntax on incoming singleassign-token @p tk - * with overall parser state in @p p_psm - **/ - void on_singleassign_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming string token @p tk, - * overall parser state in @p p_psm - **/ - void on_string_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming f64 token @p tk, - * overall parser state in @p p_psm - **/ - void on_f64_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming i64 token @p tk, - * overall parser state in @p p_psm - **/ - void on_i64_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming bool token @p tk, - * overall parser state in @p p_psm - **/ - void on_bool_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state for this syntax on incoming semicolon token @p tk, - * overall parser state in @p p_psm - **/ - void on_semicolon_token(const Token & tk, - ParserStateMachine * p_psm); - - /** (Never called). - * Operate state machine for this syntax after symbol - * emitted from nested ssm. - * Impossible path for DExpectTypeSsm until such time as it relies - * on nested ssms. Currently using on_symbol_token - * entry point instead. - **/ - void on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm); - - /** operate state machine for this syntax on receiving type-description - * from nested parser. - * Currently (jan 2026) impossible path for DExpectTypeSsm. - * Active path is via on_symbol_token() - **/ - void on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm); - - /** operate state machine to consume formal param (name,value) - * emitted by nested ssm - **/ - void on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm); - - /** consume formal params @p arglist from completed nested ssm, - * with overall parser state in @p p_psm. - **/ - void on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm); - - /** operate state machine for this syntax on receiving expression - * from nested parser. - * (provided to satisfy ASyntaxStateMachine api. not reachable) - **/ - void on_parsed_expression(obj expr, - ParserStateMachine * p_psm); - - /** operate state machine for this syntax on receiving expression - * followed by semicolon from nested parser. - * (provided to satisfy ASyntaxStateMachine api. not reachable) - **/ - void on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm); - ///@} /** @defgroup scm-expecttype-printable-facet printable facet methods **/ ///@{ diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 5e42f758..f7ee3689 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -66,44 +66,14 @@ namespace xo { this->on_symbol_token(tk, p_psm); break; - case tokentype::tk_def: - this->on_def_token(tk, p_psm); - break; - - case tokentype::tk_if: - this->on_if_token(tk, p_psm); - break; - - case tokentype::tk_colon: - this->on_colon_token(tk, p_psm); - break; - - case tokentype::tk_singleassign: - this->on_singleassign_token(tk, p_psm); - break; - - case tokentype::tk_string: - this->on_string_token(tk, p_psm); - break; - - case tokentype::tk_f64: - this->on_f64_token(tk, p_psm); - break; - - case tokentype::tk_i64: - this->on_i64_token(tk, p_psm); - break; - - case tokentype::tk_bool: - this->on_bool_token(tk, p_psm); - break; - - case tokentype::tk_semicolon: - this->on_semicolon_token(tk, p_psm); - break; - // all the not-yet handled cases case tokentype::tk_invalid: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_string: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: @@ -116,8 +86,11 @@ namespace xo { case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: + case tokentype::tk_colon: + case tokentype::tk_semicolon: case tokentype::tk_doublecolon: case tokentype::tk_assign: + case tokentype::tk_singleassign: case tokentype::tk_yields: case tokentype::tk_plus: case tokentype::tk_minus: @@ -140,87 +113,6 @@ namespace xo { } } - void - DExpectTypeSsm::on_def_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectTypeSsm", - tk, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_if_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DxpectTypeSsm", - tk, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_colon_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DxpectTypeSsm", - tk, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_singleassign_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectTypeSsm::on_singleassign_token", - tk, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_string_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectTypeSsm", - tk, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_f64_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectTypeSsm", - tk, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_i64_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectTypeSsm::on_i64_token", - tk, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_bool_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectTypeSsm::on_bool_token", - tk, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_semicolon_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExpectTypeSsm::on_semicolon_token", - tk, - this->get_expect_str()); - } - void DExpectTypeSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) @@ -247,71 +139,14 @@ namespace xo { td = Reflect::require(); if (!td) { - p_psm->illegal_input_on_token("DExpectTypeSsm::on_symbol_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); + return; } p_psm->pop_ssm(); p_psm->on_parsed_typedescr(td); } - void - DExpectTypeSsm::on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_symbol("ExpectTypeSsm::on_parsed_symbol", - sym, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_typedescr("ExpectTypeSsm::on_parsed_typedescr", - td, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal("DExpectTypeSsm::on_parsed_formal", - param_name, - param_type, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal_arglist("DExpectTypeSsm::on_parsed_formal_arglist", - arglist, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_parsed_expression(obj expr, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_expression("DExpectTypeSsm::on_parsed_expression", - expr, - this->get_expect_str()); - } - - void - DExpectTypeSsm::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_expression("DExpectTypeSsm::on_parsed_expression_with_semicolon", - expr, - this->get_expect_str()); - } - bool DExpectTypeSsm::pretty(const ppindentinfo & ppii) const { From 64bc59660bbb4aa2ef94fc5c97fe3df2668a933a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 15:01:31 -0500 Subject: [PATCH 167/342] xo-reader2: simplify DExprSeqState w/ DSyntaxStateMachine --- include/xo/reader2/DExprSeqState.hpp | 48 ++---------- src/reader2/DExprSeqState.cpp | 108 +++------------------------ 2 files changed, 15 insertions(+), 141 deletions(-) diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index a7b19c28..62ae9f5e 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -5,8 +5,7 @@ #pragma once -#include "ParserStateMachine.hpp" -#include "SyntaxStateMachine.hpp" +#include "DSyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" #include @@ -37,8 +36,9 @@ namespace xo { * * Similar to exprseq_xs in xo-expresion **/ - class DExprSeqState { + class DExprSeqState : public DSyntaxStateMachine { public: + using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AAllocator = xo::mm::AAllocator; using ppindentinfo = xo::print::ppindentinfo; @@ -54,6 +54,8 @@ namespace xo { ParserStateMachine * p_psm); public: + const char * ssm_classname() const noexcept { return "DExprSeqState"; } + /** @defgroup scm-exprseq-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -91,16 +93,6 @@ namespace xo { **/ void on_if_token(const Token & tk, ParserStateMachine * p_psm); - /** update state for this syntax on incoming colon token @p tk, - * overall parser state in @p p_psm - **/ - void on_colon_token(const Token & tk, ParserStateMachine * p_psm); - - /** update state for this syntax on incoming single-assign token @p tk, - * overall parser state in @p p_psm - **/ - void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); - /** update state for this syntax on incoming string token @p tk, * overall parser state in @p p_psm **/ @@ -121,36 +113,6 @@ namespace xo { **/ void on_bool_token(const Token & tk, ParserStateMachine * p_psm); - /** update state for this syntax on incoming semicolon token @p tk, - * overall parser state in @p p_psm - **/ - void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm); - - /** update state for this syntax on parsed symbol @p sym - * from immediately-downstream ssm. - * overall parser state in @p p_psm - **/ - void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm); - - /** update state for this syntax on parsed type-description @p td - * from nested ssm. - * overall parser state in @p p_psm - **/ - void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); - - /** update this ssm to consume parsed formal param (name, value) - * emitted by nested ssm, with overall parser state in @p p_psm - **/ - void on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm); - - /** consume formal params @p arglist from completed nested ssm, - * with overall parser state in @p p_psm. - **/ - void on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm); - /** update state for this syntax on parsed expression @p expr * from nested ssm. * overall parser state in @p p_psm diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 12847350..ca6bfa27 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -131,14 +131,6 @@ namespace xo { this->on_if_token(tk, p_psm); return; - case tokentype::tk_colon: - this->on_colon_token(tk, p_psm); - return; - - case tokentype::tk_singleassign: - this->on_singleassign_token(tk, p_psm); - return; - case tokentype::tk_string: this->on_string_token(tk, p_psm); return; @@ -155,10 +147,6 @@ namespace xo { this->on_bool_token(tk, p_psm); return; - case tokentype::tk_semicolon: - this->on_semicolon_token(tk, p_psm); - return; - // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_leftparen: @@ -173,7 +161,10 @@ namespace xo { case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: + case tokentype::tk_colon: + case tokentype::tk_semicolon: case tokentype::tk_doublecolon: + case tokentype::tk_singleassign: case tokentype::tk_assign: case tokentype::tk_yields: case tokentype::tk_plus: @@ -225,9 +216,7 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DExprSeqState::on_symbol_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -264,9 +253,7 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DExprSeqState::on_lambda_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -286,27 +273,7 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DExprSeqState::on_if_token", - tk, - this->get_expect_str()); - } - - void - DExprSeqState::on_colon_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExprSeqState::on_colon_token", - tk, - this->get_expect_str()); - } - - void - DExprSeqState::on_singleassign_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExprSeqState::on_singleassign_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -333,9 +300,7 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DExprSeqState::on_string_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -361,9 +326,7 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DExprSeqState::on_f64_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -389,9 +352,7 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DExprSeqState::on_i64_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -417,56 +378,7 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DExprSeqState::on_bool_token", - tk, - this->get_expect_str()); - } - - void - DExprSeqState::on_semicolon_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DExprSeqState::on_semicolon_token", - tk, - this->get_expect_str()); - } - - void - DExprSeqState::on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_symbol("DExprSeqState::on_parsed_symbol", - sym, - this->get_expect_str()); - } - - void - DExprSeqState::on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_typedescr("DExprSeqState::on_parsed_typedescr", - td, - this->get_expect_str()); - } - - void - DExprSeqState::on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal("DExprSeqState::on_parsed_formal", - param_name, - param_type, - this->get_expect_str()); - } - - void - DExprSeqState::on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal_arglist("DExprSeqState::on_parsed_formal_arglist", - arglist, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void From e7bdcbc12501c667787302db46cf5a1f5f21b2a7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 15:17:28 -0500 Subject: [PATCH 168/342] xo-reader2: simplify DProgressSsm w/ DSyntaxStateMachine --- include/xo/reader2/DProgressSsm.hpp | 35 ++---- src/reader2/DProgressSsm.cpp | 185 +++------------------------- 2 files changed, 27 insertions(+), 193 deletions(-) diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index ae9c2244..542707f4 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -5,7 +5,7 @@ #pragma once -#include "ParserStateMachine.hpp" +#include "DSyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" //#include #include @@ -86,8 +86,9 @@ namespace xo { * To look at but not consume a token T, can push a progress_xs instance P, * then send T to P. **/ - class DProgressSsm { + class DProgressSsm : public DSyntaxStateMachine { public: + using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -119,6 +120,8 @@ namespace xo { parserstatemachine * p_psm) const; #endif + const char * ssm_classname() const noexcept { return "DProgressSsm"; } + std::string_view get_expect_str() const noexcept; /** assemble expression from collected inputs. @@ -129,12 +132,11 @@ namespace xo { /** @defgroup scm-progressssm-methods general methods **/ ///@{ - void on_if_token(const Token & tk, - ParserStateMachine * p_psm); - void on_then_token(const Token & tk, - ParserStateMachine * p_psm); - void on_else_token(const Token & tk, - ParserStateMachine * p_psm); + /** token belongs to surrounding syntax, + * -> lock in current progress + **/ + void on_completing_token(const Token & tk, + ParserStateMachine * p_psm); ///@} /** @defgroup scm-progressssm-ssm-facet syntaxstatemachine facet methods **/ @@ -148,8 +150,6 @@ namespace xo { void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); - void on_def_token(const Token & tk, - ParserStateMachine * p_psm); void on_colon_token(const Token & tk, ParserStateMachine * p_psm); void on_singleassign_token(const Token & tk, @@ -166,17 +166,6 @@ namespace xo { ParserStateMachine * p_psm); void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm); - void on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm); - void on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm); - void on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm); - void on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm); - void on_parsed_expression(obj, - ParserStateMachine * p_psm); void on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm); @@ -204,10 +193,6 @@ namespace xo { parserstatemachine * p_psm) override; void on_rightbrace_token(const token_type & tk, parserstatemachine * p_psm) override; - void on_then_token(const token_type & tk, - parserstatemachine * p_psm) override; - void on_else_token(const token_type & tk, - parserstatemachine * p_psm) override; /* entry point for an infix operator token */ void on_operator_token(const token_type & tk, diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 5a6317a3..3c617fae 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -218,26 +218,15 @@ namespace xo { scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); switch (tk.tk_type()) { + case tokentype::tk_then: + case tokentype::tk_else: + this->on_completing_token(tk, p_psm); + return; + case tokentype::tk_symbol: this->on_symbol_token(tk, p_psm); return; - case tokentype::tk_def: - this->on_def_token(tk, p_psm); - return; - - case tokentype::tk_if: - this->on_if_token(tk, p_psm); - return; - - case tokentype::tk_then: - this->on_then_token(tk, p_psm); - return; - - case tokentype::tk_else: - this->on_else_token(tk, p_psm); - return; - case tokentype::tk_colon: this->on_colon_token(tk, p_psm); return; @@ -268,6 +257,8 @@ namespace xo { // all the not-yet handled cases case tokentype::tk_invalid: + case tokentype::tk_def: + case tokentype::tk_if: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: @@ -304,61 +295,20 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DProgressSsm::on_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void DProgressSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token("DProgressSsm::on_symbol_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void - DProgressSsm::on_def_token(const Token & tk, - ParserStateMachine * p_psm) + DProgressSsm::on_completing_token(const Token & tk, + ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token("DProgressSsm::on_def_token", - tk, - this->get_expect_str()); - } - - void - DProgressSsm::on_if_token(const Token & tk, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_token("DProgressSsm::on_if_token", - tk, - this->get_expect_str()); - } - - void - DProgressSsm::on_then_token(const Token & tk, - ParserStateMachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - (void)tk; - - obj expr = this->assemble_expr(p_psm); - - p_psm->pop_ssm(); // completes self - - // TODO: perhaps need to generalize on_parsed_expression_with_semicolon() ..? - p_psm->on_parsed_expression(expr); - p_psm->on_token(tk); - } - - void - DProgressSsm::on_else_token(const Token & tk, - ParserStateMachine * p_psm) - { - // note: common with .on_then_token() - scope log(XO_DEBUG(p_psm->debug_flag())); (void)tk; @@ -461,36 +411,28 @@ namespace xo { DProgressSsm::on_string_token(const Token & tk, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token("DProgressSsm::on_string_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void DProgressSsm::on_f64_token(const Token & tk, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token("DProgressSsm::on_f64_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void DProgressSsm::on_i64_token(const Token & tk, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token("DProgressSsm::on_i64_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void DProgressSsm::on_bool_token(const Token & tk, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token("DProgressSsm::on_bool_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } void @@ -529,59 +471,10 @@ namespace xo { */ #ifdef OBSOLETE - p_psm->illegal_input_on_token("DProgressSsm::on_semicolon_token", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); #endif } - void - DProgressSsm::on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_symbol("DProgressSsm::on_parsed_symbol", - sym, - this->get_expect_str()); - } - - void - DProgressSsm::on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm) - { - p_psm->illegal_input_on_typedescr("DProgressSsm::on_parsed_typedescr", - td, - this->get_expect_str()); - } - - void - DProgressSsm::on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal("DProgressSsm::on_parsed_formal", - param_name, - param_type, - this->get_expect_str()); - } - - void - DProgressSsm::on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_formal_arglist("DProgressSsm::on_parsed_formal_arglist", - arglist, - this->get_expect_str()); - } - - void - DProgressSsm::on_parsed_expression(obj expr, - ParserStateMachine * p_psm) - { - p_psm->illegal_parsed_expression("DProgressSsm::on_parsed_expression", - expr, - this->get_expect_str()); - } - void DProgressSsm::on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm) @@ -905,14 +798,6 @@ namespace xo { p_psm->top_exprstate().on_comma_token(tk, p_psm); } - void - progress_xs::on_typedescr(TypeDescr /*td*/, - parserstatemachine * /*p_psm*/) - { - /* unreachable */ - assert(false); - } - void progress_xs::on_semicolon_token(const token_type & /*tk*/, parserstatemachine * p_psm) @@ -1116,44 +1001,8 @@ namespace xo { exprstate::on_i64_token(tk, p_psm); } } - - void - progress_xs::print(std::ostream & os) const { - os << ""; - } - - bool - progress_xs::pretty_print(const xo::print::ppindentinfo & ppii) const - { - if (ppii.upto()) { - return (ppii.pps()->print_upto("print_upto(refrtag("lhs", lhs_)) : true) - && (op_type_ != optype::invalid ? ppii.pps()->print_upto(refrtag("op", op_type_)) : true) - && (rhs_ ? ppii.pps()->print_upto(refrtag("rhs", rhs_)) : true) - && ppii.pps()->print_upto(">")); - } else { - ppii.pps()->write("pretty(refrtag("lhs", lhs_)); - if (op_type_ != optype::invalid) - ppii.pps()->pretty(refrtag("op", op_type_)); - if (rhs_) - ppii.pps()->pretty(refrtag("rhs", rhs_)); - ppii.pps()->write(">"); - return false; - } - } - #endif + bool DProgressSsm::pretty(const xo::print::ppindentinfo & ppii) const { From bcd95502d2b13690f40eb5a46389f5bd02389cf9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 30 Jan 2026 20:08:41 -0500 Subject: [PATCH 169/342] xo-expression2 xo-reader2 DSequenceExpr, DSequenceSsm [WIP] --- include/xo/reader2/DDefineSsm.hpp | 15 --- include/xo/reader2/DSequenceSsm.hpp | 57 ++++++++++++ src/reader2/DExpectExprSsm.cpp | 4 +- src/reader2/DSequenceSsm.cpp | 137 ++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 18 deletions(-) create mode 100644 include/xo/reader2/DSequenceSsm.hpp create mode 100644 src/reader2/DSequenceSsm.cpp diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 939d5479..34918dc9 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -169,21 +169,6 @@ namespace xo { void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm); -#ifdef OBSOLETE - /** update state for this ssm to consume param (name,value) - * emitted by nested @p_psm - **/ - void on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm); - - /** consume formal params @p arglist from completed nested ssm, - * with overall parser state in @p p_psm. - **/ - void on_parsed_formal_arglist(DArray * arglist, - ParserStateMachine * p_psm); -#endif - /** update state for this syntax after parsing an expression @p expr, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DSequenceSsm.hpp b/include/xo/reader2/DSequenceSsm.hpp new file mode 100644 index 00000000..8d936254 --- /dev/null +++ b/include/xo/reader2/DSequenceSsm.hpp @@ -0,0 +1,57 @@ +/** @file DSequenceSsm.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +//#include "exprstate.hpp" + +namespace xo { + namespace scm { class Sequence; } + namespace scm { class Lambda; } + + namespace scm { + class DSequenceSsm : public DSyntaxStateMachine { + public: + using Sequence = xo::scm::Sequence; + using Lambda = xo::scm::Lambda; + + public: + const char * ssm_classname() const noexcept { return "DSequenceSsm"; } + +#ifdef NOT_YET + /** start parsing a sequence-expr. + * input begins with first expression in the sequence. + **/ + static void start(parserstatemachine * p_psm); + + /** named ctor idiom **/ + static std::unique_ptr make(); + + virtual void on_expr(bp expr, + parserstatemachine * p_psm) override; + virtual void on_expr_with_semicolon(bp expr, + parserstatemachine * p_psm) override; + + virtual void on_rightbrace_token(const token_type & tk, + parserstatemachine * p_psm) override; + + virtual void print(std::ostream & os) const override; + virtual bool pretty_print(const xo::print::ppindentinfo & ppii) const override; +#endif + + private: + DSequenceSsm(); + + private: + /** will build SequenceExpr from in-order contents of this array **/ + DArray * expr_v_; + //std::vector> expr_v_; + }; + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end DSequenceSsm.hpp */ diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 899731a3..3b4b2c36 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -183,9 +183,7 @@ namespace xo { DExpectExprSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token("DExpectExprSsm", - tk, - this->get_expect_str()); + Super::on_token(tk, p_psm); } #ifdef NOT_YET diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp new file mode 100644 index 00000000..285960bd --- /dev/null +++ b/src/reader2/DSequenceSsm.cpp @@ -0,0 +1,137 @@ +/* @file DSequenceSsm.cpp */ + +#include "DSequenceSsm.hpp" + +#ifdef NOT_YET +#include "expect_expr_xs.hpp" +#include "let1_xs.hpp" +#include "xo/expression/DefineExpr.hpp" +#include "xo/expression/Sequence.hpp" +#include "xo/expression/pretty_expression.hpp" +#endif + +namespace xo { + using xo::scm::DefineExpr; + + namespace scm { +#ifdef NOT_YET + std::unique_ptr + sequence_xs::make() { + return std::make_unique(sequence_xs()); + } +#endif + + void + sequence_xs::start(parserstatemachine * p_psm) { + p_psm->push_exprstate(sequence_xs::make()); + /* want to accept anything that starts an expression, + * except that } ends it + */ + expect_expr_xs::start(true /*allow_defs*/, + true /*cxl_on_rightbrace*/, + p_psm); + } + + sequence_xs::sequence_xs() + : exprstate(exprstatetype::sequenceexpr) + {} + + void + sequence_xs::on_expr(bp expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log(xtag("expr", expr.promote())); + + /* TODO: if expr is a DefineExpr, + * then need to rewrite... + * + * ...prefix + * DefineExpr(lhs_name, rhs) + * rest... + * + * becomes: + * + * /-- .outer_seq_expr_ + * v + * Sequence( + * ...prefix, + * + * /-- .inner_lm_expr_ + * v + * Apply(Lambda(gen999, + * [Variable(lhs_name, type(rhs))], + * /-- .expr_v_ + * v + * sequencify(rest...)), + * rhs)) + * + * so amongst other things, + * helpful to have nested seequence_xs that propagates '}' + * instead of swallowing it. + */ + bp def_expr = DefineExpr::from(expr); + + if (def_expr) { + /** nested_start: control returns via + * .on_expr(x) + * with x something like: + * Apply(Lambda(gensym(), + * [Variable(def_expr->lhs_name(), + * def_expr->valuetype())], + * body...)) + * followed immediately by + * .on_rightbrace_token() + **/ + let1_xs::start(def_expr->lhs_name(), + def_expr->rhs(), + p_psm); + } else { + this->expr_v_.push_back(expr.promote()); + + expect_expr_xs::start(true /*allow_defs*/, + true /*cxl_on_rightbrace*/, + p_psm); + } + } + + void + sequence_xs::on_expr_with_semicolon(bp expr, + parserstatemachine * p_psm) + { + /* sequence continues until right brace */ + this->on_expr(expr, p_psm); + } + + void + sequence_xs::on_rightbrace_token(const token_type & /*tk*/, + parserstatemachine * p_psm) + { + auto self = p_psm->pop_exprstate(); + + /* make sequence from expressions seen at this level, + * and report it to parent + */ + auto expr = Sequence::make(this->expr_v_); + + p_psm->top_exprstate().on_expr(expr, p_psm); + } + + void + sequence_xs::print(std::ostream & os) const { + os << ""; + } + + bool + sequence_xs::pretty_print(const xo::print::ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, "sequence_xs", + xrefrtag("expr_v.size", expr_v_.size())); + } + + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end DSequenceSsm.cpp */ From 334057613e4e3d9a90a601800c76d45e1f4a6015 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 31 Jan 2026 01:14:33 -0500 Subject: [PATCH 170/342] xo-reader2: revert c++23 feature, to keep osx clang build --- CMakeLists.txt | 5 +- include/xo/reader2/DDefineSsm.hpp | 2 +- include/xo/reader2/DExpectExprSsm.hpp | 2 +- include/xo/reader2/DExpectFormalArgSsm.hpp | 2 +- .../xo/reader2/DExpectFormalArglistSsm.hpp | 2 +- include/xo/reader2/DExpectSymbolSsm.hpp | 2 +- include/xo/reader2/DExpectTypeSsm.hpp | 2 +- include/xo/reader2/DExprSeqState.hpp | 2 +- include/xo/reader2/DIfElseSsm.hpp | 27 ++------- include/xo/reader2/DLambdaSsm.hpp | 2 +- include/xo/reader2/DProgressSsm.hpp | 2 +- include/xo/reader2/DSyntaxStateMachine.hpp | 56 ++++++++++++------- include/xo/reader2/ParserStateMachine.hpp | 2 + src/reader2/DIfElseSsm.cpp | 12 ++-- 14 files changed, 57 insertions(+), 63 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff842708..79d692ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,10 +2,7 @@ cmake_minimum_required(VERSION 3.10) -# relying on -# this auto&& -# -set(CMAKE_CXX_STANDARD 23) +#set(CMAKE_CXX_STANDARD 23) project(xo_reader2 VERSION 1.0) enable_language(CXX) diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 34918dc9..0e3b1404 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -104,7 +104,7 @@ namespace xo { /** @defgroup scm-definessm-access-methods **/ ///@{ - const char * ssm_classname() const noexcept { return "DDefineSsm"; } + static const char * ssm_classname() { return "DDefineSsm"; } /** identify this nested state machine **/ defexprstatetype defstate() const noexcept { return defstate_; } diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 424afb99..4b407881 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -38,7 +38,7 @@ namespace xo { /** @defgroup scm-expectexpr-access-methods access methods **/ ///@{ - const char * ssm_classname() const noexcept { return "DExpectExprSsm"; } + static const char * ssm_classname() { return "DExpectExprSsm"; } bool allow_defs() const noexcept { return allow_defs_; } bool cxl_on_rightbrace() const noexcept { return cxl_on_rightbrace_; } diff --git a/include/xo/reader2/DExpectFormalArgSsm.hpp b/include/xo/reader2/DExpectFormalArgSsm.hpp index 5308c701..62f5ae34 100644 --- a/include/xo/reader2/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/DExpectFormalArgSsm.hpp @@ -71,7 +71,7 @@ namespace xo { /** @defgroup scm-expectformalargssm-methods general methods **/ ///@{ - const char * ssm_classname() const noexcept { return "DExpectFormalArgSsm"; } + static const char * ssm_classname() { return "DExpectFormalArgSsm"; } /** update state on incoming colon token @p tk; * with overall parser state in @p p_psm diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index 716dfc28..203c7293 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -72,7 +72,7 @@ namespace xo { /** @defgroup scm-expectformalarglistssm-methods general methods **/ ///@{ - const char * ssm_classname() const noexcept { return "DExpectFormalArglistSsm"; } + static const char * ssm_classname() { return "DExpectFormalArglistSsm"; } /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ void on_leftparen_token(const Token & tk, diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index f06cf94b..d1cf3a3c 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -46,7 +46,7 @@ namespace xo { static void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); - const char * ssm_classname() const noexcept { return "DExpectSymbolSsm"; } + static const char * ssm_classname() { return "DExpectSymbolSsm"; } /** @defgroup scm-expectsymbol-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 421e3019..6719bfb8 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -35,7 +35,7 @@ namespace xo { static void start(ParserStateMachine * p_psm); - const char * ssm_classname() const noexcept { return "DExpectTypeSsm"; } + static const char * ssm_classname() { return "DExpectTypeSsm"; } /** @defgroup scm-expecttype-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 62ae9f5e..56578161 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -54,7 +54,7 @@ namespace xo { ParserStateMachine * p_psm); public: - const char * ssm_classname() const noexcept { return "DExprSeqState"; } + static const char * ssm_classname() { return "DExprSeqState"; } /** @defgroup scm-exprseq-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/include/xo/reader2/DIfElseSsm.hpp b/include/xo/reader2/DIfElseSsm.hpp index 2e3533cd..43f6d4b5 100644 --- a/include/xo/reader2/DIfElseSsm.hpp +++ b/include/xo/reader2/DIfElseSsm.hpp @@ -52,7 +52,7 @@ namespace xo { /** @class DIfElseSsm * @brief syntax state machine for parsing a conditional expression **/ - class DIfElseSsm : public DSyntaxStateMachine { + class DIfElseSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; using AAllocator = xo::mm::AAllocator; @@ -89,7 +89,9 @@ namespace xo { obj expr_mm, ParserStateMachine * p_psm); - const char * ssm_classname() const noexcept { return "DIfElseSsm"; } + static const char * ssm_classname() { return "DIfElseSsm"; } + + DSyntaxStateMachine * super() { return this; } ///@} /** @defgroup scm-ifelsessm-expression-methods general methods **/ @@ -142,27 +144,6 @@ namespace xo { void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm); -#ifdef OBSOLETE - /** update state for this syntax after parsing a symbol @p sym, - * with overall parser state in @p p_psm - **/ - void on_parsed_symbol(std::string_view sym, - ParserStateMachine * p_psm); - - /** update state for this syntax after parsing a type description @p td; - * overall parser state in @p p_psm - **/ - void on_parsed_typedescr(TypeDescr td, - ParserStateMachine * p_psm); - - /** update state to consume formal param (name,value) - * from nested ssm - **/ - void on_parsed_formal(const DUniqueString * param_name, - TypeDescr param_type, - ParserStateMachine * p_psm); -#endif - /** update state for this syntax after parsing an expression @p expr, * overall parser state in @p p_psm. **/ diff --git a/include/xo/reader2/DLambdaSsm.hpp b/include/xo/reader2/DLambdaSsm.hpp index 7f29e946..d4147c76 100644 --- a/include/xo/reader2/DLambdaSsm.hpp +++ b/include/xo/reader2/DLambdaSsm.hpp @@ -80,7 +80,7 @@ namespace xo { /** @defgroup scm-lambdassm-methods **/ ///@{ - const char * ssm_classname() const noexcept { return "DLambdaSsm"; } + static const char * ssm_classname() { return "DLambdaSsm"; } static void start(ParserStateMachine * p_psm); diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 542707f4..85126bed 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -120,7 +120,7 @@ namespace xo { parserstatemachine * p_psm) const; #endif - const char * ssm_classname() const noexcept { return "DProgressSsm"; } + static const char * ssm_classname() { return "DProgressSsm"; } std::string_view get_expect_str() const noexcept; diff --git a/include/xo/reader2/DSyntaxStateMachine.hpp b/include/xo/reader2/DSyntaxStateMachine.hpp index ee4fca98..f5a835ae 100644 --- a/include/xo/reader2/DSyntaxStateMachine.hpp +++ b/include/xo/reader2/DSyntaxStateMachine.hpp @@ -33,43 +33,51 @@ namespace xo { /** Default implementation for required SyntaxStateMachine facet method **/ - void on_token(this auto&& self, - const Token & tk, + void on_token(const Token & tk, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_token(self.ssm_classname(), + // starting with c++23 can use "this auto&& self" instead + Derived & self = reinterpret_cast(*this); + + p_psm->illegal_input_on_token(Derived::ssm_classname(), tk, self.get_expect_str()); } - void on_parsed_symbol(this auto&& self, - std::string_view sym, + void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_symbol(self.ssm_classname(), + // starting with c++23 can use "this auto&& self" instead + Derived & self = reinterpret_cast(*this); + + p_psm->illegal_input_on_symbol(Derived::ssm_classname(), sym, self.get_expect_str()); } /** Default implementation for required SyntaxStateMachine facet method **/ - void on_parsed_typedescr(this auto&& self, - TypeDescr td, + void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm) { - p_psm->illegal_input_on_typedescr(self.ssm_classname(), + // starting with c++23 can use "this auto&& self" instead + Derived & self = reinterpret_cast(*this); + + p_psm->illegal_input_on_typedescr(Derived::ssm_classname(), td, self.get_expect_str()); } /** Default implementation for required SyntaxStateMachine facet method **/ - void on_parsed_formal(this auto&& self, - const DUniqueString * param_name, + void on_parsed_formal(const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) { - p_psm->illegal_parsed_formal(self.ssm_classname(), + // starting with c++23 can use "this auto&& self" instead + Derived & self = reinterpret_cast(*this); + + p_psm->illegal_parsed_formal(Derived::ssm_classname(), param_name, param_type, self.get_expect_str()); @@ -79,22 +87,26 @@ namespace xo { * * arglist is DArray of obj **/ - void on_parsed_formal_arglist(this auto&& self, - DArray * arglist, + void on_parsed_formal_arglist(DArray * arglist, ParserStateMachine * p_psm) { - p_psm->illegal_parsed_formal_arglist(self.ssm_classname(), + // starting with c++23 can use "this auto&& self" instead + Derived & self = static_cast(*this); + + p_psm->illegal_parsed_formal_arglist(Derived::ssm_classname(), arglist, self.get_expect_str()); } /** Default implementation for required SyntaxStateMachine facet method **/ - void on_parsed_expression(this auto&& self, - obj expr, + void on_parsed_expression(obj expr, ParserStateMachine * p_psm) { - p_psm->illegal_parsed_expression(self.ssm_classname(), + // starting with c++23 can use "this auto&& self" instead + Derived & self = static_cast(*this); + + p_psm->illegal_parsed_expression(Derived::ssm_classname(), expr, self.get_expect_str()); @@ -102,15 +114,17 @@ namespace xo { /** Default implementation for required SyntaxStateMachine facet method **/ - void on_parsed_expression_with_semicolon(this auto&& self, - obj expr, + void on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm) { + // starting with c++23 can use "this auto&& self" instead + Derived & self = static_cast(*this); + // We don't need a separate entry point, // since the semicolon isn't relevant to problem with syntax // - p_psm->illegal_parsed_expression(self.ssm_classname(), + p_psm->illegal_parsed_expression(Derived::ssm_classname(), expr, self.get_expect_str()); diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index fbf636e3..a57247c7 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -261,10 +261,12 @@ namespace xo { **/ DLocalSymtab * local_symtab_ = nullptr; +#ifdef NOT_YET /** global symbol table. * Toplevel definitions go here. **/ DGlobalSymtab * global_symtab_ = nullptr; +#endif /** current output from parser **/ ParserResult result_; diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index 8551e1fe..7efb4a7e 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -189,7 +189,7 @@ namespace xo { break; } - Super::on_token(tk, p_psm); + DSyntaxStateMachine::on_token(tk, p_psm); } void @@ -207,7 +207,7 @@ namespace xo { return; } - Super::on_token(tk, p_psm); + DSyntaxStateMachine::on_token(tk, p_psm); } void @@ -225,7 +225,7 @@ namespace xo { return; } - Super::on_token(tk, p_psm); + DSyntaxStateMachine::on_token(tk, p_psm); } void @@ -243,7 +243,7 @@ namespace xo { return; } - Super::on_token(tk, p_psm); + DSyntaxStateMachine::on_token(tk, p_psm); } #ifdef NOT_YET @@ -313,7 +313,7 @@ namespace xo { return; } - Super::on_token(tk, p_psm); + DSyntaxStateMachine::on_token(tk, p_psm); } #ifdef NOT_YET @@ -402,7 +402,7 @@ namespace xo { break; } - Super::on_parsed_expression(expr, p_psm); + DSyntaxStateMachine::on_parsed_expression(expr, p_psm); } void From 15f779d2f8564d488edbefb34f97919662d4e9e6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 31 Jan 2026 18:28:25 -0500 Subject: [PATCH 171/342] xo-reader2 xo-expression2: + DSequenceSsm ++ utest --- CMakeLists.txt | 28 ++++++- idl/IPrintable_DSequenceSsm.json5 | 13 ++++ idl/ISyntaxStateMachine_DSequenceSsm.json5 | 13 ++++ include/xo/reader2/DExpectExprSsm.hpp | 6 ++ include/xo/reader2/DIfElseSsm.hpp | 21 +---- include/xo/reader2/DSequenceSsm.hpp | 56 ++++++++++---- include/xo/reader2/SyntaxStateMachine.hpp | 4 +- .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 4 +- .../xo/reader2/ssm/IPrintable_DDefineSsm.hpp | 2 +- .../reader2/ssm/IPrintable_DExpectExprSsm.hpp | 2 +- .../ssm/IPrintable_DExpectFormalArgSsm.hpp | 2 +- .../IPrintable_DExpectFormalArglistSsm.hpp | 2 +- .../ssm/IPrintable_DExpectSymbolSsm.hpp | 2 +- .../reader2/ssm/IPrintable_DExpectTypeSsm.hpp | 2 +- .../reader2/ssm/IPrintable_DExprSeqState.hpp | 2 +- .../xo/reader2/ssm/IPrintable_DIfElseSsm.hpp | 2 +- .../xo/reader2/ssm/IPrintable_DLambdaSsm.hpp | 2 +- .../reader2/ssm/IPrintable_DProgressSsm.hpp | 2 +- .../reader2/ssm/IPrintable_DSequenceSsm.hpp | 62 +++++++++++++++ .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 4 +- .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 +- .../ISyntaxStateMachine_DExpectExprSsm.hpp | 2 +- ...SyntaxStateMachine_DExpectFormalArgSsm.hpp | 2 +- ...axStateMachine_DExpectFormalArglistSsm.hpp | 2 +- .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 +- .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 +- .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 2 +- .../ssm/ISyntaxStateMachine_DIfElseSsm.hpp | 2 +- .../ssm/ISyntaxStateMachine_DLambdaSsm.hpp | 2 +- .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 2 +- .../ssm/ISyntaxStateMachine_DSequenceSsm.hpp | 77 +++++++++++++++++++ .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 4 +- .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 4 +- include/xo/reader2/syntaxstatetype.hpp | 27 ++++--- src/reader2/CMakeLists.txt | 4 + src/reader2/DExpectExprSsm.cpp | 28 ++++--- src/reader2/DLambdaSsm.cpp | 2 +- src/reader2/DSequenceSsm.cpp | 72 +++++++++++++---- src/reader2/IPrintable_DDefineSsm.cpp | 4 +- src/reader2/IPrintable_DExpectExprSsm.cpp | 4 +- .../IPrintable_DExpectFormalArgSsm.cpp | 4 +- .../IPrintable_DExpectFormalArglistSsm.cpp | 4 +- src/reader2/IPrintable_DExpectSymbolSsm.cpp | 4 +- src/reader2/IPrintable_DExpectTypeSsm.cpp | 4 +- src/reader2/IPrintable_DExprSeqState.cpp | 4 +- src/reader2/IPrintable_DIfElseSsm.cpp | 4 +- src/reader2/IPrintable_DLambdaSsm.cpp | 4 +- src/reader2/IPrintable_DProgressSsm.cpp | 4 +- src/reader2/IPrintable_DSequenceSsm.cpp | 28 +++++++ src/reader2/ISyntaxStateMachine_Any.cpp | 2 +- .../ISyntaxStateMachine_DDefineSsm.cpp | 4 +- .../ISyntaxStateMachine_DExpectExprSsm.cpp | 4 +- ...SyntaxStateMachine_DExpectFormalArgSsm.cpp | 4 +- ...axStateMachine_DExpectFormalArglistSsm.cpp | 4 +- .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 4 +- .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 4 +- .../ISyntaxStateMachine_DExprSeqState.cpp | 4 +- .../ISyntaxStateMachine_DIfElseSsm.cpp | 4 +- .../ISyntaxStateMachine_DLambdaSsm.cpp | 4 +- .../ISyntaxStateMachine_DProgressSsm.cpp | 4 +- .../ISyntaxStateMachine_DSequenceSsm.cpp | 69 +++++++++++++++++ src/reader2/reader2_register_facets.cpp | 4 + src/reader2/syntaxstatetype.cpp | 18 +++-- utest/SchematikaParser.test.cpp | 2 +- 64 files changed, 516 insertions(+), 156 deletions(-) create mode 100644 idl/IPrintable_DSequenceSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DSequenceSsm.json5 create mode 100644 include/xo/reader2/ssm/IPrintable_DSequenceSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp create mode 100644 src/reader2/IPrintable_DSequenceSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 79d692ba..c936619f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,7 +183,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-ifelsessm FACET_PKG xo_printable2 FACET Printable - REPR Ifelsessm + REPR IfElseSsm INPUT idl/IPrintable_DIfElseSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm @@ -192,6 +192,32 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-sequencessm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR SequenceSsm + INPUT idl/ISyntaxStateMachine_DSequenceSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-sequencessm + FACET_PKG xo_printable2 + FACET Printable + REPR SequenceSsm + INPUT idl/IPrintable_DSequenceSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectsymbolssm diff --git a/idl/IPrintable_DSequenceSsm.json5 b/idl/IPrintable_DSequenceSsm.json5 new file mode 100644 index 00000000..a217b24c --- /dev/null +++ b/idl/IPrintable_DSequenceSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DSequenceSsm", + using_doxygen: true, + repr: "DSequenceSsm", + doc: [ "implement APrintable for DSequenceSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DSequenceSsm.json5 b/idl/ISyntaxStateMachine_DSequenceSsm.json5 new file mode 100644 index 00000000..7538c09b --- /dev/null +++ b/idl/ISyntaxStateMachine_DSequenceSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DSequenceSsm", + using_doxygen: true, + repr: "DSequenceSsm", + doc: [ "implement ASyntaxStateMachine for DSequenceSsm" ], +} diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 4b407881..6b2fe30f 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -46,6 +46,12 @@ namespace xo { /** @defgroup scm-expectexpr-methods general methods **/ ///@{ + /** update state for this syntax on incoming leftbrace token @p tk, + * with overall parser state in @p p_psm + **/ + void on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm); + /** step state machine for this syntax on incoming boolean literal token @p tkk * with overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DIfElseSsm.hpp b/include/xo/reader2/DIfElseSsm.hpp index 43f6d4b5..5e6d4d8c 100644 --- a/include/xo/reader2/DIfElseSsm.hpp +++ b/include/xo/reader2/DIfElseSsm.hpp @@ -166,27 +166,8 @@ namespace xo { ///@} #ifdef NOT_YET - // ----- inherited from exprstate ----- - - virtual const char * get_expect_str() const override; - - virtual void on_if_token(const token_type & tk, - parserstatemachine * p_psm) override; - virtual void on_then_token(const token_type & tk, - parserstatemachine * p_psm) override; - virtual void on_else_token(const token_type & tk, - parserstatemachine * p_psm) override; - virtual void on_semicolon_token(const token_type & tk, - parserstatemachine * p_psm) override; virtual void on_rightbrace_token(const token_type & tk, parserstatemachine * p_psm) override; - - virtual void on_expr(bp expr, - parserstatemachine * p_psm) override; - virtual void on_expr_with_semicolon(bp expr, - parserstatemachine * p_psm) override; - - virtual void print(std::ostream & os) const override; #endif private: @@ -203,6 +184,8 @@ namespace xo { ifexprstatetype ifstate_ = ifexprstatetype::invalid; /** scaffold ifelse-expression here. * This will eventually be the output of this ssm + * + * TODO: can use DIfElseExpr* here. See xo-object2//DList **/ obj if_expr_; diff --git a/include/xo/reader2/DSequenceSsm.hpp b/include/xo/reader2/DSequenceSsm.hpp index 8d936254..6423ee29 100644 --- a/include/xo/reader2/DSequenceSsm.hpp +++ b/include/xo/reader2/DSequenceSsm.hpp @@ -6,7 +6,7 @@ #pragma once #include "DSyntaxStateMachine.hpp" -//#include "exprstate.hpp" +#include namespace xo { namespace scm { class Sequence; } @@ -15,21 +15,29 @@ namespace xo { namespace scm { class DSequenceSsm : public DSyntaxStateMachine { public: - using Sequence = xo::scm::Sequence; - using Lambda = xo::scm::Lambda; + //using Sequence = xo::scm::Sequence; + //using Lambda = xo::scm::Lambda; + using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; public: - const char * ssm_classname() const noexcept { return "DSequenceSsm"; } + static const char * ssm_classname() { return "DSequenceSsm"; } -#ifdef NOT_YET /** start parsing a sequence-expr. * input begins with first expression in the sequence. **/ - static void start(parserstatemachine * p_psm); + static void start(ParserStateMachine * p_psm); - /** named ctor idiom **/ - static std::unique_ptr make(); + /** create instance using memory from @p parser_mm **/ + static obj make(DArena & parser_mm, + obj expr_mm); + /** create instance using memory from @p parser_mm **/ + static DSequenceSsm * _make(DArena & parser_mm, + obj expr_mm); + +#ifdef NOT_YET virtual void on_expr(bp expr, parserstatemachine * p_psm) override; virtual void on_expr_with_semicolon(bp expr, @@ -37,18 +45,34 @@ namespace xo { virtual void on_rightbrace_token(const token_type & tk, parserstatemachine * p_psm) override; - - virtual void print(std::ostream & os) const override; - virtual bool pretty_print(const xo::print::ppindentinfo & ppii) const override; #endif - private: - DSequenceSsm(); + /** @defgroup scm-sequencessm-syntaxstatemachine-facet ssm facet **/ + ///@{ + + /** indentifies this state machine **/ + syntaxstatetype ssm_type() const noexcept; + + /** mnemonic for syntax sequence ssm expects given current state **/ + std::string_view get_expect_str() const noexcept; + + ///@} + /** @defgroup scm-sequencessm-printable-facet printable facet **/ + ///@{ + + /** pretty printing support **/ + bool pretty(const ppindentinfo & ppii) const; + + ///@} private: - /** will build SequenceExpr from in-order contents of this array **/ - DArray * expr_v_; - //std::vector> expr_v_; + explicit DSequenceSsm(DSequenceExpr * seq_expr); + + private: + /** scaffold sequence-expression here. + * This will eventually be the output of this ssm + **/ + DSequenceExpr * seq_expr_ = nullptr; }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/SyntaxStateMachine.hpp b/include/xo/reader2/SyntaxStateMachine.hpp index deda9e1d..c9c37ee1 100644 --- a/include/xo/reader2/SyntaxStateMachine.hpp +++ b/include/xo/reader2/SyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for facet .hpp file: @@ -19,4 +19,4 @@ #include "ssm/RSyntaxStateMachine.hpp" -/* end SyntaxStateMachine.hpp */ \ No newline at end of file +/* end SyntaxStateMachine.hpp */ diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index b9df6e6d..b6475877 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -90,4 +90,4 @@ using ISyntaxStateMachine_ImplType = xo::facet::FacetImplType +#include +#include "DSequenceSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DSequenceSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DSequenceSsm + **/ + class IPrintable_DSequenceSsm { + public: + /** @defgroup scm-printable-dsequencessm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dsequencessm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DSequenceSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index e239c46b..9cf16408 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -91,4 +91,4 @@ namespace scm { } /*namespace scm */ } /*namespace xo */ -/* ISyntaxStateMachine_Any.hpp */ \ No newline at end of file +/* ISyntaxStateMachine_Any.hpp */ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index 42616a38..c34a66a5 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DDefineSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 53669967..7280b78e 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExpectExprSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp index 99d6c9a9..acf84462 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp index 570ee3a4..4cf9e3ff 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 2003db8a..1a33685f 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExpectSymbolSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index acb752fe..054c03f1 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExpectTypeSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index 3c160d00..cd241d52 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExprSeqState.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp index 462172d2..65f585af 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DIfElseSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp index fa0cb0a2..6d931744 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DLambdaSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index ddd0c06e..27ec4f53 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DProgressSsm.json5] * 2. jinja2 template for abstract facet .hpp file: diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp new file mode 100644 index 00000000..da541414 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp @@ -0,0 +1,77 @@ +/** @file ISyntaxStateMachine_DSequenceSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DSequenceSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DSequenceSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DSequenceSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DSequenceSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DSequenceSsm + **/ + class ISyntaxStateMachine_DSequenceSsm { + public: + /** @defgroup scm-syntaxstatemachine-dsequencessm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dsequencessm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DSequenceSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DSequenceSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DSequenceSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DSequenceSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DSequenceSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DSequenceSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DSequenceSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DSequenceSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr followed by semicolon **/ + static void on_parsed_expression_with_semicolon(DSequenceSsm & self, obj expr, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index e89357ab..5fffca24 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -105,4 +105,4 @@ namespace scm { } /*namespace scm */ } /*namespace xo*/ -/* end ISyntaxStateMachine_Xfer.hpp */ \ No newline at end of file +/* end ISyntaxStateMachine_Xfer.hpp */ diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 0e2b8636..b84082d2 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -101,4 +101,4 @@ namespace xo { namespace facet { }; } } -/* end RSyntaxStateMachine.hpp */ \ No newline at end of file +/* end RSyntaxStateMachine.hpp */ diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 2d87aa25..a5b4b563 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -18,6 +18,21 @@ namespace xo { enum class syntaxstatetype { invalid = -1, + /** handle define-expression. See @ref DDefineSsm **/ + defexpr, + + /** handle lambda-expression. See @ref DLambdaSsm **/ + lambdaexpr, + + /** handle ifelse-expression. See @ref DIfElseSsm **/ + ifelseexpr, + + /** handle sequence-expression. See @ref DSequenceSsm **/ + sequence, + + /** rhs expression. state exists to achieve 1-token lookahead **/ + progress, + /** toplevel of some translation unit. See @ref DExprSeqState **/ expect_toplevel_expression_sequence, @@ -36,18 +51,6 @@ namespace xo { /** expecting a rhs expression. See @ref DExpectExprSsm **/ expect_rhs_expression, - /** handle define-expression. See @ref DDefineSsm **/ - defexpr, - - /** handle lambda-expression. See @ref DLambdaSsm **/ - lambdaexpr, - - /** handle ifelse-expression. See @ref DIfElseSsm **/ - ifelseexpr, - - /** rhs expression. state exists to achieve 1-token lookahead **/ - progress, - /** comes lasts, counts number of valid enums **/ N }; diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index aebe5d77..d883fa82 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -29,6 +29,10 @@ set(SELF_SRCS ISyntaxStateMachine_DIfElseSsm.cpp IPrintable_DIfElseSsm.cpp + DSequenceSsm.cpp + ISyntaxStateMachine_DSequenceSsm.cpp + IPrintable_DSequenceSsm.cpp + DLambdaSsm.cpp ISyntaxStateMachine_DLambdaSsm.cpp IPrintable_DLambdaSsm.cpp diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 3b4b2c36..cddfb865 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -8,6 +8,7 @@ #include "SyntaxStateMachine.hpp" #include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" #include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" +#include "DSequenceSsm.hpp" #include "syntaxstatetype.hpp" #include #include @@ -114,6 +115,10 @@ namespace xo { scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); switch (tk.tk_type()) { + case tokentype::tk_leftbrace: + this->on_leftbrace_token(tk, p_psm); + return; + case tokentype::tk_symbol: this->on_symbol_token(tk, p_psm); return; @@ -148,7 +153,6 @@ namespace xo { case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: - case tokentype::tk_leftbrace: case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: @@ -179,6 +183,15 @@ namespace xo { Super::on_token(tk, p_psm); } + void + DExpectExprSsm::on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + DSequenceSsm::start(p_psm); + } + void DExpectExprSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) @@ -377,7 +390,8 @@ namespace xo { (ppii, "DExpectExprSsm", refrtag("allow_defs", allow_defs_), - refrtag("cxl_on_rightbrace", cxl_on_rightbrace_) + refrtag("cxl_on_rightbrace", cxl_on_rightbrace_), + refrtag("expect", this->get_expect_str()) ); } @@ -412,16 +426,6 @@ namespace xo { paren_xs::start(p_psm); } - void - expect_expr_xs::on_leftbrace_token(const token_type & /*tk*/, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - /* push lparen_0 to remember to look for subsequent rightparen. */ - sequence_xs::start(p_psm); - } - void expect_expr_xs::on_rightbrace_token(const token_type & tk, parserstatemachine * p_psm) diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 4866cd66..99351533 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -1,4 +1,4 @@ -/** @file lambda_xs.cpp +/** @file DLambdaSsm.cpp * * @author Roland Conybeare, Jan 2026 **/ diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index 285960bd..6a6b8c76 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -1,6 +1,8 @@ /* @file DSequenceSsm.cpp */ #include "DSequenceSsm.hpp" +#include "ssm/ISyntaxStateMachine_DSequenceSsm.hpp" +#include "DExpectExprSsm.hpp" #ifdef NOT_YET #include "expect_expr_xs.hpp" @@ -11,31 +13,67 @@ #endif namespace xo { - using xo::scm::DefineExpr; +#ifdef NOT_YET + using xo::scm::DDefineExpr; +#endif + using xo::facet::typeseq; namespace scm { -#ifdef NOT_YET - std::unique_ptr - sequence_xs::make() { - return std::make_unique(sequence_xs()); - } -#endif - void - sequence_xs::start(parserstatemachine * p_psm) { - p_psm->push_exprstate(sequence_xs::make()); + DSequenceSsm::start(ParserStateMachine * p_psm) + { + p_psm->push_ssm(DSequenceSsm::make(p_psm->parser_alloc(), + p_psm->expr_alloc())); /* want to accept anything that starts an expression, - * except that } ends it + * except that rightbrace '}' ends it */ - expect_expr_xs::start(true /*allow_defs*/, + DExpectExprSsm::start(p_psm->parser_alloc(), + true /*allow_defs*/, true /*cxl_on_rightbrace*/, p_psm); } + obj + DSequenceSsm::make(DArena & mm, + obj expr_mm) + { + return obj(_make(mm, expr_mm)); + } + + DSequenceSsm * + DSequenceSsm::_make(DArena & mm, + obj expr_mm) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DSequenceSsm)); + + DSequenceExpr * seq_expr = DSequenceExpr::_make_empty(expr_mm); + + return new (mem) DSequenceSsm(seq_expr); + } + + DSequenceSsm::DSequenceSsm(DSequenceExpr * seq_expr) : seq_expr_{seq_expr} + {} + +#ifdef NOT_YET sequence_xs::sequence_xs() : exprstate(exprstatetype::sequenceexpr) {} +#endif + syntaxstatetype + DSequenceSsm::ssm_type() const noexcept + { + return syntaxstatetype::sequence; + } + + std::string_view + DSequenceSsm::get_expect_str() const noexcept + { + return "expr|semicolon|rightbrace"; + } + +#ifdef NOT_YET void sequence_xs::on_expr(bp expr, parserstatemachine * p_psm) @@ -122,12 +160,16 @@ namespace xo { sequence_xs::print(std::ostream & os) const { os << ""; } +#endif bool - sequence_xs::pretty_print(const xo::print::ppindentinfo & ppii) const + DSequenceSsm::pretty(const xo::print::ppindentinfo & ppii) const { - return ppii.pps()->pretty_struct(ppii, "sequence_xs", - xrefrtag("expr_v.size", expr_v_.size())); + return ppii.pps()->pretty_struct + (ppii, + "SequenceSsm", + xrefrtag("seq_expr.size", seq_expr_->size()), + xrefrtag("expect", this->get_expect_str())); } } /*namespace scm*/ diff --git a/src/reader2/IPrintable_DDefineSsm.cpp b/src/reader2/IPrintable_DDefineSsm.cpp index bb3c2096..dbd0bfc9 100644 --- a/src/reader2/IPrintable_DDefineSsm.cpp +++ b/src/reader2/IPrintable_DDefineSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DDefineSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -25,4 +25,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end IPrintable_DDefineSsm.cpp */ \ No newline at end of file +/* end IPrintable_DDefineSsm.cpp */ diff --git a/src/reader2/IPrintable_DExpectExprSsm.cpp b/src/reader2/IPrintable_DExpectExprSsm.cpp index bfeaccd1..7febe575 100644 --- a/src/reader2/IPrintable_DExpectExprSsm.cpp +++ b/src/reader2/IPrintable_DExpectExprSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExpectExprSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -25,4 +25,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end IPrintable_DExpectExprSsm.cpp */ \ No newline at end of file +/* end IPrintable_DExpectExprSsm.cpp */ diff --git a/src/reader2/IPrintable_DExpectFormalArgSsm.cpp b/src/reader2/IPrintable_DExpectFormalArgSsm.cpp index a38d4d86..13164b15 100644 --- a/src/reader2/IPrintable_DExpectFormalArgSsm.cpp +++ b/src/reader2/IPrintable_DExpectFormalArgSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExpectFormalArgSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -25,4 +25,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end IPrintable_DExpectFormalArgSsm.cpp */ \ No newline at end of file +/* end IPrintable_DExpectFormalArgSsm.cpp */ diff --git a/src/reader2/IPrintable_DExpectFormalArglistSsm.cpp b/src/reader2/IPrintable_DExpectFormalArglistSsm.cpp index d5df450d..262cb91e 100644 --- a/src/reader2/IPrintable_DExpectFormalArglistSsm.cpp +++ b/src/reader2/IPrintable_DExpectFormalArglistSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExpectFormalArglistSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -25,4 +25,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end IPrintable_DExpectFormalArglistSsm.cpp */ \ No newline at end of file +/* end IPrintable_DExpectFormalArglistSsm.cpp */ diff --git a/src/reader2/IPrintable_DExpectSymbolSsm.cpp b/src/reader2/IPrintable_DExpectSymbolSsm.cpp index e58d15f9..f03af120 100644 --- a/src/reader2/IPrintable_DExpectSymbolSsm.cpp +++ b/src/reader2/IPrintable_DExpectSymbolSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExpectSymbolSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -25,4 +25,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end IPrintable_DExpectSymbolSsm.cpp */ \ No newline at end of file +/* end IPrintable_DExpectSymbolSsm.cpp */ diff --git a/src/reader2/IPrintable_DExpectTypeSsm.cpp b/src/reader2/IPrintable_DExpectTypeSsm.cpp index 3fc75136..14c20d53 100644 --- a/src/reader2/IPrintable_DExpectTypeSsm.cpp +++ b/src/reader2/IPrintable_DExpectTypeSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExpectTypeSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -25,4 +25,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end IPrintable_DExpectTypeSsm.cpp */ \ No newline at end of file +/* end IPrintable_DExpectTypeSsm.cpp */ diff --git a/src/reader2/IPrintable_DExprSeqState.cpp b/src/reader2/IPrintable_DExprSeqState.cpp index 71997ede..36cfbd78 100644 --- a/src/reader2/IPrintable_DExprSeqState.cpp +++ b/src/reader2/IPrintable_DExprSeqState.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DExprSeqState.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -25,4 +25,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end IPrintable_DExprSeqState.cpp */ \ No newline at end of file +/* end IPrintable_DExprSeqState.cpp */ diff --git a/src/reader2/IPrintable_DIfElseSsm.cpp b/src/reader2/IPrintable_DIfElseSsm.cpp index f2aebf7c..d0ef4bb3 100644 --- a/src/reader2/IPrintable_DIfElseSsm.cpp +++ b/src/reader2/IPrintable_DIfElseSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DIfElseSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -25,4 +25,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end IPrintable_DIfElseSsm.cpp */ \ No newline at end of file +/* end IPrintable_DIfElseSsm.cpp */ diff --git a/src/reader2/IPrintable_DLambdaSsm.cpp b/src/reader2/IPrintable_DLambdaSsm.cpp index 93a703aa..4e7a09d8 100644 --- a/src/reader2/IPrintable_DLambdaSsm.cpp +++ b/src/reader2/IPrintable_DLambdaSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DLambdaSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -25,4 +25,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end IPrintable_DLambdaSsm.cpp */ \ No newline at end of file +/* end IPrintable_DLambdaSsm.cpp */ diff --git a/src/reader2/IPrintable_DProgressSsm.cpp b/src/reader2/IPrintable_DProgressSsm.cpp index c72399c9..bd9dd7e8 100644 --- a/src/reader2/IPrintable_DProgressSsm.cpp +++ b/src/reader2/IPrintable_DProgressSsm.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [xo-facet/codegen/genfacet] * arguments: * --input [idl/IPrintable_DProgressSsm.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -25,4 +25,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end IPrintable_DProgressSsm.cpp */ \ No newline at end of file +/* end IPrintable_DProgressSsm.cpp */ diff --git a/src/reader2/IPrintable_DSequenceSsm.cpp b/src/reader2/IPrintable_DSequenceSsm.cpp new file mode 100644 index 00000000..8c525ba8 --- /dev/null +++ b/src/reader2/IPrintable_DSequenceSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DSequenceSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DSequenceSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DSequenceSsm.json5] +**/ + +#include "ssm/IPrintable_DSequenceSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DSequenceSsm::pretty(const DSequenceSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DSequenceSsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 18510abb..2cd6f304 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -80,4 +80,4 @@ ISyntaxStateMachine_Any::on_parsed_expression_with_semicolon(Opaque, obj syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DSequenceSsm::get_expect_str(const DSequenceSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DSequenceSsm::on_token(DSequenceSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DSequenceSsm::on_parsed_symbol(DSequenceSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DSequenceSsm::on_parsed_typedescr(DSequenceSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DSequenceSsm::on_parsed_formal(DSequenceSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DSequenceSsm::on_parsed_formal_arglist(DSequenceSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DSequenceSsm::on_parsed_expression(DSequenceSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DSequenceSsm::on_parsed_expression_with_semicolon(DSequenceSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_semicolon(expr, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DSequenceSsm.cpp */ diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 9dc10aa2..ef584c44 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include #include @@ -63,6 +65,8 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index e003b27d..aff0a87c 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -13,6 +13,16 @@ namespace xo { switch (x) { case syntaxstatetype::invalid: break; + case syntaxstatetype::defexpr: + return "defexpr"; + case syntaxstatetype::lambdaexpr: + return "lambdaexpr"; + case syntaxstatetype::ifelseexpr: + return "ifelseexpr"; + case syntaxstatetype::sequence: + return "sequence"; + case syntaxstatetype::progress: + return "progress"; case syntaxstatetype::expect_toplevel_expression_sequence: return "expect-toplevel-expression-sequence"; case syntaxstatetype::expect_formal_arglist: @@ -25,14 +35,6 @@ namespace xo { return "expect-type"; case syntaxstatetype::expect_rhs_expression: return "expect-rhs-expression"; - case syntaxstatetype::defexpr: - return "defexpr"; - case syntaxstatetype::lambdaexpr: - return "lambdaexpr"; - case syntaxstatetype::ifelseexpr: - return "ifelseexpr"; - case syntaxstatetype::progress: - return "progress"; case syntaxstatetype::N: break; } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 0d7dbba4..ef487af3 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -363,7 +363,6 @@ namespace xo { REQUIRE(result.is_incomplete()); } -#ifdef NOT_YET { auto & result = parser.on_token(Token::leftbrace_token()); @@ -376,6 +375,7 @@ namespace xo { REQUIRE(result.is_incomplete()); } +#ifdef NOT_YET { auto & result = parser.on_token(Token::string_token("fooey")); From 726f821c4eb4afa141b87d76dca5f0370512c103 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 31 Jan 2026 21:33:39 -0500 Subject: [PATCH 172/342] xo-reader2: DLambdaSsm work towards producing DLambdaExpr [WIP] --- include/xo/reader2/DProgressSsm.hpp | 17 +-- include/xo/reader2/DSequenceSsm.hpp | 32 +++++- include/xo/reader2/ParserStateMachine.hpp | 12 +++ src/reader2/DLambdaSsm.cpp | 17 +++ src/reader2/DProgressSsm.cpp | 35 ++++++- src/reader2/DSequenceSsm.cpp | 122 ++++++++++++++++------ src/reader2/ParserStateMachine.cpp | 35 ++++++- utest/SchematikaParser.test.cpp | 16 ++- 8 files changed, 218 insertions(+), 68 deletions(-) diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 85126bed..792d6eb2 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -166,6 +166,8 @@ namespace xo { ParserStateMachine * p_psm); void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm); + void on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm); void on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm); @@ -183,27 +185,12 @@ namespace xo { void on_typedescr(TypeDescr td, parserstatemachine * p_psm) override; - void on_semicolon_token(const token_type & tk, - parserstatemachine * p_psm) override; void on_assign_token(const token_type & tk, parserstatemachine * p_psm) final override; void on_leftparen_token(const token_type & tk, parserstatemachine * p_psm) override; void on_rightparen_token(const token_type & tk, parserstatemachine * p_psm) override; - void on_rightbrace_token(const token_type & tk, - parserstatemachine * p_psm) override; - - /* entry point for an infix operator token */ - void on_operator_token(const token_type & tk, - parserstatemachine * p_psm) final override; - - void on_bool_token(const token_type & tk, - parserstatemachine * p_psm) override; - - void on_i64_token(const token_type & tk, - parserstatemachine * p_psm) override; - void print(std::ostream & os) const override; #endif diff --git a/include/xo/reader2/DSequenceSsm.hpp b/include/xo/reader2/DSequenceSsm.hpp index 6423ee29..e2943ae8 100644 --- a/include/xo/reader2/DSequenceSsm.hpp +++ b/include/xo/reader2/DSequenceSsm.hpp @@ -7,12 +7,25 @@ #include "DSyntaxStateMachine.hpp" #include +#include "syntaxstatetype.hpp" +#include +#include +#include namespace xo { namespace scm { class Sequence; } namespace scm { class Lambda; } namespace scm { + // TODO: need switching between 1a,1b states. + // Allow + // { } + // { 1 } + // { 1; } + // Reject + // { 1 2 } + // + class DSequenceSsm : public DSyntaxStateMachine { public: //using Sequence = xo::scm::Sequence; @@ -38,15 +51,14 @@ namespace xo { obj expr_mm); #ifdef NOT_YET - virtual void on_expr(bp expr, - parserstatemachine * p_psm) override; virtual void on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) override; - - virtual void on_rightbrace_token(const token_type & tk, - parserstatemachine * p_psm) override; #endif + /** update ssm for incoming rightbrace token '}' **/ + void on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm); + /** @defgroup scm-sequencessm-syntaxstatemachine-facet ssm facet **/ ///@{ @@ -56,6 +68,16 @@ namespace xo { /** mnemonic for syntax sequence ssm expects given current state **/ std::string_view get_expect_str() const noexcept; + /** operate state machine for this syntax on incoming token @p tk + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** consume expression @p expr produced by nested ssm; overall parser state in @p p_psm **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-sequencessm-printable-facet printable facet **/ ///@{ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index a57247c7..91c84ef1 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -142,6 +142,18 @@ namespace xo { **/ void on_parsed_expression_with_semicolon(obj expr); + /** update state to respond to parsed expression @p expr + * (from nested parsing state), with trailing token @p tk. + * + * Need to distinguish cases like: + * 6 // ) ? ; allowed } ? + * f(6 // ) allowed ; forbidden } forbidden + * 6 + // ) forbidden ; forbidden } forbidden + * + **/ + void on_parsed_expression_with_token(obj expr, + const Token & tk); + /** update state to respond to input token @p tk. * record output (if any) in @ref result_ **/ diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 99351533..4b2d7df8 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -336,6 +336,23 @@ namespace xo { DLambdaSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) { + if (lm_state_ == lambdastatetype::lm_4) { + this->lmstate_ = lambdastatetype::lm_5; + this->body_ = expr; + + // assemble lambda + + obj lm_expr = DLambda::make(p_psm->expr_alloc(), + xxx typeref, + xxx name, + local_symtab_, + body_); + + p_psm->pop_ssm(); // this lambda + p_psm->on_parsed_expression(lm_expr); + return; + } + Super::on_parsed_expression(expr, p_psm); } diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 3c617fae..9fd6e7b1 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -205,7 +205,7 @@ namespace xo { std::string_view DProgressSsm::get_expect_str() const noexcept { if (op_type_ == optype::invalid) { - return "oper|semicolon|rightparen"; + return "oper|semicolon|rightparen|righbrace"; } else { return "expr|leftparen"; } @@ -255,6 +255,10 @@ namespace xo { this->on_semicolon_token(tk, p_psm); return; + case tokentype::tk_rightbrace: + this->on_rightbrace_token(tk, p_psm); + return; + // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_def: @@ -264,7 +268,6 @@ namespace xo { case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: - case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_lessequal: @@ -448,7 +451,8 @@ namespace xo { obj expr = this->assemble_expr(p_psm); { - obj expr_pr = FacetRegistry::instance().variant(expr); + obj expr_pr + = FacetRegistry::instance().variant(expr); assert(expr_pr); log && log(xtag("expr", expr_pr)); } @@ -475,6 +479,27 @@ namespace xo { #endif } + void + DProgressSsm::on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + (void)tk; + + obj expr = this->assemble_expr(p_psm); + + { + obj expr_pr + = FacetRegistry::instance().variant(expr); + assert(expr_pr); + log && log(xtag("expr", expr_pr)); + } + + p_psm->pop_ssm(); + p_psm->on_parsed_expression_with_token(expr, tk); + } + void DProgressSsm::on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm) @@ -1024,7 +1049,8 @@ namespace xo { "DProgressSsm", refrtag("lhs", lhs), refrtag("op", op_type_), - cond(rhs, refrtag("rhs", rhs), "nullptr") + cond(rhs, refrtag("rhs", rhs), "nullptr"), + refrtag("expect", this->get_expect_str()) ); } @@ -1048,6 +1074,7 @@ namespace xo { std::string_view(errmsg_string)); p_psm->capture_error(c_self_name, errmsg); + return obj(); } /* consecutive expressions not legal, e.g: diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index 6a6b8c76..56efb896 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -55,12 +55,6 @@ namespace xo { DSequenceSsm::DSequenceSsm(DSequenceExpr * seq_expr) : seq_expr_{seq_expr} {} -#ifdef NOT_YET - sequence_xs::sequence_xs() - : exprstate(exprstatetype::sequenceexpr) - {} -#endif - syntaxstatetype DSequenceSsm::ssm_type() const noexcept { @@ -73,15 +67,93 @@ namespace xo { return "expr|semicolon|rightbrace"; } -#ifdef NOT_YET void - sequence_xs::on_expr(bp expr, - parserstatemachine * p_psm) + DSequenceSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); + + switch (tk.tk_type()) { + case tokentype::tk_rightbrace: + this->on_rightbrace_token(tk, p_psm); + return; + case tokentype::tk_symbol: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + // default = illegal token error + DSyntaxStateMachine::on_token(tk, p_psm); + } + + void + DSequenceSsm::on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + /** rightbrace ends DSequenceSsm **/ + + obj expr(seq_expr_); + + p_psm->pop_ssm(); + + /* make sequence from expressions seen at this level, + * and report it to parent + */ + p_psm->top_ssm().on_parsed_expression(expr, p_psm); + } + + void + DSequenceSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) { scope log(XO_DEBUG(p_psm->debug_flag())); - log && log(xtag("expr", expr.promote())); + // TODO: stream inserter that sets up pretty-printing. + // Or integrate with indentlog. + // Maybe trouble is that indentlog doesn't #include Printable ? + // + log && log(xtag("expr", expr)); +#ifdef NOT_YET /* TODO: if expr is a DefineExpr, * then need to rewrite... * @@ -132,8 +204,13 @@ namespace xo { true /*cxl_on_rightbrace*/, p_psm); } +#endif + + this->seq_expr_->push_back(p_psm->expr_alloc(), + expr); } +#ifdef NOT_YET void sequence_xs::on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) @@ -141,25 +218,6 @@ namespace xo { /* sequence continues until right brace */ this->on_expr(expr, p_psm); } - - void - sequence_xs::on_rightbrace_token(const token_type & /*tk*/, - parserstatemachine * p_psm) - { - auto self = p_psm->pop_exprstate(); - - /* make sequence from expressions seen at this level, - * and report it to parent - */ - auto expr = Sequence::make(this->expr_v_); - - p_psm->top_exprstate().on_expr(expr, p_psm); - } - - void - sequence_xs::print(std::ostream & os) const { - os << ""; - } #endif bool @@ -167,9 +225,9 @@ namespace xo { { return ppii.pps()->pretty_struct (ppii, - "SequenceSsm", - xrefrtag("seq_expr.size", seq_expr_->size()), - xrefrtag("expect", this->get_expect_str())); + "DSequenceSsm", + refrtag("seq_expr.size", seq_expr_->size()), + refrtag("expect", this->get_expect_str())); } } /*namespace scm*/ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 085cce56..82435b50 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ namespace xo { using xo::print::APrintable; + using xo::facet::FacetRegistry; using xo::facet::with_facet; namespace scm { @@ -188,6 +190,21 @@ namespace xo { this->top_ssm().on_parsed_expression_with_semicolon(expr, this); } + void + ParserStateMachine::on_parsed_expression_with_token(obj expr, + const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("expr", expr), xtag("tk", tk)); + + assert(stack_); + + this->top_ssm().on_parsed_expression(expr, this); + + assert(stack_); + + this->top_ssm().on_token(tk, this); + } + void ParserStateMachine::on_token(const Token & tk) { @@ -215,7 +232,11 @@ namespace xo { ParserStateMachine::capture_error(std::string_view ssm_name, const DString * errmsg) { - this->result_ = ParserResult::error(ssm_name, errmsg); + if (result_.is_error()) { + /* in case one error triggers another, remmber just the first one */ + } else { + this->result_ = ParserResult::error(ssm_name, errmsg); + } } void @@ -302,7 +323,7 @@ namespace xo { xtag("param_type", param_type), xtag("expecting", expect_str), xtag("ssm", ssm_name), - xtag("via", "ParserStateMachine::illegal_parsed_expression")); + xtag("via", "ParserStateMachine::illegal_parsed_formal")); assert(expr_alloc_); @@ -341,8 +362,16 @@ namespace xo { // - want to write error message using DArena // - need something like log_streambuf and/or tostr() that's arena-aware + obj expr_pr + = FacetRegistry::instance().variant(expr); + assert(expr_pr); + + /** TODO + * problem here: we have pretty() support for obj, + * but not "ordinary printing" support. So expression doesn't get printed + **/ auto errmsg_string = tostr("Unexpected expression", - xtag("expr", expr), + xtag("expr", expr_pr), xtag("expecting", expect_str), xtag("ssm", ssm_name), xtag("via", "ParserStateMachine::illegal_parsed_expression")); diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index ef487af3..b30b67f3 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -215,7 +215,7 @@ namespace xo { /** Walkthrough parsing input equivalent to: * - * lambda (n : i64, + * lambda (n : i64, r : i64) -> i64 { 123 } * **/ @@ -375,11 +375,10 @@ namespace xo { REQUIRE(result.is_incomplete()); } -#ifdef NOT_YET { - auto & result = parser.on_token(Token::string_token("fooey")); + auto & result = parser.on_token(Token::i64_token("123")); - log && log("after string token:"); + log && log("after f64(123) token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); @@ -389,17 +388,16 @@ namespace xo { } { - auto & result = parser.on_token(Token::semicolon_token()); + auto & result = parser.on_token(Token::rightbrace_token()); - log && log("after semicolon token:"); + log && log("after rightbrace token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(parser.has_incomplete_expr() == true); REQUIRE(!result.is_error()); - REQUIRE(!result.is_incomplete()); + REQUIRE(result.is_incomplete()); } -#endif //REQUIRE(result.is_error()); //// illegal input on token From 75b9e62c842cf1777e7dab1236256dc65df11826 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 31 Jan 2026 21:33:39 -0500 Subject: [PATCH 173/342] xo-reader2: DLambdaSsm work towards producing DLambdaExpr [WIP] --- include/xo/tokenizer2/Token.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index fc5dfc9a..ab3f0cb7 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -102,7 +102,7 @@ namespace xo { /** token representing left brace @c "{" **/ static Token leftbrace_token() { return Token(tokentype::tk_leftbrace); } /** token representing right brace @c "}" **/ - static Token rightbrace() { return Token(tokentype::tk_rightbrace); } + static Token rightbrace_token() { return Token(tokentype::tk_rightbrace); } /** token representing period @c "." **/ static Token dot() { return Token(tokentype::tk_dot); } /** token representing comma @c "," **/ From 939885a7d2577ee1fff73e2c4e8402eb9b9735ce Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 1 Feb 2026 00:16:37 -0500 Subject: [PATCH 174/342] xo-reader2: construct LambdaExpr to complete LambdaSsm + utest --- include/xo/reader2/ParserStateMachine.hpp | 3 +++ src/reader2/DLambdaSsm.cpp | 19 +++++++++++++------ src/reader2/ParserStateMachine.cpp | 6 ++++++ utest/SchematikaParser.test.cpp | 5 +++-- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 91c84ef1..d065e24f 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -82,6 +82,9 @@ namespace xo { **/ const DUniqueString * intern_string(std::string_view str); + /** get unique (within stringtable) string, beginning with @p prefix **/ + const DUniqueString * gensym(std::string_view prefix); + /** push nested local symtab while parsing the body of a lambda expression; * restore previous symtab at the end of lambda-expression definition. * See @ref pop_local_symtab diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 4b2d7df8..4ed77732 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -11,6 +11,7 @@ #include "DExpectExprSsm.hpp" #include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" +#include #include #include //#include @@ -336,17 +337,23 @@ namespace xo { DLambdaSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) { - if (lm_state_ == lambdastatetype::lm_4) { + if (lmstate_ == lambdastatetype::lm_4) { this->lmstate_ = lambdastatetype::lm_5; this->body_ = expr; // assemble lambda - obj lm_expr = DLambda::make(p_psm->expr_alloc(), - xxx typeref, - xxx name, - local_symtab_, - body_); + auto prefix = TypeRef::prefix_type::from_chars("lm"); + TypeRef tref = TypeRef::dwim(prefix, nullptr); + + const DUniqueString * name = p_psm->gensym("lambda"); + + auto lm_expr = obj + (DLambdaExpr::make(p_psm->expr_alloc(), + tref, + name, + local_symtab_, + body_)); p_psm->pop_ssm(); // this lambda p_psm->on_parsed_expression(lm_expr); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 82435b50..cf9c26c1 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -90,6 +90,12 @@ namespace xo { return stringtable_.intern(str); } + const DUniqueString * + ParserStateMachine::gensym(std::string_view str) + { + return stringtable_.gensym(str); + } + void ParserStateMachine::push_local_symtab(DLocalSymtab * symtab) { diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index b30b67f3..0defdeb5 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -394,9 +394,10 @@ namespace xo { log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(parser.has_incomplete_expr() == false); REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); } //REQUIRE(result.is_error()); From 029fc4ae00850d3275ec175f914059023c7ddf6f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 1 Feb 2026 17:26:24 -0500 Subject: [PATCH 175/342] xo-reader2 xo-gc: streamline example + DX1Collector.ref() method --- example/readerreplxx/readerreplxx.cpp | 69 +++++++++++++++++---------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/example/readerreplxx/readerreplxx.cpp b/example/readerreplxx/readerreplxx.cpp index 341893cf..122b2730 100644 --- a/example/readerreplxx/readerreplxx.cpp +++ b/example/readerreplxx/readerreplxx.cpp @@ -134,6 +134,43 @@ namespace { } } +struct AppConfig { + using ReaderConfig = xo::scm::ReaderConfig; + using CollectorConfig = xo::mm::CollectorConfig; + + AppConfig() { + rdr_config_.reader_debug_flag_ = true; + //rdr_config.parser_debug_flag_ = true; + //rdr_config.tk_debug_flag_ = true; + } + + std::size_t max_history_size_ = 1000; + std::string repl_history_fname_ = "repl_history.txt";; + CollectorConfig x1_config_ = (CollectorConfig().with_size(4*1024*1024)); + ReaderConfig rdr_config_; +}; + +struct AppContext { + using DX1Collector = xo::mm::DX1Collector; + using CollectorConfig = xo::mm::CollectorConfig; + using Replxx = replxx::Replxx; + + AppContext(const AppConfig & cfg = AppConfig()) : config_{cfg}, + x1_{CollectorConfig().with_size(4*1024*1024)}, + rdr_{config_.rdr_config_, x1_.ref()} + { + rx_.set_max_history_size(config_.max_history_size_); + rx_.history_load(config_.repl_history_fname_); + // rx.bind_key_internal(Replxx::KEY::control('p'), "history_previous"); + // rx.bind_key_internal(Replxx::KEY::control('n'), "history_next"); + } + + AppConfig config_; + Replxx rx_; + DX1Collector x1_; + SchematikaReader rdr_; +}; + int main() { @@ -143,7 +180,6 @@ main() using xo::scm::ReaderConfig; using xo::mm::AAllocator; using xo::mm::DX1Collector; - using xo::mm::CollectorConfig; using xo::mm::DArena; using xo::facet::with_facet; using xo::facet::obj; @@ -158,45 +194,28 @@ main() InitSubsys::require(); Subsystem::initialize_all(); - Replxx rx; - rx.set_max_history_size(1000); - rx.history_load("repl_history.txt"); -// rx.bind_key_internal(Replxx::KEY::control('p'), "history_previous"); -// rx.bind_key_internal(Replxx::KEY::control('n'), "history_next"); + AppConfig cfg; + AppContext cx(cfg); constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag)); - CollectorConfig x1_config = (CollectorConfig() - .with_size(4*1024*1024)); - DX1Collector x1(x1_config); - obj expr_alloc = with_facet::mkobj(&x1); - - // accepting defaults too - ReaderConfig rdr_config; - { - rdr_config.reader_debug_flag_ = true; - //rdr_config.parser_debug_flag_ = true; - //rdr_config.tk_debug_flag_ = true; - } - - SchematikaReader rdr(rdr_config, expr_alloc); using span_type = SchematikaReader::span_type; welcome(cerr); - rdr.begin_interactive_session(); + cx.rdr_.begin_interactive_session(); bool eof = false; const char * input_str = nullptr; span_type input; - while (replxx_getline(interactive, rdr.is_at_toplevel(), rx, &input_str)) { + while (replxx_getline(interactive, cx.rdr_.is_at_toplevel(), cx.rx_, &input_str)) { if (input_str && *input_str) { input = span_type::from_cstr(input_str); while (!input.empty() - && reader_seq(&rdr, &input, false /*eof*/, c_debug_flag)) + && reader_seq(&cx.rdr_, &input, false /*eof*/, c_debug_flag)) { ; } @@ -209,9 +228,9 @@ main() } /* reminder: eof can complete at most one token */ - reader_seq(&rdr, &input, true /*eof*/, c_debug_flag); + reader_seq(&cx.rdr_, &input, true /*eof*/, c_debug_flag); - rx.history_save("repl_history.txt"); + cx.rx_.history_save(cx.config_.repl_history_fname_); } /* end readerreplxx.cpp */ From 6b2ebe02ac40127267fb098010ec1a0f53390ff4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 1 Feb 2026 22:12:28 -0500 Subject: [PATCH 176/342] xo-interpreter2: work towards utest w/ vsm+reader [WIP] --- example/readerreplxx/readerreplxx.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example/readerreplxx/readerreplxx.cpp b/example/readerreplxx/readerreplxx.cpp index 122b2730..c95dd101 100644 --- a/example/readerreplxx/readerreplxx.cpp +++ b/example/readerreplxx/readerreplxx.cpp @@ -136,7 +136,7 @@ namespace { struct AppConfig { using ReaderConfig = xo::scm::ReaderConfig; - using CollectorConfig = xo::mm::CollectorConfig; + using X1CollectorConfig = xo::mm::X1CollectorConfig; AppConfig() { rdr_config_.reader_debug_flag_ = true; @@ -146,17 +146,17 @@ struct AppConfig { std::size_t max_history_size_ = 1000; std::string repl_history_fname_ = "repl_history.txt";; - CollectorConfig x1_config_ = (CollectorConfig().with_size(4*1024*1024)); ReaderConfig rdr_config_; + X1CollectorConfig x1_config_ = (X1CollectorConfig().with_size(4*1024*1024)); }; struct AppContext { using DX1Collector = xo::mm::DX1Collector; - using CollectorConfig = xo::mm::CollectorConfig; + using X1CollectorConfig = xo::mm::X1CollectorConfig; using Replxx = replxx::Replxx; AppContext(const AppConfig & cfg = AppConfig()) : config_{cfg}, - x1_{CollectorConfig().with_size(4*1024*1024)}, + x1_{X1CollectorConfig().with_size(4*1024*1024)}, rdr_{config_.rdr_config_, x1_.ref()} { rx_.set_max_history_size(config_.max_history_size_); From eb929bb69359c9304d9b47976ee5baf888e7fbb3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 2 Feb 2026 10:53:28 -0500 Subject: [PATCH 177/342] xo-interpreter2: refactor to setup vsm utest + repl --- include/xo/reader2/ReaderConfig.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/reader2/ReaderConfig.hpp b/include/xo/reader2/ReaderConfig.hpp index 826bb215..5b02e62c 100644 --- a/include/xo/reader2/ReaderConfig.hpp +++ b/include/xo/reader2/ReaderConfig.hpp @@ -41,7 +41,7 @@ namespace xo { size_t max_stringtable_cap_ = 64*1024; /** debug flag for schematika_reader **/ - bool reader_debug_flag_ = false;; + bool reader_debug_flag_ = false; }; } /*namespace scm*/ From eec85cc217648b78c06304a3f755d547b55e0250 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 2 Feb 2026 21:55:34 -0500 Subject: [PATCH 178/342] xo-interpreter2: scaffold repl + alloc measurement frameowkr --- include/xo/reader2/ParserStateMachine.hpp | 6 +++++ include/xo/reader2/SchematikaParser.hpp | 6 +++++ include/xo/reader2/SchematikaReader.hpp | 9 +++++++ src/reader2/ParserStateMachine.cpp | 24 ++++++++++++++++++ src/reader2/SchematikaParser.cpp | 13 ++++++++++ src/reader2/SchematikaReader.cpp | 31 +++++++++++++++++++++++ 6 files changed, 89 insertions(+) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index d065e24f..89569695 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -36,6 +36,7 @@ namespace xo { using AAllocator = xo::mm::AAllocator; using ArenaConfig = xo::mm::ArenaConfig; using DArena = xo::mm::DArena; + using MemorySizeInfo = xo::mm::MemorySizeInfo; using size_type = std::size_t; public: @@ -61,6 +62,11 @@ namespace xo { /** top of parser stack **/ obj top_ssm() const; + /** number of distinct memory pools owned by PS **/ + std::size_t _n_store() const noexcept; + /** memory consumption for i'th memory pool **/ + MemorySizeInfo _store_info(std::size_t i) const noexcept; + ///@} /** @defgroup scm-parserstatemachine-bookkeeping bookkeeping methods **/ diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 7be74aa5..83e9230b 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -156,6 +156,7 @@ namespace xo { using token_type = Token; using ArenaConfig = xo::mm::ArenaConfig; using AAllocator = xo::mm::AAllocator; + using MemorySizeInfo = xo::mm::MemorySizeInfo; using ppindentinfo = xo::print::ppindentinfo; using size_type = std::size_t; @@ -192,6 +193,11 @@ namespace xo { /** top of parser stack **/ obj top_ssm() const; + /** number of distinct memory pools owned by PS **/ + std::size_t _n_store() const noexcept; + /** memory consumption for i'th memory pool **/ + MemorySizeInfo _store_info(std::size_t i) const noexcept; + ///@} /** scm-schematikaparser-general-methods **/ ///@{ diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index fd26a4ec..3c2b5312 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -36,6 +36,7 @@ namespace xo { class SchematikaReader { public: using AAllocator = xo::mm::AAllocator; + using MemorySizeInfo = xo::mm::MemorySizeInfo; using span_type = xo::mm::span; using size_type = std::size_t; @@ -43,6 +44,9 @@ namespace xo { SchematikaReader(const ReaderConfig & config, obj expr_alloc); + std::size_t _n_store() const noexcept; + MemorySizeInfo _store_info(std::size_t i) const noexcept; + /** true iff parser is at top-level. * false iff parser is working on incomplete expression **/ @@ -53,6 +57,11 @@ namespace xo { **/ void begin_interactive_session(); + /** prepare batch session + * (limits expression types at toplevel) + **/ + void begin_batch_session(); + /** consume input @p input_cstr **/ const ReaderResult & read_expr(span_type input_span, bool eof); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index cf9c26c1..ff845762 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -16,6 +16,7 @@ #include namespace xo { + using xo::mm::MemorySizeInfo; using xo::print::APrintable; using xo::facet::FacetRegistry; using xo::facet::with_facet; @@ -53,6 +54,29 @@ namespace xo { return this->stack_->top(); } + std::size_t + ParserStateMachine::_n_store() const noexcept + { + return stringtable_._n_store() + 1; + } + + MemorySizeInfo + ParserStateMachine::_store_info(std::size_t i) const noexcept + { + size_t n0 = stringtable_._n_store(); + + if (i < n0) + return stringtable_._store_info(i); + + if (i == n0) + return parser_alloc_._store_info(); + + // not counting expr_alloc_. We don't consider + // that to be owned by ParserStateMachine + + return MemorySizeInfo::sentinel(); + } + void ParserStateMachine::establish_toplevel_ssm(obj ssm) { diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index e584044c..07c74d17 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -13,6 +13,7 @@ namespace xo { using xo::mm::AAllocator; + using xo::mm::MemorySizeInfo; using xo::tostr; using xo::xtag; @@ -46,6 +47,18 @@ namespace xo { return psm_.top_ssm(); } + std::size_t + SchematikaParser::_n_store() const noexcept + { + return psm_._n_store(); + } + + MemorySizeInfo + SchematikaParser::_store_info(std::size_t i) const noexcept + { + return psm_._store_info(i); + } + void SchematikaParser::begin_interactive_session() { diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index 4dd8600c..097c68df 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -6,6 +6,8 @@ #include "SchematikaReader.hpp" namespace xo { + using xo::mm::MemorySizeInfo; + namespace scm { SchematikaReader::SchematikaReader(const ReaderConfig & config, obj expr_alloc) @@ -19,6 +21,29 @@ namespace xo { { } + std::size_t + SchematikaReader::_n_store() const noexcept + { + return tokenizer_._n_store() + parser_._n_store(); + } + + MemorySizeInfo + SchematikaReader::_store_info(std::size_t i) const noexcept + { + size_t n_tk = tokenizer_._n_store(); + + if (i < n_tk) { + return tokenizer_._store_info(i); + } + + size_t n_pr = parser_._n_store(); + + if (i < n_tk + n_pr) + return parser_._store_info(i - n_tk); + + return MemorySizeInfo::sentinel(); + } + bool SchematikaReader::is_at_toplevel() const noexcept { @@ -31,6 +56,12 @@ namespace xo { parser_.begin_interactive_session(); } + void + SchematikaReader::begin_batch_session() + { + parser_.begin_batch_session(); + } + // TODO: // Schematika::end_interactive_session() From 415a382442e496d2ac04fd2942aa68f84e9ee1a0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 2 Feb 2026 21:55:34 -0500 Subject: [PATCH 179/342] xo-interpreter2: scaffold repl + alloc measurement frameowkr --- include/xo/tokenizer2/Tokenizer.hpp | 6 ++++++ src/tokenizer2/Tokenizer.cpp | 13 +++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/xo/tokenizer2/Tokenizer.hpp b/include/xo/tokenizer2/Tokenizer.hpp index 3dc6da11..83015c03 100644 --- a/include/xo/tokenizer2/Tokenizer.hpp +++ b/include/xo/tokenizer2/Tokenizer.hpp @@ -61,6 +61,7 @@ namespace xo { using error_type = TokenizerError; using DCircularBuffer = xo::mm::DCircularBuffer; using CircularBufferConfig = xo::mm::CircularBufferConfig; + using MemorySizeInfo = xo::mm::MemorySizeInfo; using span_type = xo::mm::span; //using input_state_type = TkInputState; using result_type = scan_result; @@ -90,6 +91,11 @@ namespace xo { const TkInputState & input_state() const { return input_state_; } #pragma GCC diagnostic pop + /** number of distinct memory pools owned by tokenizer **/ + std::size_t _n_store() const noexcept; + /** memory consumption for i'th memory pool **/ + MemorySizeInfo _store_info(std::size_t i) const noexcept; + ///@} /** @defgroup tokenizer-general-methods tokenizer methods **/ diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index c79e10c3..c36d85a5 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -6,6 +6,7 @@ #include "Tokenizer.hpp" namespace xo { + using xo::mm::MemorySizeInfo; using std::byte; namespace scm { @@ -21,6 +22,18 @@ namespace xo { this->input_state_.discard_current_line(); } + std::size_t + Tokenizer::_n_store() const noexcept + { + return input_buffer_._n_store(); + } + + MemorySizeInfo + Tokenizer::_store_info(std::size_t i) const noexcept + { + return input_buffer_._store_info(i); + } + bool Tokenizer::is_1char_punctuation(CharT ch) { From d243124ea8ad7366ec219c4cc8ce48e8820e9c15 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Feb 2026 01:05:36 -0500 Subject: [PATCH 180/342] xo-interpreter2 .. xo-arena. memory pool introspection --- include/xo/reader2/ParserStateMachine.hpp | 8 +++----- include/xo/reader2/SchematikaParser.hpp | 8 +++----- include/xo/reader2/SchematikaReader.hpp | 9 ++++++--- src/reader2/ParserStateMachine.cpp | 21 ++++---------------- src/reader2/SchematikaParser.cpp | 12 +++--------- src/reader2/SchematikaReader.cpp | 24 ++++------------------- 6 files changed, 23 insertions(+), 59 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 89569695..3fae8903 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -36,7 +36,7 @@ namespace xo { using AAllocator = xo::mm::AAllocator; using ArenaConfig = xo::mm::ArenaConfig; using DArena = xo::mm::DArena; - using MemorySizeInfo = xo::mm::MemorySizeInfo; + using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using size_type = std::size_t; public: @@ -62,10 +62,8 @@ namespace xo { /** top of parser stack **/ obj top_ssm() const; - /** number of distinct memory pools owned by PS **/ - std::size_t _n_store() const noexcept; - /** memory consumption for i'th memory pool **/ - MemorySizeInfo _store_info(std::size_t i) const noexcept; + /** visit psm-owned memory pools; call visitor(info) for each **/ + void visit_pools(const MemorySizeVisitor & visitor) const; ///@} diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 83e9230b..8c3f51b1 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -156,7 +156,7 @@ namespace xo { using token_type = Token; using ArenaConfig = xo::mm::ArenaConfig; using AAllocator = xo::mm::AAllocator; - using MemorySizeInfo = xo::mm::MemorySizeInfo; + using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using ppindentinfo = xo::print::ppindentinfo; using size_type = std::size_t; @@ -193,10 +193,8 @@ namespace xo { /** top of parser stack **/ obj top_ssm() const; - /** number of distinct memory pools owned by PS **/ - std::size_t _n_store() const noexcept; - /** memory consumption for i'th memory pool **/ - MemorySizeInfo _store_info(std::size_t i) const noexcept; + /** visit parser-owned memory pools; invoke visitor(info) for each **/ + void visit_pools(const MemorySizeVisitor & visitor) const; ///@} /** scm-schematikaparser-general-methods **/ diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index 3c2b5312..ee3de91f 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -36,7 +36,7 @@ namespace xo { class SchematikaReader { public: using AAllocator = xo::mm::AAllocator; - using MemorySizeInfo = xo::mm::MemorySizeInfo; + using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using span_type = xo::mm::span; using size_type = std::size_t; @@ -44,8 +44,11 @@ namespace xo { SchematikaReader(const ReaderConfig & config, obj expr_alloc); - std::size_t _n_store() const noexcept; - MemorySizeInfo _store_info(std::size_t i) const noexcept; + /** visit reader-owned memory pools; call visitor(info) for each. + * Specifically exclude expr_alloc, since we don't consider + * that reader-owned + **/ + void visit_pools(const MemorySizeVisitor & visitor) const; /** true iff parser is at top-level. * false iff parser is working on incomplete expression diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index ff845762..38f7ff4a 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -54,27 +54,14 @@ namespace xo { return this->stack_->top(); } - std::size_t - ParserStateMachine::_n_store() const noexcept + void + ParserStateMachine::visit_pools(const MemorySizeVisitor & visitor) const { - return stringtable_._n_store() + 1; - } - - MemorySizeInfo - ParserStateMachine::_store_info(std::size_t i) const noexcept - { - size_t n0 = stringtable_._n_store(); - - if (i < n0) - return stringtable_._store_info(i); - - if (i == n0) - return parser_alloc_._store_info(); + stringtable_.visit_pools(visitor); + parser_alloc_.visit_pools(visitor); // not counting expr_alloc_. We don't consider // that to be owned by ParserStateMachine - - return MemorySizeInfo::sentinel(); } void diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 07c74d17..c53acc16 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -47,16 +47,10 @@ namespace xo { return psm_.top_ssm(); } - std::size_t - SchematikaParser::_n_store() const noexcept + void + SchematikaParser::visit_pools(const MemorySizeVisitor & visitor) const { - return psm_._n_store(); - } - - MemorySizeInfo - SchematikaParser::_store_info(std::size_t i) const noexcept - { - return psm_._store_info(i); + return psm_.visit_pools(visitor); } void diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index 097c68df..47140d63 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -21,27 +21,11 @@ namespace xo { { } - std::size_t - SchematikaReader::_n_store() const noexcept + void + SchematikaReader::visit_pools(const MemorySizeVisitor & visitor) const { - return tokenizer_._n_store() + parser_._n_store(); - } - - MemorySizeInfo - SchematikaReader::_store_info(std::size_t i) const noexcept - { - size_t n_tk = tokenizer_._n_store(); - - if (i < n_tk) { - return tokenizer_._store_info(i); - } - - size_t n_pr = parser_._n_store(); - - if (i < n_tk + n_pr) - return parser_._store_info(i - n_tk); - - return MemorySizeInfo::sentinel(); + tokenizer_.visit_pools(visitor); + parser_.visit_pools(visitor); } bool From 3f5bd39ed8e5a38a7d44052c7be29b73a62d5de3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Feb 2026 01:05:36 -0500 Subject: [PATCH 181/342] xo-interpreter2 .. xo-arena. memory pool introspection --- include/xo/tokenizer2/Tokenizer.hpp | 8 +++----- src/tokenizer2/Tokenizer.cpp | 12 +++--------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/include/xo/tokenizer2/Tokenizer.hpp b/include/xo/tokenizer2/Tokenizer.hpp index 83015c03..0a212a8f 100644 --- a/include/xo/tokenizer2/Tokenizer.hpp +++ b/include/xo/tokenizer2/Tokenizer.hpp @@ -61,7 +61,7 @@ namespace xo { using error_type = TokenizerError; using DCircularBuffer = xo::mm::DCircularBuffer; using CircularBufferConfig = xo::mm::CircularBufferConfig; - using MemorySizeInfo = xo::mm::MemorySizeInfo; + using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using span_type = xo::mm::span; //using input_state_type = TkInputState; using result_type = scan_result; @@ -91,10 +91,8 @@ namespace xo { const TkInputState & input_state() const { return input_state_; } #pragma GCC diagnostic pop - /** number of distinct memory pools owned by tokenizer **/ - std::size_t _n_store() const noexcept; - /** memory consumption for i'th memory pool **/ - MemorySizeInfo _store_info(std::size_t i) const noexcept; + /** visit tokenizer-owned memory pools; invoke visitor(info) for each one **/ + void visit_pools(const MemorySizeVisitor & visitor) const; ///@} diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index c36d85a5..f176a88f 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -22,16 +22,10 @@ namespace xo { this->input_state_.discard_current_line(); } - std::size_t - Tokenizer::_n_store() const noexcept + void + Tokenizer::visit_pools(const MemorySizeVisitor & visitor) const { - return input_buffer_._n_store(); - } - - MemorySizeInfo - Tokenizer::_store_info(std::size_t i) const noexcept - { - return input_buffer_._store_info(i); + input_buffer_.visit_pools(visitor); } bool From 3f19001c94527008ea9d7bc07c8dfb209fd99a8d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Feb 2026 10:32:43 -0500 Subject: [PATCH 182/342] xo-reader2 stack: curate memory pool naming --- include/xo/reader2/ReaderConfig.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/reader2/ReaderConfig.hpp b/include/xo/reader2/ReaderConfig.hpp index 5b02e62c..62e0e758 100644 --- a/include/xo/reader2/ReaderConfig.hpp +++ b/include/xo/reader2/ReaderConfig.hpp @@ -28,7 +28,7 @@ namespace xo { bool tk_debug_flag_ = false; /** arena configuration for parser stack **/ - ArenaConfig parser_arena_config_ { .name_ = "parer-arena", + ArenaConfig parser_arena_config_ { .name_ = "parser-arena", .size_ = 2*1024*1024, .hugepage_z_ = 2*1024*1024, .store_header_flag_ = false, From d895083b584efaaee53e271ad5e7b6af1337b8b6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Feb 2026 11:55:50 -0500 Subject: [PATCH 183/342] xo-interpreter2 stack: cleanup memory reporting --- include/xo/reflectutil/typeseq.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/xo/reflectutil/typeseq.hpp b/include/xo/reflectutil/typeseq.hpp index dd0b869a..d2f888cd 100644 --- a/include/xo/reflectutil/typeseq.hpp +++ b/include/xo/reflectutil/typeseq.hpp @@ -16,6 +16,10 @@ namespace xo { */ template struct typeseq_impl { + /** create sentinel value **/ + typeseq_impl() = default; + + /** typeseq with specific unique id **/ explicit typeseq_impl(int32_t s) : seqno_{s} {} /** Can't have this be constexpr. @@ -56,7 +60,7 @@ namespace xo { private: static int32_t s_next_id; - int32_t seqno_; + int32_t seqno_ = 0; }; template From 6621d3900e381633860f0ef6455e20e2192a6463 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Feb 2026 12:58:55 -0500 Subject: [PATCH 184/342] xo-interpreter2 stack: bugfix: top-level i64 token -> DInteger --- src/reader2/DExprSeqState.cpp | 13 +++++--- utest/SchematikaParser.test.cpp | 54 +++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index ca6bfa27..802f37a2 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -12,14 +12,19 @@ #include #include + #include #include + #include #include -#include -#include + #include +#include + +#include #include + #include namespace xo { @@ -336,8 +341,8 @@ namespace xo { switch (seqtype_) { case exprseqtype::toplevel_interactive: { - auto i64o = DFloat::box(p_psm->expr_alloc(), - tk.i64_value()); + auto i64o = DInteger::box(p_psm->expr_alloc(), + tk.i64_value()); auto expr = DConstant::make(p_psm->expr_alloc(), i64o); DProgressSsm::start(p_psm->parser_alloc(), diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 0defdeb5..29697389 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -197,6 +197,60 @@ namespace xo { //REQUIRE(result.error_description()); } + TEST_CASE("SchematikaParser-interactive-integer", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * 1011 ; + * + **/ + + { + auto & result = parser.on_token(Token::i64_token("1011")); + + log && log("after integer token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::semicolon_token()); + + log && log("after semicolon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + } + + //REQUIRE(result.is_error()); + //// illegal input on token + //REQUIRE(result.error_description()); + } + TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]") { constexpr bool c_debug_flag = true; From 574185ccdf44457b934f06de3b4c6004a67495b1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Feb 2026 13:23:38 -0500 Subject: [PATCH 185/342] xo-reader2 stack: misc qol improvements + improve reader2 utest --- utest/SchematikaParser.test.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 29697389..0761ce39 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -18,11 +20,15 @@ namespace xo { using xo::scm::syntaxstatetype; // using xo::scm::DDefineSsm; using xo::scm::DExpectExprSsm; + using xo::scm::AExpression; + using xo::scm::DConstant; // using xo::scm::defexprstatetype; //using xo::scm::ParserResult; //using xo::scm::parser_result_type; using xo::scm::Token; using xo::scm::DString; + using xo::scm::DInteger; + using xo::mm::AGCObject; using xo::mm::ArenaConfig; using xo::mm::AAllocator; using xo::mm::DArena; @@ -244,6 +250,17 @@ namespace xo { REQUIRE(!result.is_error()); REQUIRE(result.is_expression()); REQUIRE(result.result_expr()); + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + + REQUIRE(expr->value()); + + auto value_i64 = obj::from(expr->value()); + + REQUIRE(value_i64); + + REQUIRE(value_i64->value() == 1011); } //REQUIRE(result.is_error()); From bdccad4087f6820a4edaecfc0a4763f6d48c7366 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Feb 2026 13:43:00 -0500 Subject: [PATCH 186/342] xo-reader2 stack: convenience #includes + parsing examples --- utest/SchematikaParser.test.cpp | 147 +++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 4 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 0761ce39..9ccad56b 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -9,8 +9,11 @@ #include #include #include +#include #include +#include #include +#include #include #include @@ -20,15 +23,18 @@ namespace xo { using xo::scm::syntaxstatetype; // using xo::scm::DDefineSsm; using xo::scm::DExpectExprSsm; + using xo::scm::AExpression; + using xo::scm::DDefineExpr; using xo::scm::DConstant; -// using xo::scm::defexprstatetype; + //using xo::scm::ParserResult; - //using xo::scm::parser_result_type; using xo::scm::Token; - using xo::scm::DString; - using xo::scm::DInteger; using xo::mm::AGCObject; + using xo::scm::DString; + using xo::scm::DFloat; + using xo::scm::DInteger; + using xo::mm::ArenaConfig; using xo::mm::AAllocator; using xo::mm::DArena; @@ -196,6 +202,9 @@ namespace xo { log && log(xtag("result", result)); REQUIRE(parser.has_incomplete_expr() == false); + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); } // define-expressions not properly implemented @@ -268,6 +277,136 @@ namespace xo { //REQUIRE(result.error_description()); } + TEST_CASE("SchematikaParser-interactive-float", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * 3.14159265 ; + * + **/ + + { + auto & result = parser.on_token(Token::f64_token("3.14159265")); + + log && log("after float token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::semicolon_token()); + + log && log("after semicolon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + + REQUIRE(expr->value()); + + auto value_f64 = obj::from(expr->value()); + + REQUIRE(value_f64); + + REQUIRE(value_f64->value() == 3.14159265); + } + + //REQUIRE(result.is_error()); + //// illegal input on token + //REQUIRE(result.error_description()); + } + + TEST_CASE("SchematikaParser-interactive-string", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * "hello world" ; + * + **/ + + { + auto & result = parser.on_token(Token::string_token("hello world")); + + log && log("after string token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::semicolon_token()); + + log && log("after semicolon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + + REQUIRE(expr->value()); + + auto value_str = obj::from(expr->value()); + + REQUIRE(value_str); + + REQUIRE(strcmp(value_str->chars(), "hello world") == 0); + } + + //REQUIRE(result.is_error()); + //// illegal input on token + //REQUIRE(result.error_description()); + } + TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]") { constexpr bool c_debug_flag = true; From 0e043f56a46efaa6b8e8fa4c7428dc4080d0eb8f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Feb 2026 14:27:42 -0500 Subject: [PATCH 187/342] xo-reader2 stack: streamlining + arith parser test --- src/reader2/DProgressSsm.cpp | 36 ++++++----- utest/SchematikaParser.test.cpp | 108 ++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 15 deletions(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 9fd6e7b1..102384e2 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -1038,21 +1038,27 @@ namespace xo { obj lhs = FacetRegistry::instance().variant(lhs_); - obj rhs; - if (rhs_) - rhs = FacetRegistry::instance().variant(rhs_); - - (void)lhs; - - return ppii.pps()->pretty_struct - (ppii, - "DProgressSsm", - refrtag("lhs", lhs), - refrtag("op", op_type_), - cond(rhs, refrtag("rhs", rhs), "nullptr"), - refrtag("expect", this->get_expect_str()) - ); + obj rhs + = FacetRegistry::instance().try_variant(rhs_); + if (rhs) { + return ppii.pps()->pretty_struct + (ppii, + "DProgressSsm", + refrtag("lhs", lhs), + refrtag("op", op_type_), + refrtag("rhs", rhs), + refrtag("expect", this->get_expect_str()) + ); + } else { + return ppii.pps()->pretty_struct + (ppii, + "DProgressSsm", + refrtag("lhs", lhs), + refrtag("op", op_type_), + refrtag("expect", this->get_expect_str()) + ); + } } obj @@ -1065,7 +1071,7 @@ namespace xo { constexpr const char * c_self_name = "DProgressSsm::assemble_expr"; - if ((op_type_ != optype::invalid) && rhs_) { + if ((op_type_ != optype::invalid) && !rhs_) { std::string errmsg_string = tostr("expected expression on rhs of operator op", xtag("lhs", lhs_), xtag("op", op_type_)); diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 9ccad56b..2fb10ea5 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -26,11 +28,13 @@ namespace xo { using xo::scm::AExpression; using xo::scm::DDefineExpr; + using xo::scm::DApplyExpr; using xo::scm::DConstant; //using xo::scm::ParserResult; using xo::scm::Token; using xo::mm::AGCObject; + using xo::scm::DPrimitive_gco_2_gco_gco; using xo::scm::DString; using xo::scm::DFloat; using xo::scm::DInteger; @@ -407,6 +411,110 @@ namespace xo { //REQUIRE(result.error_description()); } + TEST_CASE("SchematikaParser-interactive-arith", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * 3.14159265 * 0.5 ; + * + **/ + + { + auto & result = parser.on_token(Token::f64_token("3.14159265")); + + log && log("after float(3.14159265) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::star_token()); + + log && log("after star token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::f64_token("0.5")); + + log && log("after float(0.5) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::semicolon_token()); + + log && log("after semicolon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + + REQUIRE(expr->n_args() == 2); + + auto fn = obj::from(expr->fn()); + REQUIRE(fn); + + auto pm = obj::from(fn->value()); + REQUIRE(pm); + REQUIRE(pm->name() == "_mul"); + + auto lhs = obj::from(expr->arg(0)); + REQUIRE(lhs); + + auto lhs_f64 = obj::from(lhs->value()); + REQUIRE(lhs_f64); + REQUIRE(lhs_f64->value() == 3.14159265); + + auto rhs = obj::from(expr->arg(1)); + REQUIRE(rhs); + + auto rhs_f64 = obj::from(rhs->value()); + REQUIRE(rhs_f64); + REQUIRE(rhs_f64->value() == 0.5); + } + + //REQUIRE(result.is_error()); + //// illegal input on token + //REQUIRE(result.error_description()); + } + TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]") { constexpr bool c_debug_flag = true; From 2aa6dfd942984b5b4a73895170096bfc678a831e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 4 Feb 2026 10:32:16 -0500 Subject: [PATCH 188/342] xo-reader2 xo-expression2: streamline pretty w/ presence flag --- src/reader2/DProgressSsm.cpp | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 102384e2..626963b4 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -1041,24 +1041,16 @@ namespace xo { obj rhs = FacetRegistry::instance().try_variant(rhs_); - if (rhs) { - return ppii.pps()->pretty_struct - (ppii, - "DProgressSsm", - refrtag("lhs", lhs), - refrtag("op", op_type_), - refrtag("rhs", rhs), - refrtag("expect", this->get_expect_str()) - ); - } else { - return ppii.pps()->pretty_struct - (ppii, - "DProgressSsm", - refrtag("lhs", lhs), - refrtag("op", op_type_), - refrtag("expect", this->get_expect_str()) - ); - } + bool rhs_present = rhs; + + return ppii.pps()->pretty_struct + (ppii, + "DProgressSsm", + refrtag("lhs", lhs), + refrtag("op", op_type_), + refrtag("rhs", rhs, rhs_present), + refrtag("expect", this->get_expect_str()) + ); } obj From 4cd4328f071954e6bd247cc8cd48cab1038dee07 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 5 Feb 2026 10:44:11 -0500 Subject: [PATCH 189/342] xo-interpreter2 stack: work on variable references [WIP] --- include/xo/reader2/ExpectExprSsm.hpp | 12 ++ include/xo/reader2/ParserStateMachine.hpp | 8 + src/reader2/DExpectExprSsm.cpp | 41 +++-- src/reader2/DIfElseSsm.cpp | 3 +- src/reader2/ParserStateMachine.cpp | 57 +++++++ utest/SchematikaParser.test.cpp | 174 +++++++++++++++++++++- 6 files changed, 274 insertions(+), 21 deletions(-) create mode 100644 include/xo/reader2/ExpectExprSsm.hpp diff --git a/include/xo/reader2/ExpectExprSsm.hpp b/include/xo/reader2/ExpectExprSsm.hpp new file mode 100644 index 00000000..d46ef489 --- /dev/null +++ b/include/xo/reader2/ExpectExprSsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectExprSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DExpectExprSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" +#include "ssm/IPrintable_DExpectExprSsm.hpp" + +/* end ExpectExprSsm.hpp */ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 3fae8903..2bee6a96 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -89,6 +89,9 @@ namespace xo { /** get unique (within stringtable) string, beginning with @p prefix **/ const DUniqueString * gensym(std::string_view prefix); + /** get variable defn for @p symbolname, or else nullptr **/ + Binding lookup_binding(std::string_view symbolname); + /** push nested local symtab while parsing the body of a lambda expression; * restore previous symtab at the end of lambda-expression definition. * See @ref pop_local_symtab @@ -229,6 +232,11 @@ namespace xo { obj, std::string_view expect_str); + /** report error - no binding for variable @p sym + **/ + void error_unbound_variable(std::string_view ssm_name, + std::string_view sym); + ///@} private: diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index cddfb865..b1b0701b 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -3,23 +3,18 @@ * @author Roland Conybeare, Jan 2026 **/ -#include "DExpectExprSsm.hpp" +#include "ExpectExprSsm.hpp" #include "ParserStateMachine.hpp" #include "SyntaxStateMachine.hpp" -#include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" #include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" #include "DSequenceSsm.hpp" #include "syntaxstatetype.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include @@ -196,7 +191,27 @@ namespace xo { DExpectExprSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) { - Super::on_token(tk, p_psm); + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log(xtag("tk", tk)); + + const DVariable * var = p_psm->lookup_variable(tk.text()); + + if (!var) { + p_psm->error_unbound_variable(ssm_classname(), + tk.text()); + } + + // examples of possible continuations from symbol foo + // foo ; // (1) foo is entire rvalue expression + // foo + ... // (2) foo begin operator expression + // foo(..); // (3) foo begin apply function + // + // + + DProgressSsm::start(p_psm->parser_alloc(), + obj(const_cast(var)), + p_psm); } #ifdef NOT_YET diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index 7efb4a7e..0782f23a 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -68,8 +68,7 @@ namespace xo { obj expr_mm, ParserStateMachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); DIfElseExpr * if_expr = DIfElseExpr::_make_empty(expr_mm); DIfElseSsm * if_ssm = DIfElseSsm::_make(parser_mm, if_expr); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 38f7ff4a..bd1effbb 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -107,6 +107,48 @@ namespace xo { return stringtable_.gensym(str); } + Binding + ParserStateMachine::lookup_binding(std::string_view symbolname) + { + scope log(XO_DEBUG(debug_flag_)); + + if (!local_symtab_) + return Binding::null(); + + const DUniqueString * ustr = stringtable_.lookup(symbolname); + + if (!ustr) { + // if not in string table, then can't be a variable either + return Binding::null(); + } + + DLocalSymtab * symtab = local_symtab_; + + // count #of nested scopes to cross, to reach symbol + // + int32_t link_count = 0; + + while (symtab) { + Binding b = symtab->lookup_binding(ustr); + + if (b.is_local()) { + assert(b.i_link() == 0); + + return Binding(link_count, b.j_slot()); + } + + ++link_count; + symtab = symtab->parent(); + } + + // TODO: check global symtab also + + log.retroactively_enable(); + log("STUB: check global symtab"); + + return Binding::null(); + } + void ParserStateMachine::push_local_symtab(DLocalSymtab * symtab) { @@ -400,6 +442,21 @@ namespace xo { this->capture_error(ssm_name, errmsg); } + + void + ParserStateMachine::error_unbound_variable(std::string_view ssm_name, + std::string_view sym) + { + auto errmsg_string = tostr("No binding for symbol", + xtag("symbol", sym), + xtag("ssm", ssm_name)); + + auto errmsg = DString::from_view(expr_alloc_, + std::string_view(errmsg_string)); + + this->capture_error(ssm_name, errmsg); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 2fb10ea5..48983353 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -220,7 +220,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; @@ -285,7 +285,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; @@ -350,7 +350,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; @@ -415,7 +415,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; @@ -517,7 +517,7 @@ namespace xo { TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]") { - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag)); ArenaConfig config; @@ -725,7 +725,7 @@ namespace xo { TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]") { - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag)); ArenaConfig config; @@ -834,6 +834,168 @@ namespace xo { //REQUIRE(result.error_description()); } + TEST_CASE("SchematikaParser-interactive-lambda2", "[reader2][SchematikaParser]") + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * lambda (x : i64) -> i64 { x * x }; + * + **/ + + { + auto & result = parser.on_token(Token::lambda_token()); + + log && log("after lambda token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::leftparen_token()); + + log && log("after lparen token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("x")); + + log && log("after symbol(n) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::colon_token()); + + log && log("after colon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("i64")); + + log && log("after symbol(i64) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::rightparen_token()); + + log && log("after rightparen token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::yields_token()); + + log && log("after yields token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("i64")); + + log && log("after symbol(i64) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::leftbrace_token()); + + log && log("after leftbrace token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("x")); + + log && log("after symbol(x) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + +#ifdef NOPE + { + auto & result = parser.on_token(Token::rightbrace_token()); + + log && log("after rightbrace token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + } + + //REQUIRE(result.is_error()); + //// illegal input on token + //REQUIRE(result.error_description()); +#endif + REQUIRE(false); + } } /*namespace ut*/ } /*namespace xo*/ From ca1370570b407e366b588b4032e49c1d7fc971e1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 5 Feb 2026 15:45:40 -0500 Subject: [PATCH 190/342] xo-reader2 stack: top-level lambda w/ apply parses --- idl/SyntaxStateMachine.json5 | 6 +- include/xo/reader2/DDefineSsm.hpp | 9 +- include/xo/reader2/DExpectExprSsm.hpp | 7 +- include/xo/reader2/DExprSeqState.hpp | 6 +- include/xo/reader2/DIfElseSsm.hpp | 7 +- include/xo/reader2/DLambdaSsm.hpp | 5 +- include/xo/reader2/DProgressSsm.hpp | 5 +- include/xo/reader2/DSequenceSsm.hpp | 8 ++ include/xo/reader2/DSyntaxStateMachine.hpp | 12 +- include/xo/reader2/ParserStateMachine.hpp | 26 ++-- .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 6 +- .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 7 +- .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 4 +- .../ISyntaxStateMachine_DExpectExprSsm.hpp | 4 +- ...SyntaxStateMachine_DExpectFormalArgSsm.hpp | 4 +- ...axStateMachine_DExpectFormalArglistSsm.hpp | 4 +- .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 4 +- .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 4 +- .../ssm/ISyntaxStateMachine_DExprSeqState.hpp | 4 +- .../ssm/ISyntaxStateMachine_DIfElseSsm.hpp | 4 +- .../ssm/ISyntaxStateMachine_DLambdaSsm.hpp | 4 +- .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 4 +- .../ssm/ISyntaxStateMachine_DSequenceSsm.hpp | 4 +- .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 9 +- .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 11 +- src/reader2/DDefineSsm.cpp | 27 +++- src/reader2/DExpectExprSsm.cpp | 11 +- src/reader2/DExprSeqState.cpp | 15 ++- src/reader2/DIfElseSsm.cpp | 24 +++- src/reader2/DLambdaSsm.cpp | 7 +- src/reader2/DProgressSsm.cpp | 45 +++---- src/reader2/DSequenceSsm.cpp | 33 ++++- src/reader2/ISyntaxStateMachine_Any.cpp | 2 +- .../ISyntaxStateMachine_DDefineSsm.cpp | 4 +- .../ISyntaxStateMachine_DExpectExprSsm.cpp | 4 +- ...SyntaxStateMachine_DExpectFormalArgSsm.cpp | 4 +- ...axStateMachine_DExpectFormalArglistSsm.cpp | 4 +- .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 4 +- .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 4 +- .../ISyntaxStateMachine_DExprSeqState.cpp | 4 +- .../ISyntaxStateMachine_DIfElseSsm.cpp | 4 +- .../ISyntaxStateMachine_DLambdaSsm.cpp | 4 +- .../ISyntaxStateMachine_DProgressSsm.cpp | 4 +- .../ISyntaxStateMachine_DSequenceSsm.cpp | 4 +- src/reader2/ParserStateMachine.cpp | 118 ++++++++++++------ utest/SchematikaParser.test.cpp | 32 +++-- 46 files changed, 332 insertions(+), 194 deletions(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 716b7268..4e33e468 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -101,13 +101,15 @@ ], }, { - name: "on_parsed_expression_with_semicolon", - doc: ["update state machine for incoming parsed expression @p expr followed by semicolon"], + name: "on_parsed_expression_with_token", + doc: ["update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk"], return_type: "void", args: [ {type: "obj", name: "expr"}, + {type: "const Token &", name: "tk"}, {type: "ParserStateMachine *", name: "p_psm"}, ], }, ], + router_facet_explicit_content: [ ], } diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 0e3b1404..d675090e 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -176,11 +176,12 @@ namespace xo { ParserStateMachine * p_psm); /** update state for this syntax after parsing an expression @p expr - * followed by semicolon, - * overall parser state in @p p_psm + * followed by token @p tk, + * with overall parser state in @p p_psm **/ - void on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm); + void on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm); ///@} /** @defgroup scm-define-printable-facet printable facet methods **/ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 6b2fe30f..9b4bbd98 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -113,11 +113,12 @@ namespace xo { ParserStateMachine * p_psm); /** update state for this syntax after parsing an expression @p expr - * followed by semicolon, + * followed by token @p tk * overall parser state in @p p_psm **/ - void on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm); + void on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm); ///@} /** @defgroup scm-define-printable-facet printable facet methods **/ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 56578161..72e26203 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -120,10 +120,12 @@ namespace xo { void on_parsed_expression(obj expr, ParserStateMachine * p_psm); /** update state for this syntax on parsed expression @p expr - * followed by semicolon from nested ssm. + * followed by token @p tk from nested ssm. * overall parser state in @p p_psm **/ - void on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm); + void on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm); ///@} /** @defgroup scm-exprseq-printable-facet printable facet methods **/ diff --git a/include/xo/reader2/DIfElseSsm.hpp b/include/xo/reader2/DIfElseSsm.hpp index 5e6d4d8c..986ffcd7 100644 --- a/include/xo/reader2/DIfElseSsm.hpp +++ b/include/xo/reader2/DIfElseSsm.hpp @@ -54,7 +54,7 @@ namespace xo { **/ class DIfElseSsm : public DSyntaxStateMachine { public: - using Super = DSyntaxStateMachine; + using Super = DSyntaxStateMachine; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -154,8 +154,9 @@ namespace xo { * followed by semicolon, * with overall parser state in @p p_psm. **/ - void on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm); + void on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm); ///@} /** @defgroup scm-ifelsessm-printable-facet printable facet methods **/ diff --git a/include/xo/reader2/DLambdaSsm.hpp b/include/xo/reader2/DLambdaSsm.hpp index d4147c76..d494639c 100644 --- a/include/xo/reader2/DLambdaSsm.hpp +++ b/include/xo/reader2/DLambdaSsm.hpp @@ -150,8 +150,9 @@ namespace xo { /** update this ssm when nested parser * emits expression @p expr **/ - void on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm); + void on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm); #ifdef NOT_YET virtual const char * get_expect_str() const override; diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 792d6eb2..3b9dff6f 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -168,8 +168,9 @@ namespace xo { ParserStateMachine * p_psm); void on_rightbrace_token(const Token & tk, ParserStateMachine * p_psm); - void on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm); + void on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm); ///@} /** @defgroup scm-progressssm-printable-facet printable facet methods **/ diff --git a/include/xo/reader2/DSequenceSsm.hpp b/include/xo/reader2/DSequenceSsm.hpp index e2943ae8..486187fc 100644 --- a/include/xo/reader2/DSequenceSsm.hpp +++ b/include/xo/reader2/DSequenceSsm.hpp @@ -28,6 +28,7 @@ namespace xo { class DSequenceSsm : public DSyntaxStateMachine { public: + using Super = DSyntaxStateMachine; //using Sequence = xo::scm::Sequence; //using Lambda = xo::scm::Lambda; using AAllocator = xo::mm::AAllocator; @@ -78,6 +79,13 @@ namespace xo { void on_parsed_expression(obj expr, ParserStateMachine * p_psm); + /** consume expression @p expr produced by nested ssm followed by token @p tk; + * overall parser state in @p p_psm + **/ + void on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-sequencessm-printable-facet printable facet **/ ///@{ diff --git a/include/xo/reader2/DSyntaxStateMachine.hpp b/include/xo/reader2/DSyntaxStateMachine.hpp index f5a835ae..947d3b84 100644 --- a/include/xo/reader2/DSyntaxStateMachine.hpp +++ b/include/xo/reader2/DSyntaxStateMachine.hpp @@ -114,8 +114,9 @@ namespace xo { /** Default implementation for required SyntaxStateMachine facet method **/ - void on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) + void on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm) { // starting with c++23 can use "this auto&& self" instead Derived & self = static_cast(*this); @@ -124,9 +125,10 @@ namespace xo { // since the semicolon isn't relevant to problem with syntax // - p_psm->illegal_parsed_expression(Derived::ssm_classname(), - expr, - self.get_expect_str()); + p_psm->illegal_parsed_expression_with_token(Derived::ssm_classname(), + expr, + tk, + self.get_expect_str()); } }; diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 2bee6a96..d8dc8da9 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -89,8 +90,8 @@ namespace xo { /** get unique (within stringtable) string, beginning with @p prefix **/ const DUniqueString * gensym(std::string_view prefix); - /** get variable defn for @p symbolname, or else nullptr **/ - Binding lookup_binding(std::string_view symbolname); + /** get variable reference for @p symbolname in current context, or else nullptr **/ + DVarRef * lookup_varref(std::string_view symbolname); /** push nested local symtab while parsing the body of a lambda expression; * restore previous symtab at the end of lambda-expression definition. @@ -141,17 +142,6 @@ namespace xo { **/ void on_parsed_expression(obj expr); - /** update state to respond to parsed expression @p expr - * (from nested parsing state), with trailing semicolon. - * - * Need to distinguish cases like: - * 6 // ; allowed - * f(6 // ) allowed ; forbidden - * 6 + // ) forbidden ; forbidden - * - **/ - void on_parsed_expression_with_semicolon(obj expr); - /** update state to respond to parsed expression @p expr * (from nested parsing state), with trailing token @p tk. * @@ -232,6 +222,16 @@ namespace xo { obj, std::string_view expect_str); + /** report illegal parsed expression @p expr from nested ssm @p ssm_name, + * presented with immediately-following input token @p tk + * Introducing as placeholder; not clear if this will be reachable + * in full parser + **/ + void illegal_parsed_expression_with_token(std::string_view ssm_name, + obj expr, + const Token & tk, + std::string_view expect_str); + /** report error - no binding for variable @p sym **/ void error_unbound_variable(std::string_view ssm_name, diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index b6475877..93a0e402 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -51,6 +51,8 @@ public: // const methods /** RTTI: unique id# for actual runtime data representation **/ virtual typeseq _typeseq() const noexcept = 0; + /** destroy instance @p d; calls c++ dtor only for actual runtime type; does not recover memory **/ + virtual void _drop(Opaque d) const noexcept = 0; /** identify a type of syntax state machine **/ virtual syntaxstatetype ssm_type(Copaque data) const noexcept = 0; /** text describing expected/allowed input to this ssm in current state **/ @@ -69,8 +71,8 @@ public: virtual void on_parsed_formal_arglist(Opaque data, DArray * arglist, ParserStateMachine * p_psm) = 0; /** update state machine for incoming parsed expression @p expr **/ virtual void on_parsed_expression(Opaque data, obj expr, ParserStateMachine * p_psm) = 0; - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - virtual void on_parsed_expression_with_semicolon(Opaque data, obj expr, ParserStateMachine * p_psm) = 0; + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + virtual void on_parsed_expression_with_token(Opaque data, obj expr, const Token & tk, ParserStateMachine * p_psm) = 0; ///@} }; /*ASyntaxStateMachine*/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 9cf16408..05d292cc 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -54,8 +54,11 @@ namespace scm { // from ASyntaxStateMachine - // const methods + // builtin methods typeseq _typeseq() const noexcept override { return s_typeseq; } + [[noreturn]] void _drop(Opaque) const noexcept override { _fatal(); } + + // const methods [[noreturn]] syntaxstatetype ssm_type(Copaque) const noexcept override { _fatal(); } [[noreturn]] std::string_view get_expect_str(Copaque) const noexcept override { _fatal(); } @@ -66,7 +69,7 @@ namespace scm { [[noreturn]] void on_parsed_formal(Opaque, const DUniqueString *, TypeDescr, ParserStateMachine *) override; [[noreturn]] void on_parsed_formal_arglist(Opaque, DArray *, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression(Opaque, obj, ParserStateMachine *) override; - [[noreturn]] void on_parsed_expression_with_semicolon(Opaque, obj, ParserStateMachine *) override; + [[noreturn]] void on_parsed_expression_with_token(Opaque, obj, const Token &, ParserStateMachine *) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index c34a66a5..0a8ff60d 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -66,8 +66,8 @@ namespace xo { static void on_parsed_formal_arglist(DDefineSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - static void on_parsed_expression_with_semicolon(DDefineSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DDefineSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 7280b78e..e425386e 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -66,8 +66,8 @@ namespace xo { static void on_parsed_formal_arglist(DExpectExprSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - static void on_parsed_expression_with_semicolon(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExpectExprSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp index acf84462..4c8e8c44 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp @@ -66,8 +66,8 @@ namespace xo { static void on_parsed_formal_arglist(DExpectFormalArgSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - static void on_parsed_expression_with_semicolon(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExpectFormalArgSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp index 4cf9e3ff..2540684c 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp @@ -66,8 +66,8 @@ namespace xo { static void on_parsed_formal_arglist(DExpectFormalArglistSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - static void on_parsed_expression_with_semicolon(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExpectFormalArglistSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 1a33685f..4b4ea7dd 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -66,8 +66,8 @@ namespace xo { static void on_parsed_formal_arglist(DExpectSymbolSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - static void on_parsed_expression_with_semicolon(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExpectSymbolSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index 054c03f1..49c0ffe4 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -66,8 +66,8 @@ namespace xo { static void on_parsed_formal_arglist(DExpectTypeSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - static void on_parsed_expression_with_semicolon(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExpectTypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index cd241d52..cfb92548 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -66,8 +66,8 @@ namespace xo { static void on_parsed_formal_arglist(DExprSeqState & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DExprSeqState & self, obj expr, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - static void on_parsed_expression_with_semicolon(DExprSeqState & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExprSeqState & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp index 65f585af..f1594b02 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp @@ -66,8 +66,8 @@ namespace xo { static void on_parsed_formal_arglist(DIfElseSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - static void on_parsed_expression_with_semicolon(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DIfElseSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp index 6d931744..062de20c 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp @@ -66,8 +66,8 @@ namespace xo { static void on_parsed_formal_arglist(DLambdaSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - static void on_parsed_expression_with_semicolon(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DLambdaSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 27ec4f53..0d776976 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -66,8 +66,8 @@ namespace xo { static void on_parsed_formal_arglist(DProgressSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DProgressSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - static void on_parsed_expression_with_semicolon(DProgressSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DProgressSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp index da541414..90c17b36 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp @@ -66,8 +66,8 @@ namespace xo { static void on_parsed_formal_arglist(DSequenceSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ static void on_parsed_expression(DSequenceSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr followed by semicolon **/ - static void on_parsed_expression_with_semicolon(DSequenceSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DSequenceSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 5fffca24..971f08b8 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -42,8 +42,11 @@ namespace scm { // from ASyntaxStateMachine - // const methods + // builtin methods typeseq _typeseq() const noexcept override { return s_typeseq; } + void _drop(Opaque d) const noexcept override { _dcast(d).~DRepr(); } + + // const methods syntaxstatetype ssm_type(Copaque data) const noexcept override { return I::ssm_type(_dcast(data)); } @@ -70,8 +73,8 @@ namespace scm { void on_parsed_expression(Opaque data, obj expr, ParserStateMachine * p_psm) override { return I::on_parsed_expression(_dcast(data), expr, p_psm); } - void on_parsed_expression_with_semicolon(Opaque data, obj expr, ParserStateMachine * p_psm) override { - return I::on_parsed_expression_with_semicolon(_dcast(data), expr, p_psm); + void on_parsed_expression_with_token(Opaque data, obj expr, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_parsed_expression_with_token(_dcast(data), expr, tk, p_psm); } ///@} diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index b84082d2..28be39be 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -46,8 +46,13 @@ public: /** @defgroup scm-syntaxstatemachine-router-methods **/ ///@{ - // const methods + // explicit injected content + + // builtin methods typeseq _typeseq() const noexcept { return O::iface()->_typeseq(); } + void _drop() const noexcept { O::iface()->_drop(O::data()); } + + // const methods syntaxstatetype ssm_type() const noexcept { return O::iface()->ssm_type(O::data()); } @@ -74,8 +79,8 @@ public: void on_parsed_expression(obj expr, ParserStateMachine * p_psm) { return O::iface()->on_parsed_expression(O::data(), expr, p_psm); } - void on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm) { - return O::iface()->on_parsed_expression_with_semicolon(O::data(), expr, p_psm); + void on_parsed_expression_with_token(obj expr, const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_parsed_expression_with_token(O::data(), expr, tk, p_psm); } ///@} diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 4ad36f4f..26a68224 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -626,7 +626,7 @@ namespace xo { { if (defstate_ == defexprstatetype::def_6) { p_psm->pop_ssm(); - p_psm->on_parsed_expression_with_semicolon(def_expr_); + p_psm->on_parsed_expression_with_token(def_expr_, tk); return; } @@ -649,11 +649,28 @@ namespace xo { } void - DDefineSsm::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) + DDefineSsm::on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm) { - this->on_parsed_expression(expr, p_psm); - this->on_semicolon_token(Token::semicolon_token(), p_psm); + /* must end with semicolon */ + + if (tk.tk_type() == tokentype::tk_semicolon) { + if (defstate_ == defexprstatetype::def_5) + { + this->defstate_ = defexprstatetype::def_6; + + def_expr_.data()->assign_rhs(expr); + + // completes this definition syntax + this->on_semicolon_token(tk, p_psm); + + return; + } + } + + // error in all other cases + Super::on_parsed_expression_with_token(expr, tk, p_psm); } bool diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index b1b0701b..c3cb4b31 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -195,7 +195,7 @@ namespace xo { log && log(xtag("tk", tk)); - const DVariable * var = p_psm->lookup_variable(tk.text()); + DVarRef * var = p_psm->lookup_varref(tk.text()); if (!var) { p_psm->error_unbound_variable(ssm_classname(), @@ -210,7 +210,7 @@ namespace xo { // DProgressSsm::start(p_psm->parser_alloc(), - obj(const_cast(var)), + obj(var), p_psm); } @@ -388,14 +388,15 @@ namespace xo { } void - DExpectExprSsm::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) + DExpectExprSsm::on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm) { // expression (reported by nested ProgressSsm) // completes this DExpectExprSsm's assignment p_psm->pop_ssm(); - p_psm->on_parsed_expression_with_semicolon(expr); + p_psm->on_parsed_expression_with_token(expr, tk); } bool diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 802f37a2..08094655 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -167,7 +167,10 @@ namespace xo { case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_colon: + break; case tokentype::tk_semicolon: + assert(false); + break; case tokentype::tk_doublecolon: case tokentype::tk_singleassign: case tokentype::tk_assign: @@ -396,10 +399,16 @@ namespace xo { } void - DExprSeqState::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) + DExprSeqState::on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm) { - p_psm->capture_result("DExprSeqState::on_parsed_expression_with_semicolon", expr); + if (tk.tk_type() == tokentype::tk_semicolon) { + p_psm->capture_result("DExprSeqState::on_parsed_expression_with_token", expr); + return; + } + + Super::on_parsed_expression_with_token(expr, tk, p_psm); } bool diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index 0782f23a..ccf4705f 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -150,13 +150,15 @@ namespace xo { case tokentype::tk_else: this->on_else_token(tk, p_psm); return; + case tokentype::tk_semicolon: + this->on_semicolon_token(tk, p_psm); + return; case tokentype::tk_colon: case tokentype::tk_singleassign: case tokentype::tk_string: case tokentype::tk_f64: case tokentype::tk_i64: case tokentype::tk_bool: - case tokentype::tk_semicolon: case tokentype::tk_invalid: case tokentype::tk_leftparen: case tokentype::tk_rightparen: @@ -405,13 +407,25 @@ namespace xo { } void - DIfElseSsm::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) + DIfElseSsm::on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm) { scope log(XO_DEBUG(p_psm->debug_flag())); - this->on_parsed_expression(expr, p_psm); - this->on_semicolon_token(Token::semicolon_token(), p_psm); + // TODO: may consider allowing if-else to terminate on other particular tokens + // e.g. ')' + + if ((tk.tk_type() == tokentype::tk_then) + || (tk.tk_type() == tokentype::tk_else) + || (tk.tk_type() == tokentype::tk_semicolon)) + { + this->on_parsed_expression(expr, p_psm); + this->on_token(tk, p_psm); + return; + } + + Super::on_parsed_expression_with_token(expr, tk, p_psm); } bool diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 4ed77732..286fcfa5 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -364,10 +364,11 @@ namespace xo { } void - DLambdaSsm::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) + DLambdaSsm::on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm) { - Super::on_parsed_expression_with_semicolon(expr, p_psm); + Super::on_parsed_expression_with_token(expr, tk, p_psm); } #ifdef NOT_YET diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 626963b4..751264dd 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -319,10 +319,7 @@ namespace xo { obj expr = this->assemble_expr(p_psm); p_psm->pop_ssm(); // completes self - - // TODO: perhaps need to generalize on_parsed_expression_with_semicolon() ..? - p_psm->on_parsed_expression(expr); - p_psm->on_token(tk); + p_psm->on_parsed_expression_with_token(expr, tk); } void @@ -458,25 +455,7 @@ namespace xo { } p_psm->pop_ssm(); - p_psm->on_parsed_expression_with_semicolon(expr); - - /* control here on input like: - * (1.234; - * - * a. '(' sets up stack [lparen_0:expect_rhs_expression] - * (see exprstate::on_leftparen()) - * b. 1.234 pushes (in case operators) [lparen_0:expect_rhs_expression:expr_progress] - * (see exprstate::on_f64()) - * c. semicolon completes expr_progress [lparen_0:expect_rhs_expression] - * deliver expresssion to expect_rhs_expression.on_expr_with_semicolon() - * (see exprstate::on_expr_with_semicolon()) - * d. expr_rhs_expression forwards expression to [lparen_0] - * e. lparen_0 would advance to [lparen_1], but rejects semicolon - */ - -#ifdef OBSOLETE - Super::on_token(tk, p_psm); -#endif + p_psm->on_parsed_expression_with_token(expr, tk); } void @@ -489,11 +468,15 @@ namespace xo { obj expr = this->assemble_expr(p_psm); - { + if (expr) { obj expr_pr - = FacetRegistry::instance().variant(expr); + = FacetRegistry::instance().try_variant(expr); assert(expr_pr); log && log(xtag("expr", expr_pr)); + } else { + // illegal token if assemble failed + Super::on_token(tk, p_psm); + return; } p_psm->pop_ssm(); @@ -501,15 +484,19 @@ namespace xo { } void - DProgressSsm::on_parsed_expression_with_semicolon(obj expr, - ParserStateMachine * p_psm) + DProgressSsm::on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm) { scope log(XO_DEBUG(p_psm->debug_flag()), xtag("expr", expr)); if (op_type_ == optype::invalid) { + // e.g. control here on input like + // x : = 4 4 + p_psm->illegal_parsed_expression - ("DProgressSsm::on_parsed_expression_with_semicolon", + ("DProgressSsm::on_parsed_expression_with_token", expr, this->get_expect_str()); return; @@ -521,7 +508,7 @@ namespace xo { if (expr2) { p_psm->pop_ssm(); - p_psm->on_parsed_expression_with_semicolon(expr2); + p_psm->on_parsed_expression_with_token(expr2, tk); } } diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index 56efb896..7a65d60d 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -147,10 +147,8 @@ namespace xo { { scope log(XO_DEBUG(p_psm->debug_flag())); - // TODO: stream inserter that sets up pretty-printing. - // Or integrate with indentlog. - // Maybe trouble is that indentlog doesn't #include Printable ? - // + // TODO: switch to printable facet + log && log(xtag("expr", expr)); #ifdef NOT_YET @@ -206,8 +204,31 @@ namespace xo { } #endif - this->seq_expr_->push_back(p_psm->expr_alloc(), - expr); + this->seq_expr_->push_back(p_psm->expr_alloc(), expr); + } + + void + DSequenceSsm::on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + if (tk.tk_type() == tokentype::tk_semicolon) { + // keep sequence on stack, consuming semicolon + + this->seq_expr_->push_back(p_psm->expr_alloc(), + expr); + return; + } else if (tk.tk_type() == tokentype::tk_rightbrace) { + // rightbrace ends sequence + + this->seq_expr_->push_back(p_psm->expr_alloc(), expr); + this->on_rightbrace_token(tk, p_psm); + return; + } + + Super::on_parsed_expression_with_token(expr, tk, p_psm); } #ifdef NOT_YET diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 2cd6f304..6a78fa5e 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -71,7 +71,7 @@ ISyntaxStateMachine_Any::on_parsed_expression(Opaque, obj, ParserSt } auto -ISyntaxStateMachine_Any::on_parsed_expression_with_semicolon(Opaque, obj, ParserStateMachine *) -> void +ISyntaxStateMachine_Any::on_parsed_expression_with_token(Opaque, obj, const Token &, ParserStateMachine *) -> void { _fatal(); } diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index 70ff908d..8940c1b5 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -58,9 +58,9 @@ namespace xo { self.on_parsed_expression(expr, p_psm); } auto - ISyntaxStateMachine_DDefineSsm::on_parsed_expression_with_semicolon(DDefineSsm & self, obj expr, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DDefineSsm::on_parsed_expression_with_token(DDefineSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_expression_with_semicolon(expr, p_psm); + self.on_parsed_expression_with_token(expr, tk, p_psm); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index e3e008dd..17f0ec3f 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -58,9 +58,9 @@ namespace xo { self.on_parsed_expression(expr, p_psm); } auto - ISyntaxStateMachine_DExpectExprSsm::on_parsed_expression_with_semicolon(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExpectExprSsm::on_parsed_expression_with_token(DExpectExprSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_expression_with_semicolon(expr, p_psm); + self.on_parsed_expression_with_token(expr, tk, p_psm); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp index c6b45889..77afbe60 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp @@ -58,9 +58,9 @@ namespace xo { self.on_parsed_expression(expr, p_psm); } auto - ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_expression_with_semicolon(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_expression_with_token(DExpectFormalArgSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_expression_with_semicolon(expr, p_psm); + self.on_parsed_expression_with_token(expr, tk, p_psm); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp index fc9ae0a0..619f2ceb 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp @@ -58,9 +58,9 @@ namespace xo { self.on_parsed_expression(expr, p_psm); } auto - ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_expression_with_semicolon(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_expression_with_token(DExpectFormalArglistSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_expression_with_semicolon(expr, p_psm); + self.on_parsed_expression_with_token(expr, tk, p_psm); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 1dee4234..efd7b893 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -58,9 +58,9 @@ namespace xo { self.on_parsed_expression(expr, p_psm); } auto - ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_expression_with_semicolon(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_expression_with_token(DExpectSymbolSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_expression_with_semicolon(expr, p_psm); + self.on_parsed_expression_with_token(expr, tk, p_psm); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 42a4ce23..32e07aaa 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -58,9 +58,9 @@ namespace xo { self.on_parsed_expression(expr, p_psm); } auto - ISyntaxStateMachine_DExpectTypeSsm::on_parsed_expression_with_semicolon(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExpectTypeSsm::on_parsed_expression_with_token(DExpectTypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_expression_with_semicolon(expr, p_psm); + self.on_parsed_expression_with_token(expr, tk, p_psm); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index faccd745..71b0cc1a 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -58,9 +58,9 @@ namespace xo { self.on_parsed_expression(expr, p_psm); } auto - ISyntaxStateMachine_DExprSeqState::on_parsed_expression_with_semicolon(DExprSeqState & self, obj expr, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExprSeqState::on_parsed_expression_with_token(DExprSeqState & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_expression_with_semicolon(expr, p_psm); + self.on_parsed_expression_with_token(expr, tk, p_psm); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp index 0283eee0..3dbd66a8 100644 --- a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp @@ -58,9 +58,9 @@ namespace xo { self.on_parsed_expression(expr, p_psm); } auto - ISyntaxStateMachine_DIfElseSsm::on_parsed_expression_with_semicolon(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DIfElseSsm::on_parsed_expression_with_token(DIfElseSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_expression_with_semicolon(expr, p_psm); + self.on_parsed_expression_with_token(expr, tk, p_psm); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp index f3f23819..967e328a 100644 --- a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp @@ -58,9 +58,9 @@ namespace xo { self.on_parsed_expression(expr, p_psm); } auto - ISyntaxStateMachine_DLambdaSsm::on_parsed_expression_with_semicolon(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DLambdaSsm::on_parsed_expression_with_token(DLambdaSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_expression_with_semicolon(expr, p_psm); + self.on_parsed_expression_with_token(expr, tk, p_psm); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index b4320d51..4cb25bf4 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -58,9 +58,9 @@ namespace xo { self.on_parsed_expression(expr, p_psm); } auto - ISyntaxStateMachine_DProgressSsm::on_parsed_expression_with_semicolon(DProgressSsm & self, obj expr, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DProgressSsm::on_parsed_expression_with_token(DProgressSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_expression_with_semicolon(expr, p_psm); + self.on_parsed_expression_with_token(expr, tk, p_psm); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp index b7f770df..b27f25ba 100644 --- a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp @@ -58,9 +58,9 @@ namespace xo { self.on_parsed_expression(expr, p_psm); } auto - ISyntaxStateMachine_DSequenceSsm::on_parsed_expression_with_semicolon(DSequenceSsm & self, obj expr, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DSequenceSsm::on_parsed_expression_with_token(DSequenceSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void { - self.on_parsed_expression_with_semicolon(expr, p_psm); + self.on_parsed_expression_with_token(expr, tk, p_psm); } } /*namespace scm*/ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index bd1effbb..56a4560c 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -107,38 +107,57 @@ namespace xo { return stringtable_.gensym(str); } - Binding - ParserStateMachine::lookup_binding(std::string_view symbolname) + DVarRef * + ParserStateMachine::lookup_varref(std::string_view symbolname) { scope log(XO_DEBUG(debug_flag_)); - if (!local_symtab_) - return Binding::null(); - - const DUniqueString * ustr = stringtable_.lookup(symbolname); - - if (!ustr) { - // if not in string table, then can't be a variable either - return Binding::null(); - } - - DLocalSymtab * symtab = local_symtab_; - - // count #of nested scopes to cross, to reach symbol + // TODO: + // 1. check global symtab + // 2. combine local+global symtab into indept struct + // 3. move lookup_varref implementation there. // - int32_t link_count = 0; - while (symtab) { - Binding b = symtab->lookup_binding(ustr); + if (local_symtab_) { + const DUniqueString * ustr = stringtable_.lookup(symbolname); - if (b.is_local()) { - assert(b.i_link() == 0); + if (ustr) { + DLocalSymtab * symtab = local_symtab_; - return Binding(link_count, b.j_slot()); + // count #of nested scopes to cross, to reach symbol + // + int32_t link_count = 0; + + while (symtab) { + Binding b = symtab->lookup_binding(ustr); + + if (b.is_local()) { + assert(b.i_link() == 0); + + DVariable * vardef = symtab->lookup_var(b); + assert(vardef); + + + /** ascii diagram here + **/ + + return DVarRef::make(expr_alloc_, + vardef, + link_count); + } else { + assert(b.is_null()); + } + + ++link_count; + symtab = symtab->parent(); + } + } else { + // if we don't already know the symbol, + // -> can't be a valid variable reference + // (whether global or local) + + return nullptr; } - - ++link_count; - symtab = symtab->parent(); } // TODO: check global symtab also @@ -146,7 +165,7 @@ namespace xo { log.retroactively_enable(); log("STUB: check global symtab"); - return Binding::null(); + return nullptr; } void @@ -239,16 +258,6 @@ namespace xo { this->top_ssm().on_parsed_expression(expr, this); } - void - ParserStateMachine::on_parsed_expression_with_semicolon(obj expr) - { - scope log(XO_DEBUG(debug_flag_), xtag("expr", expr)); - - assert(stack_); - - this->top_ssm().on_parsed_expression_with_semicolon(expr, this); - } - void ParserStateMachine::on_parsed_expression_with_token(obj expr, const Token & tk) @@ -257,11 +266,7 @@ namespace xo { assert(stack_); - this->top_ssm().on_parsed_expression(expr, this); - - assert(stack_); - - this->top_ssm().on_token(tk, this); + this->top_ssm().on_parsed_expression_with_token(expr, tk, this); } void @@ -443,6 +448,39 @@ namespace xo { this->capture_error(ssm_name, errmsg); } + void + ParserStateMachine::illegal_parsed_expression_with_token(std::string_view ssm_name, + obj expr, + const Token & tk, + std::string_view expect_str) + { + // TODO: + // - want to write error message using DArena + // - need something like log_streambuf and/or tostr() that's arena-aware + + obj expr_pr + = FacetRegistry::instance().variant(expr); + assert(expr_pr); + + /** TODO + * problem here: we have pretty() support for obj, + * but not "ordinary printing" support. So expression doesn't get printed + **/ + auto errmsg_string = tostr("Unexpected expression", + xtag("expr", expr_pr), + xtag("tk", tk), + xtag("expecting", expect_str), + xtag("ssm", ssm_name), + xtag("via", "ParserStateMachine::illegal_parsed_expression")); + + assert(expr_alloc_); + + auto errmsg = DString::from_view(expr_alloc_, + std::string_view(errmsg_string)); + + this->capture_error(ssm_name, errmsg); + } + void ParserStateMachine::error_unbound_variable(std::string_view ssm_name, std::string_view sym) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 48983353..740d71f4 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -976,11 +976,34 @@ namespace xo { REQUIRE(result.is_incomplete()); } -#ifdef NOPE + { + auto & result = parser.on_token(Token::star_token()); + + log && log("after star(*) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("x")); + + log && log("after symbol(x) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + { auto & result = parser.on_token(Token::rightbrace_token()); - log && log("after rightbrace token:"); + log && log("after rightbrace(}) token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); @@ -990,11 +1013,6 @@ namespace xo { REQUIRE(result.result_expr()); } - //REQUIRE(result.is_error()); - //// illegal input on token - //REQUIRE(result.error_description()); -#endif - REQUIRE(false); } } /*namespace ut*/ } /*namespace xo*/ From d65eb541026a45f27540c721f22a709d740d5269 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 10 Feb 2026 15:14:40 -0500 Subject: [PATCH 191/342] xo-reader2 stack: parenthesized expressions [WIP] --- CMakeLists.txt | 26 ++ idl/IPrintable_DParenSsm.json5 | 13 + idl/ISyntaxStateMachine_DParenSsm.json5 | 13 + include/xo/reader2/DDefineSsm.hpp | 11 +- include/xo/reader2/DExpectExprSsm.hpp | 6 + include/xo/reader2/DExprSeqState.hpp | 5 + include/xo/reader2/DLambdaSsm.hpp | 6 + include/xo/reader2/DParenSsm.hpp | 127 ++++++ include/xo/reader2/LambdaSsm.hpp | 10 + include/xo/reader2/ParenSsm.hpp | 12 + .../xo/reader2/ssm/IPrintable_DParenSsm.hpp | 62 +++ .../ssm/ISyntaxStateMachine_DParenSsm.hpp | 77 ++++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 4 + src/reader2/DDefineSsm.cpp | 1 - src/reader2/DExpectExprSsm.cpp | 26 +- src/reader2/DExprSeqState.cpp | 30 +- src/reader2/DLambdaSsm.cpp | 40 +- src/reader2/DParenSsm.cpp | 382 ++++++++++++++++++ src/reader2/IPrintable_DParenSsm.cpp | 28 ++ src/reader2/ISyntaxStateMachine_DParenSsm.cpp | 69 ++++ src/reader2/reader2_register_facets.cpp | 6 + src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 171 +++++++- 24 files changed, 1095 insertions(+), 35 deletions(-) create mode 100644 idl/IPrintable_DParenSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DParenSsm.json5 create mode 100644 include/xo/reader2/DParenSsm.hpp create mode 100644 include/xo/reader2/LambdaSsm.hpp create mode 100644 include/xo/reader2/ParenSsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DParenSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp create mode 100644 src/reader2/DParenSsm.cpp create mode 100644 src/reader2/IPrintable_DParenSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DParenSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c936619f..d1e807e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,6 +114,32 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-parenssm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ParenSsm + INPUT idl/ISyntaxStateMachine_DParenSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-parenssm + FACET_PKG xo_printable2 + FACET Printable + REPR ParenSsm + INPUT idl/IPrintable_DParenSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectformalarglistssm diff --git a/idl/IPrintable_DParenSsm.json5 b/idl/IPrintable_DParenSsm.json5 new file mode 100644 index 00000000..495729b5 --- /dev/null +++ b/idl/IPrintable_DParenSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DParenSsm", + using_doxygen: true, + repr: "DParenSsm", + doc: [ "implement APrintable for DParenSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DParenSsm.json5 b/idl/ISyntaxStateMachine_DParenSsm.json5 new file mode 100644 index 00000000..521e7ba8 --- /dev/null +++ b/idl/ISyntaxStateMachine_DParenSsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DParenSsm", + using_doxygen: true, + repr: "DParenSsm", + doc: [ "implement ASyntaxStateMachine for DParenSsm" ], +} diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index d675090e..f71477dd 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -6,7 +6,6 @@ #pragma once #include "DSyntaxStateMachine.hpp" -//#include "SyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" #include #include @@ -36,7 +35,7 @@ namespace xo { * --on_singleassign_token()--> def_5 * def_3 --on_typedescr()--> def_4 * def_4 --on_singleassign_token()--> def_5 - * def_5 --on_expr()--> def_6 + * def_5 --on_parsed_expression()--> def_6 * def_6 --on_semicolon_token()--> (done) * * def_1:expect_symbol: got 'def' keyword, symbol to follow @@ -104,9 +103,10 @@ namespace xo { /** @defgroup scm-definessm-access-methods **/ ///@{ + /** identify this nested state machine **/ static const char * ssm_classname() { return "DDefineSsm"; } - /** identify this nested state machine **/ + /** internal state **/ defexprstatetype defstate() const noexcept { return defstate_; } ///@} @@ -193,6 +193,9 @@ namespace xo { ///@} private: + /** @defgroup scm-definessm-member-vars **/ + ///@{ + /** identify define-expression state **/ defexprstatetype defstate_; @@ -200,6 +203,8 @@ namespace xo { * This will eventually be the output of this ssm **/ obj def_expr_; + + ///@} }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 9b4bbd98..d6558c1e 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -76,6 +76,12 @@ namespace xo { void on_string_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming lambda token @p tk, + * overall parser state in @p p_psm + **/ + void on_lambda_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expectexpr-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 72e26203..83448b5e 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -113,6 +113,11 @@ namespace xo { **/ void on_bool_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming leftparen token @p tk, + * overall parser state in @p p_psm + **/ + void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on parsed expression @p expr * from nested ssm. * overall parser state in @p p_psm diff --git a/include/xo/reader2/DLambdaSsm.hpp b/include/xo/reader2/DLambdaSsm.hpp index d494639c..5ecbecd2 100644 --- a/include/xo/reader2/DLambdaSsm.hpp +++ b/include/xo/reader2/DLambdaSsm.hpp @@ -96,6 +96,12 @@ namespace xo { void on_yields_token(const Token & tk, ParserStateMachine * p_psm); + /** update ssm on leftbrace token @p tk, + * with overall parser state in @p p_psm + **/ + void on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-lambdassm-syntaxstatemachine-facet **/ ///@{ diff --git a/include/xo/reader2/DParenSsm.hpp b/include/xo/reader2/DParenSsm.hpp new file mode 100644 index 00000000..2ed7f58c --- /dev/null +++ b/include/xo/reader2/DParenSsm.hpp @@ -0,0 +1,127 @@ +/** @file DParenSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include +#include + +namespace xo { + namespace scm { + + /** + * @pre + * + * ( x * x ) + * ^ ^ ^ ^ + * | | | (done) + * | | | + * | | lparen_2 + * | lparen_1:expect expr + * lparen_0 + * + * lparen_0 --on_leftparen_token()--> lparen_1 + * lparen_1 --on_parsed_expression()--> lparen_2 + * lparen_2 --on_rightparen_token()--> (done) + * + * @endpre + **/ + + enum class parenexprstatetype { + invalid = -1, + + lparen_0, + lparen_1, + lparen_2, + + N, + }; + + extern const char * parenexprstatetype_descr(parenexprstatetype x); + + std::ostream & + operator<<(std::ostream & os, parenexprstatetype x); + + class DParenSsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using TypeDescr = xo::reflect::TypeDescr; + using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; + + public: + /** @defgroup scm-parenssm-ctors **/ + ///@{ + + DParenSsm(); + + /** create instance using memory from @p parser_mm + **/ + static DParenSsm * make(DArena & parser_mm); + + /** push DParenSsm instance onto @p p_psm stack **/ + static void start(ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-parenssm-access-methods **/ + ///@{ + + /** identify this nested state machine **/ + static const char * ssm_classname() { return "DParenSsm"; } + + /** internal state **/ + parenexprstatetype parenstate() const noexcept { return parenstate_; } + + ///@} + /** @defgroup scm-parenssm-admin-methods admin methods **/ + ///@{ + + /** update ssm state for incoming leftparen token @p tk, + * with overall parser state in @p p_psm + **/ + void on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-parenssm-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies this ssm **/ + syntaxstatetype ssm_type() const noexcept; + + /** text describing expected/allowed input to this ssm in current state. **/ + std::string_view get_expect_str() const noexcept; + + /** update ssm for token @p tk, with overall state in @p p_psm **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-parenssm-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + /** @defgroup scm-parenssm-member-vars **/ + ///@{ + + /** identify paren-expression state **/ + parenexprstatetype parenstate_; + /** scaffold expression (representing parenthesized value) here **/ + obj expr_; + + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DParenSsm.hpp */ diff --git a/include/xo/reader2/LambdaSsm.hpp b/include/xo/reader2/LambdaSsm.hpp new file mode 100644 index 00000000..49ac731b --- /dev/null +++ b/include/xo/reader2/LambdaSsm.hpp @@ -0,0 +1,10 @@ +/** @file LambdaSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "DLambdaSsm.hpp" +#include "ssm/ISyntaxStateMachine_DLambdaSsm.hpp" +#include "ssm/IPrintable_DLambdaSsm.hpp" + +/* end LambdaSsm.hpp */ diff --git a/include/xo/reader2/ParenSsm.hpp b/include/xo/reader2/ParenSsm.hpp new file mode 100644 index 00000000..a9a786fd --- /dev/null +++ b/include/xo/reader2/ParenSsm.hpp @@ -0,0 +1,12 @@ +/** @file ParenSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DParenSsm.hpp" +#include "ssm/ISyntaxStateMachine_DParenSsm.hpp" +#include "ssm/IPrintable_DParenSsm.hpp" + +/* end ParenSsm.hpp */ diff --git a/include/xo/reader2/ssm/IPrintable_DParenSsm.hpp b/include/xo/reader2/ssm/IPrintable_DParenSsm.hpp new file mode 100644 index 00000000..2b4b49c2 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DParenSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DParenSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DParenSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DParenSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DParenSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DParenSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DParenSsm + **/ + class IPrintable_DParenSsm { + public: + /** @defgroup scm-printable-dparenssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dparenssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DParenSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp new file mode 100644 index 00000000..33be5e16 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp @@ -0,0 +1,77 @@ +/** @file ISyntaxStateMachine_DParenSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DParenSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DParenSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DParenSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DParenSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DParenSsm + **/ + class ISyntaxStateMachine_DParenSsm { + public: + /** @defgroup scm-syntaxstatemachine-dparenssm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dparenssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DParenSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DParenSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DParenSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DParenSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DParenSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DParenSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DParenSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DParenSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DParenSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index a5b4b563..3031a444 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -33,6 +33,9 @@ namespace xo { /** rhs expression. state exists to achieve 1-token lookahead **/ progress, + /** expression enclosed in parentheses. See @ref DParenSsm **/ + paren, + /** toplevel of some translation unit. See @ref DExprSeqState **/ expect_toplevel_expression_sequence, diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index d883fa82..4a813900 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -37,6 +37,10 @@ set(SELF_SRCS ISyntaxStateMachine_DLambdaSsm.cpp IPrintable_DLambdaSsm.cpp + DParenSsm.cpp + ISyntaxStateMachine_DParenSsm.cpp + IPrintable_DParenSsm.cpp + DExpectFormalArglistSsm.cpp ISyntaxStateMachine_DExpectFormalArglistSsm.cpp IPrintable_DExpectFormalArglistSsm.cpp diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 26a68224..2d2ecb0b 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -555,7 +555,6 @@ namespace xo { case tokentype::tk_end: case tokentype::N: break; - return; } Super::on_token(tk, p_psm); diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index c3cb4b31..c763e2a4 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -8,6 +8,7 @@ #include "SyntaxStateMachine.hpp" #include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" #include "DSequenceSsm.hpp" +#include "LambdaSsm.hpp" #include "syntaxstatetype.hpp" #include #include @@ -138,6 +139,10 @@ namespace xo { this->on_bool_token(tk, p_psm); return; + case tokentype::tk_lambda: + this->on_lambda_token(tk, p_psm); + return; + // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_if: @@ -165,7 +170,6 @@ namespace xo { case tokentype::tk_cmpeq: case tokentype::tk_cmpne: case tokentype::tk_type: - case tokentype::tk_lambda: case tokentype::tk_then: case tokentype::tk_else: case tokentype::tk_let: @@ -379,6 +383,15 @@ namespace xo { p_psm); } + void + DExpectExprSsm::on_lambda_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + DLambdaSsm::start(p_psm); + } + void DExpectExprSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) @@ -412,17 +425,6 @@ namespace xo { } #ifdef NOT_YET - void - expect_expr_xs::on_lambda_token(const token_type & /*tk*/, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - //constexpr const char * self_name = "exprstate::on_leftparen"; - - lambda_xs::start(p_psm); - } - void expect_expr_xs::on_if_token(const token_type & /*tk*/, parserstatemachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 08094655..82eb2f44 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -1,5 +1,5 @@ /** @file DExprSeqState.cpp -* + * * @author Roland Conybeare, Jan 2026 **/ @@ -9,6 +9,8 @@ #include "DLambdaSsm.hpp" #include "DProgressSsm.hpp" #include "DIfElseSsm.hpp" +#include "ParenSsm.hpp" +#include "ExpectExprSsm.hpp" #include #include @@ -152,9 +154,12 @@ namespace xo { this->on_bool_token(tk, p_psm); return; + case tokentype::tk_leftparen: + this->on_leftparen_token(tk, p_psm); + return; + // all the not-yet handled cases case tokentype::tk_invalid: - case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: @@ -389,6 +394,27 @@ namespace xo { Super::on_token(tk, p_psm); } + void + DExprSeqState::on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (seqtype_) { + case exprseqtype::toplevel_interactive: { + DParenSsm::start(p_psm); + p_psm->on_token(Token::leftparen_token()); + + return; + } + case exprseqtype::toplevel_batch: + break; + case exprseqtype::N: + assert(false); // unreachable + break; + } + + Super::on_token(tk, p_psm); + } + void DExprSeqState::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 286fcfa5..a2c2dfbd 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -136,6 +136,10 @@ namespace xo { this->on_yields_token(tk, p_psm); return; + case tokentype::tk_leftbrace: + this->on_leftbrace_token(tk, p_psm); + return; + // all the not-yet-handled cases case tokentype::tk_def: case tokentype::tk_if: @@ -152,7 +156,6 @@ namespace xo { case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: - case tokentype::tk_leftbrace: case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: @@ -179,11 +182,6 @@ namespace xo { } Super::on_token(tk, p_psm); -#ifdef OBSOLETE - p_psm->illegal_input_on_token("DLambdaSsm::on_token", - tk, - this->get_expect_str()); -#endif } void @@ -199,11 +197,6 @@ namespace xo { } Super::on_token(tk, p_psm); -#ifdef OBSOLETE - p_psm->illegal_input_on_token("DLambdaSsm::on_lambda_token", - tk, - this->get_expect_str()); -#endif } void @@ -220,13 +213,28 @@ namespace xo { } Super::on_token(tk, p_psm); -#ifdef OBSOLETE - p_psm->illegal_input_on_token("DLambdaSsm::on_yields_token", - tk, - this->get_expect_str()); -#endif } + void + DLambdaSsm::on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (lmstate_ == lambdastatetype::lm_2) { + // control here when leftbrace immediately follows + // formal param list. + // Otherwise leftbrace arrives in DExpectExprSsm + // pushed via on_parsed_typedescr() + + this->lmstate_ = lambdastatetype::lm_4; + + DExpectExprSsm::start(p_psm); + // precharge ssm for body with leftbrace + p_psm->on_token(Token::leftbrace_token()); + return; + } + + Super::on_token(tk, p_psm); + } void DLambdaSsm::on_parsed_typedescr(TypeDescr td, diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp new file mode 100644 index 00000000..166e96bf --- /dev/null +++ b/src/reader2/DParenSsm.cpp @@ -0,0 +1,382 @@ +/** @file DParenSsm.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "ParenSsm.hpp" +#include "syntaxstatetype.hpp" +#include + +namespace xo { + using xo::facet::with_facet; + using xo::facet::typeseq; + + namespace scm { + + extern const char * + parenexprstatetype_descr(parenexprstatetype x) + { + switch(x) { + case parenexprstatetype::invalid: return "invalid"; + case parenexprstatetype::lparen_0: return "lparen_0"; + case parenexprstatetype::lparen_1: return "lparen_1"; + case parenexprstatetype::lparen_2: return "lparen_2"; + case parenexprstatetype::N: break; + } + + return "???parenexprstatetype"; + } + + std::ostream & + operator<<(std::ostream & os, parenexprstatetype x) { + os << parenexprstatetype_descr(x); + return os; + } + + DParenSsm::DParenSsm() + : parenstate_(parenexprstatetype::lparen_0), + expr_{} + {} + + DParenSsm * + DParenSsm::make(DArena & mm) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DParenSsm)); + + return new (mem) DParenSsm(); + } + + void + DParenSsm::start(ParserStateMachine * p_psm) + { + DParenSsm * paren_ssm = DParenSsm::make(p_psm->parser_alloc()); + + auto ssm = with_facet::mkobj(paren_ssm); + + p_psm->push_ssm(ssm); + } + + syntaxstatetype + DParenSsm::ssm_type() const noexcept + { + return syntaxstatetype::paren; + } + + std::string_view + DParenSsm::get_expect_str() const noexcept + { + switch (this->parenstate_) { + case parenexprstatetype::invalid: + case parenexprstatetype::N: + break; + case parenexprstatetype::lparen_0: return "lparen_0"; + case parenexprstatetype::lparen_1: return "lparen_1"; + case parenexprstatetype::lparen_2: return "lparen_2"; + } + + return "???parenexprstatetype"; + } + + void + DParenSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (tk.tk_type()) { + case tokentype::tk_leftparen: + this->on_leftparen_token(tk, p_psm); + return; + // all the not-yet handled cases + case tokentype::tk_symbol: + case tokentype::tk_def: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_if: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + Super::on_token(tk, p_psm); + } + + void + DParenSsm::on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + Super::on_token(tk, p_psm); + } + +#ifdef OBSOLETE + void + paren_xs::start(parserstatemachine * p_psm) + { + p_psm->push_exprstate(paren_xs::make()); + expect_expr_xs::start(p_psm); + } + + bool + paren_xs::admits_rightparen() const { + switch (parenxs_type_) { + case parenexprstatetype::lparen_0: + /* unreachable */ + assert(false); + return false; + + case parenexprstatetype::lparen_1: + return true; + + case parenexprstatetype::invalid: + case parenexprstatetype::n_parenexprstatetype: + /* unreachable */ + assert(false); + return false; + } + + return false; + } + + bool + paren_xs::admits_f64() const { + switch (parenxs_type_) { + case parenexprstatetype::lparen_0: + return true; + + case parenexprstatetype::lparen_1: + return false; + + case parenexprstatetype::invalid: + case parenexprstatetype::n_parenexprstatetype: + /* unreachable */ + assert(false); + return false; + } + + return false; + } + + void + paren_xs::on_def_token(const token_type & tk, + parserstatemachine * /*p_psm*/) + { + constexpr const char * c_self_name = "paren_xs::on_def"; + + this->illegal_input_error(c_self_name, tk); + } + + void + paren_xs::on_symbol_token(const token_type & /*tk*/, + parserstatemachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + log && log(xtag("exstype", p_psm->top_exprstate().exs_type())); + + //constexpr const char * self_name = "paren_xs::on_symbol"; + + /* TODO: lparen_0: treat as variable reference */ + + assert(false); + } + + void + paren_xs::on_typedescr(TypeDescr /*td*/, + parserstatemachine * /*p_psm*/) + { + assert(false); + return; + } + + void + paren_xs::on_colon_token(const token_type & tk, + parserstatemachine * /*p_psm*/) + { + constexpr const char * c_self_name = "paren_xs::on_colon"; + + this->illegal_input_error(c_self_name, tk); + } + + void + paren_xs::on_semicolon_token(const token_type & tk, + parserstatemachine * /*p_psm*/) + { + constexpr const char * c_self_name = "paren_xs::on_semicolon"; + + this->illegal_input_error(c_self_name, tk); + } + + void + paren_xs::on_singleassign_token(const token_type & tk, + parserstatemachine * /*p_psm*/) + { + constexpr const char * c_self_name = "paren_xs::on_singleassign"; + + this->illegal_input_error(c_self_name, tk); + } + + void + paren_xs::on_leftparen_token(const token_type & tk, + parserstatemachine * /*p_psm*/) + { + constexpr const char * c_self_name = "paren_xs::on_leftparen"; + + this->illegal_input_error(c_self_name, tk); + } + + void + paren_xs::on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + constexpr const char * c_self_name = "paren_xs::on_rightparen"; + + if (!this->admits_rightparen()) + { + this->illegal_input_error(c_self_name, tk); + } + + if (this->parenxs_type_ == parenexprstatetype::lparen_1) { + rp expr = this->gen_expr_; + + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->top_exprstate().on_expr(expr, p_psm); + } + } + + void + paren_xs::on_i64_token(const token_type & tk, + parserstatemachine * /*p_psm*/) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + constexpr const char * c_self_name = "paren_xs::on_i64"; + + this->illegal_input_error(c_self_name, tk); + } + + void + paren_xs::on_f64_token(const token_type & tk, + parserstatemachine * /*p_psm*/) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + constexpr const char * c_self_name = "paren_xs::on_f64"; + + this->illegal_input_error(c_self_name, tk); + } + + void + paren_xs::on_expr(bp expr, + parserstatemachine * p_psm) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + log && log(xtag("exstype", this->exs_type_), + xtag("expr", expr)); + + switch (this->parenxs_type_) { + case parenexprstatetype::lparen_0: { + this->parenxs_type_ = parenexprstatetype::lparen_1; /* wants on_rightparen */ + progress_xs::start(expr.promote(), p_psm); + + return; + } + + case parenexprstatetype::lparen_1: { + this->gen_expr_ = expr.promote(); + + /* expect immediate incoming call, this time to on_rightparen() */ + return; + } + + default: + /* unreachable */ + assert(false); + return; + } + } /*on_expr*/ + + void + paren_xs::on_symbol(const std::string & /*symbol_name*/, + parserstatemachine * /*p_psm*/) + { + switch(this->parenxs_type_) { + case parenexprstatetype::lparen_0: + case parenexprstatetype::lparen_1: + /* NOT IMPLEMENTED */ + assert(false); + return; + + default: + /* unreachable */ + assert(false); + return; + } + } + + void + paren_xs::print(std::ostream & os) const { + os << ""; + } +#endif + + bool + DParenSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, + "DParenSsm", + refrtag("parenstate", parenstate_), + refrtag("expect", this->get_expect_str())); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DParenSsm.cpp */ diff --git a/src/reader2/IPrintable_DParenSsm.cpp b/src/reader2/IPrintable_DParenSsm.cpp new file mode 100644 index 00000000..b2228f7f --- /dev/null +++ b/src/reader2/IPrintable_DParenSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DParenSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DParenSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DParenSsm.json5] +**/ + +#include "ssm/IPrintable_DParenSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DParenSsm::pretty(const DParenSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DParenSsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp new file mode 100644 index 00000000..1bb2ea83 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp @@ -0,0 +1,69 @@ +/** @file ISyntaxStateMachine_DParenSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DParenSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DParenSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DParenSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DParenSsm::ssm_type(const DParenSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DParenSsm::get_expect_str(const DParenSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DParenSsm::on_token(DParenSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DParenSsm::on_parsed_symbol(DParenSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DParenSsm::on_parsed_typedescr(DParenSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DParenSsm::on_parsed_formal(DParenSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DParenSsm::on_parsed_formal_arglist(DParenSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DParenSsm::on_parsed_expression(DParenSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DParenSsm::on_parsed_expression_with_token(DParenSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DParenSsm.cpp */ diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index ef584c44..3955fae3 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -19,6 +19,8 @@ #include +#include "ParenSsm.hpp" + #include #include @@ -85,6 +87,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + log && log(xtag("DExprSeqState.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); log && log(xtag("DLambdaSsm.tseq", typeseq::id())); @@ -95,6 +100,7 @@ namespace xo { log && log(xtag("DExpectTypeSsm.tseq", typeseq::id())); log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); log && log(xtag("DProgressSsm.tseq", typeseq::id())); + log && log(xtag("DParenSsm.tseq", typeseq::id())); log && log(xtag("ASyntaxStateMachine.tseq", typeseq::id())); return true; diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index aff0a87c..18acb000 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -23,6 +23,8 @@ namespace xo { return "sequence"; case syntaxstatetype::progress: return "progress"; + case syntaxstatetype::paren: + return "paren"; case syntaxstatetype::expect_toplevel_expression_sequence: return "expect-toplevel-expression-sequence"; case syntaxstatetype::expect_formal_arglist: diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 740d71f4..870cabd1 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -836,7 +836,7 @@ namespace xo { TEST_CASE("SchematikaParser-interactive-lambda2", "[reader2][SchematikaParser]") { - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag)); ArenaConfig config; @@ -1014,6 +1014,175 @@ namespace xo { } } + + TEST_CASE("SchematikaParser-interactive-apply", "[reader2][SchematikaParser]") + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * (lambda (x : i64) { x * x })(13); + * + **/ + + { + auto & result = parser.on_token(Token::leftparen_token()); + + log && log("after lparen token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::lambda_token()); + + log && log("after lambda token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::leftparen_token()); + + log && log("after lparen token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("x")); + + log && log("after symbol(x) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::colon_token()); + + log && log("after colon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("i64")); + + log && log("after symbol(i64) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::rightparen_token()); + + log && log("after rightparen token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::leftbrace_token()); + + log && log("after leftbrace token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("x")); + + log && log("after symbol(x) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::star_token()); + + log && log("after star(*) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::symbol_token("x")); + + log && log("after symbol(x) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::rightbrace_token()); + + log && log("after rightbrace(}) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + } + + } } /*namespace ut*/ } /*namespace xo*/ From 4744139d748f7720a8337c78964c010048a6d481 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 10 Feb 2026 23:28:20 -0500 Subject: [PATCH 192/342] xo-reader2 stack: progress towards recognizing function calls [WIP] --- include/xo/reader2/DExpectExprSsm.hpp | 4 +- include/xo/reader2/DParenSsm.hpp | 12 ++++ include/xo/reader2/DProgressSsm.hpp | 39 ++++++----- include/xo/reader2/ProgressSsm.hpp | 12 ++++ src/reader2/DExprSeqState.cpp | 10 ++- src/reader2/DParenSsm.cpp | 67 +++++++++++++++++-- src/reader2/DProgressSsm.cpp | 95 ++++++++++++++++++++++++--- src/reader2/ParserStateMachine.cpp | 4 +- utest/SchematikaParser.test.cpp | 28 +++++++- 9 files changed, 234 insertions(+), 37 deletions(-) create mode 100644 include/xo/reader2/ProgressSsm.hpp diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index d6558c1e..473a89d3 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -27,11 +27,11 @@ namespace xo { static DExpectExprSsm * make(DArena & parser_mm, bool allow_defs, - bool cxl_on_rightparen); + bool cxl_on_rightbrace); static void start(DArena & parser_mm, bool allow_defs, - bool cxl_on_rightparen, + bool cxl_on_rightbrace, ParserStateMachine * p_psm); static void start(ParserStateMachine * p_psm); diff --git a/include/xo/reader2/DParenSsm.hpp b/include/xo/reader2/DParenSsm.hpp index 2ed7f58c..6f359b65 100644 --- a/include/xo/reader2/DParenSsm.hpp +++ b/include/xo/reader2/DParenSsm.hpp @@ -87,6 +87,12 @@ namespace xo { void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); + /** update ssm state for incoming rightparen token @p tk + * with overall parser state in @p p_psm + **/ + void on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-parenssm-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -101,6 +107,12 @@ namespace xo { void on_token(const Token & tk, ParserStateMachine * p_psm); + /** update ssm for expression @p expr (emitted by nested ssm), + * with overall parser state in @p p_psm + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-parenssm-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 3b9dff6f..47ca29b9 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -100,6 +100,8 @@ namespace xo { obj lhs, optype op); + static void start(DArena & parser_mm, + ParserStateMachine * p_psm); static void start(DArena & parser_mm, obj lhs, ParserStateMachine * p_psm); @@ -132,21 +134,9 @@ namespace xo { /** @defgroup scm-progressssm-methods general methods **/ ///@{ - /** token belongs to surrounding syntax, - * -> lock in current progress - **/ - void on_completing_token(const Token & tk, - ParserStateMachine * p_psm); - - ///@} - /** @defgroup scm-progressssm-ssm-facet syntaxstatemachine facet methods **/ - /// @{ - - /** operate state machine for this syntax on incoming token @p tk - * with overall parser state in @p p_psm - **/ - void on_token(const Token & tk, - ParserStateMachine * p_psm); + /** handle leftparen token @p tk. Overall parser state in @p p_psm **/ + void on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm); void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); @@ -168,6 +158,25 @@ namespace xo { ParserStateMachine * p_psm); void on_rightbrace_token(const Token & tk, ParserStateMachine * p_psm); + + /** token belongs to surrounding syntax, + * -> lock in current progress + **/ + void on_completing_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-progressssm-ssm-facet syntaxstatemachine facet methods **/ + /// @{ + + /** operate state machine for this syntax on incoming token @p tk + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); void on_parsed_expression_with_token(obj expr, const Token & tk, ParserStateMachine * p_psm); diff --git a/include/xo/reader2/ProgressSsm.hpp b/include/xo/reader2/ProgressSsm.hpp new file mode 100644 index 00000000..150c60d9 --- /dev/null +++ b/include/xo/reader2/ProgressSsm.hpp @@ -0,0 +1,12 @@ +/** @file ProgressSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DProgressSsm.hpp" +#include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" +#include "ssm/IPrintable_DProgressSsm.hpp" + +/* end ProgressSsm.hpp */ diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 82eb2f44..1d9b38a3 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -7,7 +7,7 @@ #include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" #include "DDefineSsm.hpp" #include "DLambdaSsm.hpp" -#include "DProgressSsm.hpp" +#include "ProgressSsm.hpp" #include "DIfElseSsm.hpp" #include "ParenSsm.hpp" #include "ExpectExprSsm.hpp" @@ -400,7 +400,13 @@ namespace xo { { switch (seqtype_) { case exprseqtype::toplevel_interactive: { - DParenSsm::start(p_psm); + // not sufficient to just start a paren-ssm here. + // we want to parse toplevel input like + // (getfunction())(); + // just as C would. + // To wait for token following right paren, use a progress-ssm + + DProgressSsm::start(p_psm->parser_alloc(), p_psm); p_psm->on_token(Token::leftparen_token()); return; diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index 166e96bf..972d503a 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -4,6 +4,7 @@ **/ #include "ParenSsm.hpp" +#include "ExpectExprSsm.hpp" #include "syntaxstatetype.hpp" #include @@ -70,9 +71,9 @@ namespace xo { case parenexprstatetype::invalid: case parenexprstatetype::N: break; - case parenexprstatetype::lparen_0: return "lparen_0"; - case parenexprstatetype::lparen_1: return "lparen_1"; - case parenexprstatetype::lparen_2: return "lparen_2"; + case parenexprstatetype::lparen_0: return "leftparen"; + case parenexprstatetype::lparen_1: return "expression"; + case parenexprstatetype::lparen_2: return "rightparen"; } return "???parenexprstatetype"; @@ -83,9 +84,15 @@ namespace xo { ParserStateMachine * p_psm) { switch (tk.tk_type()) { + case tokentype::tk_leftparen: this->on_leftparen_token(tk, p_psm); return; + + case tokentype::tk_rightparen: + this->on_rightparen_token(tk, p_psm); + return; + // all the not-yet handled cases case tokentype::tk_symbol: case tokentype::tk_def: @@ -98,7 +105,6 @@ namespace xo { case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_if: - case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: @@ -136,6 +142,25 @@ namespace xo { DParenSsm::on_leftparen_token(const Token & tk, ParserStateMachine * p_psm) { + if (parenstate_ == parenexprstatetype::lparen_0) { + this->parenstate_ = parenexprstatetype::lparen_1; + + /** 1. allow_defs=false not allowing definitions immediately + * within a parenthesized expression. + * e.g. + * (def y : i64 = 4; x + y) // nope + * 2. cxl_on_rightparen=false expression _must_ be followed + * by rightparen. empty parentheses '()' + * do not denote anything, in expression context + **/ + DExpectExprSsm::start(p_psm->parser_alloc(), + false /*!allow_defs*/, + false /*cx_on_rightbrace*/, + p_psm); + + return; + } + Super::on_token(tk, p_psm); } @@ -255,7 +280,24 @@ namespace xo { this->illegal_input_error(c_self_name, tk); } +#endif + void + DParenSsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (this->parenstate_ == parenexprstatetype::lparen_2) { + // parenthesized expression successfully parsed + + p_psm->pop_ssm(); + p_psm->on_parsed_expression(this->expr_); + return; + } + + Super::on_token(tk, p_psm); + } + +#ifdef NOT_YET void paren_xs::on_rightparen_token(const token_type & tk, parserstatemachine * p_psm) @@ -302,7 +344,24 @@ namespace xo { this->illegal_input_error(c_self_name, tk); } +#endif + void + DParenSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + if (parenstate_ == parenexprstatetype::lparen_1) { + this->parenstate_ = parenexprstatetype::lparen_2; + this->expr_ = expr; + + return; + } + + Super::on_parsed_expression(expr, p_psm); + + } + +#ifdef NOT_YET void paren_xs::on_expr(bp expr, parserstatemachine * p_psm) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 751264dd..d774c269 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -9,6 +9,8 @@ #include "DExpectExprSsm.hpp" #include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" +#include "ParenSsm.hpp" + #include #include @@ -185,6 +187,13 @@ namespace xo { start(parser_mm, lhs, optype::invalid, p_psm); } + void + DProgressSsm::start(DArena & parser_mm, + ParserStateMachine * p_psm) + { + start(parser_mm, obj(), p_psm); + } + DProgressSsm::DProgressSsm(obj valex, optype op) : lhs_{valex}, @@ -204,10 +213,12 @@ namespace xo { std::string_view DProgressSsm::get_expect_str() const noexcept { - if (op_type_ == optype::invalid) { + if (!lhs_) { + return "expr1|leftparen"; + } else if (op_type_ == optype::invalid) { return "oper|semicolon|rightparen|righbrace"; } else { - return "expr|leftparen"; + return "expr2|leftparen"; } } @@ -259,11 +270,14 @@ namespace xo { this->on_rightbrace_token(tk, p_psm); return; + case tokentype::tk_leftparen: + this->on_leftparen_token(tk, p_psm); + return; + // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_def: case tokentype::tk_if: - case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: @@ -483,13 +497,48 @@ namespace xo { p_psm->on_parsed_expression_with_token(expr, tk); } + void + DProgressSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + const bool c_debug_flag = p_psm->debug_flag() || true; + + scope log(XO_DEBUG(c_debug_flag)); + + if (!lhs_) { + log && log("accepting expr1"); + + this->lhs_ = expr; + return; + } + + Super::on_parsed_expression(expr, p_psm); + } + void DProgressSsm::on_parsed_expression_with_token(obj expr, const Token & tk, ParserStateMachine * p_psm) { - scope log(XO_DEBUG(p_psm->debug_flag()), - xtag("expr", expr)); + const bool c_debug_flag = p_psm->debug_flag() || true; + + scope log(XO_DEBUG(c_debug_flag), + xtag("expr", expr), + xtag("tk", tk)); + +#ifdef NOT_YET + if (!lhs_) { + log && log("DProgressSsm: accepting expr1"); + + this->lhs_ = expr; + + // now we have to handle tk! + + return; + } +#endif + + // here: have lhs_ expression if (op_type_ == optype::invalid) { // e.g. control here on input like @@ -499,6 +548,7 @@ namespace xo { ("DProgressSsm::on_parsed_expression_with_token", expr, this->get_expect_str()); + return; } @@ -847,7 +897,32 @@ namespace xo { { this->on_operator_token(tk, p_psm); } +#endif + void + DProgressSsm::on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (!lhs_) { + // leftparen begins possible lhs expression + DParenSsm::start(p_psm); + + p_psm->on_token(Token::leftparen_token()); + return; + } + + if (optype_ == optype::invalid) { + // leftparen begins function call arguments. + // .lhs_ now understood to be expression that evaluates to a + // function + + + } + + Super::on_token(tk, p_psm); + } + +#ifdef NOT_YET /* editor bait: on_lparen */ void progress_xs::on_leftparen_token(const token_type & tk, @@ -885,8 +960,8 @@ namespace xo { return; } - constexpr const char * c_self_name = "exprstate::on_leftparen"; const char * exp = get_expect_str(); + constexpr const char * c_self_name = "exprstate::on_leftparen"; this->illegal_input_on_token(c_self_name, tk, exp, p_psm); } @@ -1023,18 +1098,20 @@ namespace xo { log && log(xtag("rhs_.tseq", rhs_._typeseq())); obj lhs - = FacetRegistry::instance().variant(lhs_); + = FacetRegistry::instance().try_variant(lhs_); obj rhs = FacetRegistry::instance().try_variant(rhs_); + bool lhs_present = lhs; bool rhs_present = rhs; + bool op_present = (op_type_ != optype::invalid); return ppii.pps()->pretty_struct (ppii, "DProgressSsm", - refrtag("lhs", lhs), - refrtag("op", op_type_), + refrtag("lhs", lhs, lhs_present), + refrtag("op", op_type_, op_present), refrtag("rhs", rhs, rhs_present), refrtag("expect", this->get_expect_str()) ); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 56a4560c..58119789 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -426,8 +426,8 @@ namespace xo { // - want to write error message using DArena // - need something like log_streambuf and/or tostr() that's arena-aware - obj expr_pr - = FacetRegistry::instance().variant(expr); + auto expr_pr = expr.to_facet(); + //= FacetRegistry::instance().variant(expr); assert(expr_pr); /** TODO diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 870cabd1..77d9471c 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1176,12 +1176,34 @@ namespace xo { log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(parser.has_incomplete_expr() == true); REQUIRE(!result.is_error()); - REQUIRE(result.is_expression()); - REQUIRE(result.result_expr()); + REQUIRE(result.is_incomplete()); } + { + auto & result = parser.on_token(Token::rightparen_token()); + + log && log("after rightparen token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::leftparen_token()); + + log && log("after leftparen token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } } } /*namespace ut*/ } /*namespace xo*/ From 40e1fb531db11c2f43362041ae0d071df633b3a4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Feb 2026 16:02:41 -0500 Subject: [PATCH 193/342] xo-reader2: DApplySsm for apply expressions [WIP] --- include/xo/reader2/DApplySsm.hpp | 165 ++++++++++++++++++ include/xo/reader2/DDefineSsm.hpp | 4 +- include/xo/reader2/syntaxstatetype.hpp | 5 +- src/reader2/CMakeLists.txt | 4 + src/reader2/DApplySsm.cpp | 221 +++++++++++++++++++++++++ src/reader2/DProgressSsm.cpp | 7 +- src/reader2/syntaxstatetype.cpp | 2 + 7 files changed, 402 insertions(+), 6 deletions(-) create mode 100644 include/xo/reader2/DApplySsm.hpp create mode 100644 src/reader2/DApplySsm.cpp diff --git a/include/xo/reader2/DApplySsm.hpp b/include/xo/reader2/DApplySsm.hpp new file mode 100644 index 00000000..34c78f78 --- /dev/null +++ b/include/xo/reader2/DApplySsm.hpp @@ -0,0 +1,165 @@ +/** @file DApplySsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include +//#include +#include + + +namespace xo { + namespace scm { + /** + * fn ( arg1 , arg2 , .. , argn ) + * ^ ^ ^ ^ ^ ^ ^ ^ ^ + * | | | | | | | | (done) + * | | | | | | | apply_3 + * | | | | | | apply_2:expect_rhs_expression + * | | | | | apply_3 + * | | | | apply_2:expect_rhs_expression + * | | | apply_3 + * | | apply_2:expect_rhs_expression + * | apply_1 + * apply_0:expect_rhs_expression + * + * apply_0 --on_expr()--> apply_1 + * apply_1 --on_leftparen()--> apply_2 + * apply_2 --on_expr()--> apply_3 + * apply_3 --on_comma()--> apply_2 + * --on_rightparen()-> (done) + * + * apply_0: start + * apply_1: leftparen following expr allows parser to recognize apply + * apply_2: expect next argument + * apply_3: got argument, expect comma or rightparen to continue + * (done): apply complete, pop exprstate from stack + * + * In practice will start in state apply_1 + **/ + enum class applyexprstatetype { + invalid = -1, + + apply_0, + apply_1, + apply_2, + apply_3, + + N + }; + + extern const char * applyexprstatetype_descr(applyexprstatetype x); + + std::ostream & + operator<<(std::ostream & os, applyexprstatetype x); + + /** @class DApplySsm + * @brief state machine for parsing a schematika function-call-expression + **/ + class DApplySsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using TypeDescr = xo::reflect::TypeDescr; + using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; + + //using Apply = xo::scm::Apply; + + public: + /** @defgroup scm-applyssm-ctors constructors **/ + ///@{ + + /** construct apply ssm with @p fn_expr + * supplying function to be invoked. + * + * Expect during parsing of input like f(...) + * that we parse f before parser knows that it will be + * followed by leftparen + **/ + explicit DApplySsm(obj fn_expr); + + /** create instance using memory from @p parser_mm. + * with function to be called supplied by @p fn_expr. + **/ + static DApplySsm * make(DArena & parser_mm, + obj fn_expr); + +#ifdef NOT_YET + /** + * Start apply. Will trigger this after input like + * "fn(" + * + * apply_xs remains on expr stack until closing right paren + * fn(arg1-expr, arg2-expr, ...) + * + * @p fnex expression in function position + * @p p_psm parser state machine + **/ + static void start(rp fnex, + parserstatemachine * p_psm); +#endif + + ///@} + /** @defgroup scm-applyssm-access methods **/ + ///@{ + + /** identify this nested state machine **/ + static const char * ssm_classname() { return "DApplySsm"; } + + /** current internal state **/ + applyexprstatetype applystate() const noexcept { return applystate_; } + + ///@} + /** @defgroup ssm-applyssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** mnemonic for expected remaining syntax for current parsing state **/ + std::string_view get_expect_str() const noexcept; + +#ifdef NOT_YET + + virtual void on_expr(bp expr, + parserstatemachine * p_psm) override; + + virtual void on_comma_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_leftparen_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) override; + + virtual void print(std::ostream & os) const override; + virtual bool pretty_print(const print::ppindentinfo & ppii) const final override; + + private: + static std::unique_ptr make(); +#endif + + private: + /** current state of parser for this apply expression **/ + applyexprstatetype applystate_ = applyexprstatetype::apply_0; + /** evaluates to function to be invoked **/ + obj fn_expr_; +#ifdef NOT_YET + /** evaluates to the arguments to pass to @ref fn_ **/ + std::vector> args_expr_v_; +#endif + }; + } /*namespace scm */ + + namespace print { +#ifndef ppdetail_atomic + PPDETAIL_ATOMIC(xo::scm::applyexprstatetype); +#endif + } +} /*namespace xo*/ + +/* end DApplySsm.hpp */ diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index f71477dd..d42246ef 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -78,7 +78,7 @@ namespace xo { using ppindentinfo = xo::print::ppindentinfo; public: - /** @defgroup scm-define-ssm-facet constructors **/ + /** @defgroup scm-definessm-ctors constructors **/ ///@{ /** constructor; using @p def_expr for initial expression scaffold **/ @@ -110,7 +110,7 @@ namespace xo { defexprstatetype defstate() const noexcept { return defstate_; } ///@} - /** @defgroup scm-define-ssm-facet syntaxstatemachine facet methods **/ + /** @defgroup scm-definessm-facet syntaxstatemachine facet methods **/ ///@{ /** identifies the ssm implemented here **/ diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 3031a444..147b7770 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -27,9 +27,12 @@ namespace xo { /** handle ifelse-expression. See @ref DIfElseSsm **/ ifelseexpr, - /** handle sequence-expression. See @ref DSequenceSsm **/ + /** handle sequence-expression syntax. See @ref DSequenceSsm **/ sequence, + /** handle apply-expression syntax. See @ref DApplySsm **/ + apply, + /** rhs expression. state exists to achieve 1-token lookahead **/ progress, diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 4a813900..b6d9bed0 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -37,6 +37,10 @@ set(SELF_SRCS ISyntaxStateMachine_DLambdaSsm.cpp IPrintable_DLambdaSsm.cpp + DApplySsm.cpp + # ISyntaxStateMachine_DApplySsm.cpp + # IPrintable_DApplySsm.cpp + DParenSsm.cpp ISyntaxStateMachine_DParenSsm.cpp IPrintable_DParenSsm.cpp diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp new file mode 100644 index 00000000..f58ce7d4 --- /dev/null +++ b/src/reader2/DApplySsm.cpp @@ -0,0 +1,221 @@ +/** @file DApplySsm.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "DApplySsm.hpp" +#include + +//#include "parserstatemachine.hpp" +//#include "expect_expr_xs.hpp" + +namespace xo { + using xo::reflect::typeseq; + + namespace scm { + + // ----- applyexprstatetype ----- + + const char * + applyexprstatetype_descr(applyexprstatetype x) { + switch (x) { + case applyexprstatetype::invalid: return "invalid"; + case applyexprstatetype::apply_0: return "apply_0"; + case applyexprstatetype::apply_1: return "apply_1"; + case applyexprstatetype::apply_2: return "apply_2"; + case applyexprstatetype::apply_3: return "apply_3"; + case applyexprstatetype::N: break; + } + + return "???applyexprstatetype"; + } + + std::ostream & + operator<<(std::ostream & os, applyexprstatetype x) { + os << applyexprstatetype_descr(x); + return os; + } + + // ----- DApplySsm ----- + + DApplySsm::DApplySsm(obj fn_expr) + : applystate_{applyexprstatetype::apply_0}, + fn_expr_{fn_expr} + { + if (fn_expr) { + this->applystate_ = applyexprstatetype::apply_1; + } + } + + DApplySsm * + DApplySsm::make(DArena & mm, + obj fn_expr) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DApplySsm)); + + // TODO: revisit if we use flexible array for + // arguments + + return new (mem) DApplySsm(fn_expr); + } + +#ifdef NOT_YET + void + apply_xs::start(rp fn_expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + p_psm->push_exprstate(apply_xs::make()); + p_psm->top_exprstate().on_expr(fn_expr.get(), p_psm); + p_psm->top_exprstate().on_leftparen_token(token_type::leftparen(), p_psm); + } +#endif + + syntaxstatetype + DApplySsm::ssm_type() const noexcept { + return syntaxstatetype::apply; + } + + + std::string_view + DApplySsm::get_expect_str() const noexcept + { + switch(applystate_) { + case applyexprstatetype::invalid: return "invalid"; + case applyexprstatetype::apply_0: return "expr"; + case applyexprstatetype::apply_1: return "lparen"; + case applyexprstatetype::apply_2: return "expr"; + case applyexprstatetype::apply_3: return "comma|rparen"; + case applyexprstatetype::N: break; + } + + return "?expect"; + } + +#ifdef NOT_YET + void + apply_xs::on_expr(bp expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + switch (applyxs_type_) { + case applyexprstatetype::invalid: + case applyexprstatetype::n_applyexprstatetype: + // unreachable + break; + case applyexprstatetype::apply_0: + log && log("stash fn -> new state apply_1"); + this->fn_expr_ = expr.promote(); + this->applyxs_type_ = applyexprstatetype::apply_1; + return; + case applyexprstatetype::apply_1: + log && log("error: was expecting lparen"); + // error, expecting lparen + break; + case applyexprstatetype::apply_2: + log && log(xtag("expr", expr), xtag("do", "stash expr -> new state apply_3")); + this->args_expr_v_.push_back(expr.promote()); + this->applyxs_type_ = applyexprstatetype::apply_3; + return; + case applyexprstatetype::apply_3: + // error, expecting comma|rparen + break; + } + + /* control here --implies-> error state */ + + constexpr const char * c_self_name = "apply_xs::on_expr"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_expr(c_self_name, expr, exp, p_psm); + } + + void + apply_xs::on_comma_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + if (this->applyxs_type_ == applyexprstatetype::apply_3) { + this->applyxs_type_ = applyexprstatetype::apply_2; + expect_expr_xs::start(p_psm); + } else { + constexpr const char * c_self_name = "apply_xs::on_comma_token"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + } + + void + apply_xs::on_leftparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("applyxs_type", applyxs_type_); + + if (this->applyxs_type_ == applyexprstatetype::apply_1) { + this->applyxs_type_ = applyexprstatetype::apply_2; + expect_expr_xs::start(p_psm); + } else { + constexpr const char * c_self_name = "apply_xs::on_leftparen_token"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + } + + void + apply_xs::on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("applyxs_type", applyxs_type_); + + if (this->applyxs_type_ == applyexprstatetype::apply_3) { + /* (done) state */ + log("apply complete -> pop + send expr"); + + rp apply_expr = Apply::make(this->fn_expr_, this->args_expr_v_); + + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->top_exprstate().on_expr(apply_expr, p_psm); + return; + } + + constexpr const char * c_self_name = "apply_xs::on_rightparen_token"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + + void + apply_xs::print(std::ostream & os) const + { + os << ""; + } + + bool + apply_xs::pretty_print(const xo::print::ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, "apply_xs", + refrtag("applyxs_type", applyxs_type_), + refrtag("fn_expr", fn_expr_), + refrtag("args_expr_v", args_expr_v_)); + } + +#endif + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end DApplySsm.cpp */ diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index d774c269..0a28fd60 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -538,7 +538,7 @@ namespace xo { } #endif - // here: have lhs_ expression + // here: have lhs_ expression if (op_type_ == optype::invalid) { // e.g. control here on input like @@ -911,12 +911,13 @@ namespace xo { return; } - if (optype_ == optype::invalid) { + if (op_type_ == optype::invalid) { // leftparen begins function call arguments. // .lhs_ now understood to be expression that evaluates to a // function - + + } Super::on_token(tk, p_psm); diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index 18acb000..01ab1005 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -21,6 +21,8 @@ namespace xo { return "ifelseexpr"; case syntaxstatetype::sequence: return "sequence"; + case syntaxstatetype::apply: + return "apply"; case syntaxstatetype::progress: return "progress"; case syntaxstatetype::paren: From 65d1fd840b9609818aca609c56d54bad32019a5b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Feb 2026 18:07:55 -0500 Subject: [PATCH 194/342] xo-reader2: progress+apply works up to lparen introducing formals --- CMakeLists.txt | 26 +++++++ idl/IPrintable_DApplySsm.json5 | 13 ++++ idl/ISyntaxStateMachine_DApplySsm.json5 | 13 ++++ include/xo/reader2/ApplySsm.hpp | 12 +++ include/xo/reader2/DApplySsm.hpp | 18 ++++- include/xo/reader2/SequenceSsm.hpp | 13 ++++ .../xo/reader2/ssm/IPrintable_DApplySsm.hpp | 62 +++++++++++++++ .../ssm/ISyntaxStateMachine_DApplySsm.hpp | 77 +++++++++++++++++++ src/reader2/CMakeLists.txt | 4 +- src/reader2/DApplySsm.cpp | 36 +++++++-- src/reader2/DProgressSsm.cpp | 42 +++++++--- src/reader2/IPrintable_DApplySsm.cpp | 28 +++++++ src/reader2/ISyntaxStateMachine_DApplySsm.cpp | 69 +++++++++++++++++ src/reader2/reader2_register_facets.cpp | 7 +- 14 files changed, 393 insertions(+), 27 deletions(-) create mode 100644 idl/IPrintable_DApplySsm.json5 create mode 100644 idl/ISyntaxStateMachine_DApplySsm.json5 create mode 100644 include/xo/reader2/ApplySsm.hpp create mode 100644 include/xo/reader2/SequenceSsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DApplySsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp create mode 100644 src/reader2/IPrintable_DApplySsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DApplySsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d1e807e6..7bfc86f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -244,6 +244,32 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-applyssm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ApplySsm + INPUT idl/ISyntaxStateMachine_DApplySsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-applyssm + FACET_PKG xo_printable2 + FACET Printable + REPR ApplySsm + INPUT idl/IPrintable_DApplySsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectsymbolssm diff --git a/idl/IPrintable_DApplySsm.json5 b/idl/IPrintable_DApplySsm.json5 new file mode 100644 index 00000000..cdcd32ca --- /dev/null +++ b/idl/IPrintable_DApplySsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DApplySsm", + using_doxygen: true, + repr: "DApplySsm", + doc: [ "implement APrintable for DApplySsm" ], +} diff --git a/idl/ISyntaxStateMachine_DApplySsm.json5 b/idl/ISyntaxStateMachine_DApplySsm.json5 new file mode 100644 index 00000000..7806d2cb --- /dev/null +++ b/idl/ISyntaxStateMachine_DApplySsm.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DApplySsm", + using_doxygen: true, + repr: "DApplySsm", + doc: [ "implement ASyntaxStateMachine for DApplySsm" ], +} diff --git a/include/xo/reader2/ApplySsm.hpp b/include/xo/reader2/ApplySsm.hpp new file mode 100644 index 00000000..6e9f9a9d --- /dev/null +++ b/include/xo/reader2/ApplySsm.hpp @@ -0,0 +1,12 @@ +/** @file ApplySsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DApplySsm.hpp" +#include "ssm/ISyntaxStateMachine_DApplySsm.hpp" +#include "ssm/IPrintable_DApplySsm.hpp" + +/* end ApplySsm.hpp */ diff --git a/include/xo/reader2/DApplySsm.hpp b/include/xo/reader2/DApplySsm.hpp index 34c78f78..46f9097b 100644 --- a/include/xo/reader2/DApplySsm.hpp +++ b/include/xo/reader2/DApplySsm.hpp @@ -89,10 +89,11 @@ namespace xo { static DApplySsm * make(DArena & parser_mm, obj fn_expr); -#ifdef NOT_YET /** * Start apply. Will trigger this after input like * "fn(" + * or + * "makefn()()" * * apply_xs remains on expr stack until closing right paren * fn(arg1-expr, arg2-expr, ...) @@ -100,9 +101,8 @@ namespace xo { * @p fnex expression in function position * @p p_psm parser state machine **/ - static void start(rp fnex, - parserstatemachine * p_psm); -#endif + static void start(obj fnex, + ParserStateMachine * p_psm); ///@} /** @defgroup scm-applyssm-access methods **/ @@ -124,6 +124,8 @@ namespace xo { /** mnemonic for expected remaining syntax for current parsing state **/ std::string_view get_expect_str() const noexcept; + ///@} + #ifdef NOT_YET virtual void on_expr(bp expr, @@ -143,6 +145,14 @@ namespace xo { static std::unique_ptr make(); #endif + /** @defgroup ssm-applyssm-printable-facet printable facet **/ + ///@{ + + /** pretty-printing support **/ + bool pretty(const ppindentinfo & ppii) const; + + ///@} + private: /** current state of parser for this apply expression **/ applyexprstatetype applystate_ = applyexprstatetype::apply_0; diff --git a/include/xo/reader2/SequenceSsm.hpp b/include/xo/reader2/SequenceSsm.hpp new file mode 100644 index 00000000..0e82e081 --- /dev/null +++ b/include/xo/reader2/SequenceSsm.hpp @@ -0,0 +1,13 @@ +/** @file SequenceSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DSequenceSsm.hpp" +#include "ssm/ISyntaxStateMachine_DSequenceSsm.hpp" +#include "ssm/IPrintable_DSequenceSsm.hpp" + +/* end SequenceSsm.hpp */ + diff --git a/include/xo/reader2/ssm/IPrintable_DApplySsm.hpp b/include/xo/reader2/ssm/IPrintable_DApplySsm.hpp new file mode 100644 index 00000000..3bae71f2 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DApplySsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DApplySsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DApplySsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DApplySsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DApplySsm.hpp" + +namespace xo { namespace scm { class IPrintable_DApplySsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DApplySsm + **/ + class IPrintable_DApplySsm { + public: + /** @defgroup scm-printable-dapplyssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dapplyssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DApplySsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp new file mode 100644 index 00000000..d6b1a53e --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp @@ -0,0 +1,77 @@ +/** @file ISyntaxStateMachine_DApplySsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DApplySsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DApplySsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DApplySsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DApplySsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DApplySsm + **/ + class ISyntaxStateMachine_DApplySsm { + public: + /** @defgroup scm-syntaxstatemachine-dapplyssm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dapplyssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DApplySsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DApplySsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DApplySsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DApplySsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DApplySsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DApplySsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DApplySsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DApplySsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DApplySsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index b6d9bed0..5c98e209 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -38,8 +38,8 @@ set(SELF_SRCS IPrintable_DLambdaSsm.cpp DApplySsm.cpp - # ISyntaxStateMachine_DApplySsm.cpp - # IPrintable_DApplySsm.cpp + ISyntaxStateMachine_DApplySsm.cpp + IPrintable_DApplySsm.cpp DParenSsm.cpp ISyntaxStateMachine_DParenSsm.cpp diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index f58ce7d4..217c60b2 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -3,13 +3,14 @@ * @author Roland Conybeare, Feb 2026 **/ -#include "DApplySsm.hpp" +#include "ApplySsm.hpp" #include //#include "parserstatemachine.hpp" //#include "expect_expr_xs.hpp" namespace xo { + using xo::print::APrintable; using xo::reflect::typeseq; namespace scm { @@ -60,18 +61,21 @@ namespace xo { return new (mem) DApplySsm(fn_expr); } -#ifdef NOT_YET void - apply_xs::start(rp fn_expr, - parserstatemachine * p_psm) + DApplySsm::start(obj fn_expr, + ParserStateMachine * p_psm) { scope log(XO_DEBUG(p_psm->debug_flag())); - p_psm->push_exprstate(apply_xs::make()); - p_psm->top_exprstate().on_expr(fn_expr.get(), p_psm); - p_psm->top_exprstate().on_leftparen_token(token_type::leftparen(), p_psm); + DApplySsm * apply_ssm + = DApplySsm::make(p_psm->parser_alloc(), fn_expr); + + obj ssm(apply_ssm); + + p_psm->push_ssm(ssm); + //OBSOLETE //p_psm->top_exprstate().on_expr(fn_expr.get(), p_psm); + //OBSOLETE //p_psm->on_token(token_type::leftparen(), p_psm); } -#endif syntaxstatetype DApplySsm::ssm_type() const noexcept { @@ -194,7 +198,23 @@ namespace xo { this->illegal_input_on_token(c_self_name, tk, exp, p_psm); } +#endif + bool + DApplySsm::pretty(const ppindentinfo & ppii) const + { + // TODO: const-correct version of obj<> template + auto fn_expr = const_cast(this)->fn_expr_.to_facet(); + bool fn_expr_present(fn_expr); + + return ppii.pps()->pretty_struct(ppii, + "DApplySsm", + refrtag("applystate", applystate_), + refrtag("expect", this->get_expect_str()), + refrtag("fn_expr", fn_expr, fn_expr_present)); + } + +#ifdef NOT_YET void apply_xs::print(std::ostream & os) const { diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 0a28fd60..19d318f6 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -9,6 +9,7 @@ #include "DExpectExprSsm.hpp" #include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" +#include "ApplySsm.hpp" #include "ParenSsm.hpp" #include @@ -20,21 +21,13 @@ #include // for xo::scm::Primitives #include -#ifdef NOT_YET -#include "DApplySsm.hpp" -#include "ssm/ISyntaxStateMachine_DApplySsm.hpp" -#endif - #include #include #include #include #ifdef NOT_YET -#include "apply_xs.hpp" -#include "exprstatestack.hpp" #include "expect_expr_xs.hpp" -#include "parserstatemachine.hpp" #include "pretty_exprstatestack.hpp" #include "xo/expression/AssignExpr.hpp" #include "xo/expression/Apply.hpp" @@ -912,12 +905,39 @@ namespace xo { } if (op_type_ == optype::invalid) { - // leftparen begins function call arguments. - // .lhs_ now understood to be expression that evaluates to a - // function + // input: + /// <--- F1 ---> + // (..........)(.. ).. + // <------ A1 -----> + // <------- X1 ------> + // + // F1: expression evaluating to a function, + // parsed as fn_expr + // A1: expression parsed as a function call (i.e. apply-expression) + // X1: operator expression starting with A1 + // + // before: + // [0] ProgressSsm responsible for input beginning with F1 + // .lhs = fn_expr, .op_type empty, .rhs empty + // + // after: + // [0] ApplySsm responsible for function call A1 + // .fn_expr = fn_expr + // [1] ProgressSsm responsible for operator expression X1 + // .lhs empty, .op_type empty, .rhs empty + // + // Remarks: + // 1. keep ProgressSsm on the stack in case input continues like: + // fn_expr(args..) + .. + // i.e. to allow for infix operator following apply + // + obj fn_expr(this->lhs_); + this->lhs_ = obj(); + DApplySsm::start(fn_expr, p_psm); + return; } Super::on_token(tk, p_psm); diff --git a/src/reader2/IPrintable_DApplySsm.cpp b/src/reader2/IPrintable_DApplySsm.cpp new file mode 100644 index 00000000..5066b082 --- /dev/null +++ b/src/reader2/IPrintable_DApplySsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DApplySsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DApplySsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DApplySsm.json5] +**/ + +#include "ssm/IPrintable_DApplySsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DApplySsm::pretty(const DApplySsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DApplySsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DApplySsm.cpp b/src/reader2/ISyntaxStateMachine_DApplySsm.cpp new file mode 100644 index 00000000..2164ae04 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DApplySsm.cpp @@ -0,0 +1,69 @@ +/** @file ISyntaxStateMachine_DApplySsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DApplySsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DApplySsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DApplySsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DApplySsm::ssm_type(const DApplySsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DApplySsm::get_expect_str(const DApplySsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DApplySsm::on_token(DApplySsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DApplySsm::on_parsed_symbol(DApplySsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DApplySsm::on_parsed_typedescr(DApplySsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DApplySsm::on_parsed_formal(DApplySsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DApplySsm::on_parsed_formal_arglist(DApplySsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DApplySsm::on_parsed_expression(DApplySsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DApplySsm::on_parsed_expression_with_token(DApplySsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DApplySsm.cpp */ diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 3955fae3..eb39f6ac 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -17,8 +17,8 @@ #include #include -#include - +#include "ApplySsm.hpp" +#include "SequenceSsm.hpp" #include "ParenSsm.hpp" #include @@ -67,6 +67,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); FacetRegistry::register_impl(); FacetRegistry::register_impl(); From e0ab3c59274af5af13a1906adddd13da4277aa49 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Feb 2026 20:25:24 -0500 Subject: [PATCH 195/342] xo-reader2: more work on apply expressions [WIP] --- include/xo/reader2/DApplySsm.hpp | 43 ++++-- include/xo/reader2/DProgressSsm.hpp | 2 + src/reader2/DApplySsm.cpp | 186 ++++++++++++++++++------ src/reader2/DExpectFormalArglistSsm.cpp | 3 +- src/reader2/DProgressSsm.cpp | 41 +++++- utest/SchematikaParser.test.cpp | 24 +++ 6 files changed, 238 insertions(+), 61 deletions(-) diff --git a/include/xo/reader2/DApplySsm.hpp b/include/xo/reader2/DApplySsm.hpp index 46f9097b..e5d59f10 100644 --- a/include/xo/reader2/DApplySsm.hpp +++ b/include/xo/reader2/DApplySsm.hpp @@ -46,8 +46,8 @@ namespace xo { apply_0, apply_1, - apply_2, - apply_3, + apply_2, // rename -> apply_2a + apply_3, // rename -> apply_2b N }; @@ -81,7 +81,8 @@ namespace xo { * that we parse f before parser knows that it will be * followed by leftparen **/ - explicit DApplySsm(obj fn_expr); + explicit DApplySsm(obj fn_expr, + DArray * args); /** create instance using memory from @p parser_mm. * with function to be called supplied by @p fn_expr. @@ -103,9 +104,8 @@ namespace xo { **/ static void start(obj fnex, ParserStateMachine * p_psm); - ///@} - /** @defgroup scm-applyssm-access methods **/ + /** @defgroup scm-applyssm-access-methods access methods **/ ///@{ /** identify this nested state machine **/ @@ -114,6 +114,16 @@ namespace xo { /** current internal state **/ applyexprstatetype applystate() const noexcept { return applystate_; } + ///@} + /** @defgroup scm-applyssm-methods general methods **/ + ///@{ + + /** handle leftparen token @p tk for this ssm, + * with overall parser state in @p p_psm + **/ + void on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup ssm-applyssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -124,6 +134,12 @@ namespace xo { /** mnemonic for expected remaining syntax for current parsing state **/ std::string_view get_expect_str() const noexcept; + /** update this apply-ssm for incoming token @p tk, + * with overall parsing state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} #ifdef NOT_YET @@ -133,14 +149,9 @@ namespace xo { virtual void on_comma_token(const token_type & tk, parserstatemachine * p_psm) override; - virtual void on_leftparen_token(const token_type & tk, - parserstatemachine * p_psm) override; virtual void on_rightparen_token(const token_type & tk, parserstatemachine * p_psm) override; - virtual void print(std::ostream & os) const override; - virtual bool pretty_print(const print::ppindentinfo & ppii) const final override; - private: static std::unique_ptr make(); #endif @@ -158,10 +169,14 @@ namespace xo { applyexprstatetype applystate_ = applyexprstatetype::apply_0; /** evaluates to function to be invoked **/ obj fn_expr_; -#ifdef NOT_YET - /** evaluates to the arguments to pass to @ref fn_ **/ - std::vector> args_expr_v_; -#endif + /** args_expr_v_[i] evaluates to the i'th argument to call. + * Not using flexible array here since we don't know size at + * construction time + * + * (though could revisit + realloc this DApplySsm instance in + * place to optimize) + **/ + DArray * args_expr_v_ = nullptr; }; } /*namespace scm */ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 47ca29b9..1a0e7186 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -137,6 +137,8 @@ namespace xo { /** handle leftparen token @p tk. Overall parser state in @p p_psm **/ void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); + void on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm); void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index 217c60b2..bdcbe965 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -4,6 +4,7 @@ **/ #include "ApplySsm.hpp" +#include "ExpectExprSsm.hpp" #include //#include "parserstatemachine.hpp" @@ -39,13 +40,18 @@ namespace xo { // ----- DApplySsm ----- - DApplySsm::DApplySsm(obj fn_expr) - : applystate_{applyexprstatetype::apply_0}, - fn_expr_{fn_expr} + DApplySsm::DApplySsm(applyexprstatetype applystate, + obj fn_expr, + DArray * args) + : applystate_{applystate}, + fn_expr_{fn_expr}, + arg_expr_v_{args} { if (fn_expr) { this->applystate_ = applyexprstatetype::apply_1; } + + assert(args->empty()); } DApplySsm * @@ -55,10 +61,21 @@ namespace xo { void * mem = mm.alloc(typeseq::id(), sizeof(DApplySsm)); - // TODO: revisit if we use flexible array for - // arguments + /* allocate room for 8 arguments (during parsing) + * will reallocate to expand if needed. + * + * See similar code in DExpectFormalArglistSsm::_make + */ + DArray * args = DArray::empty(mm, 8); - return new (mem) DApplySsm(fn_expr); + applyexprstatetype applystate + = (fn_expr + ? applyexprstatetype::apply_1 + : applyexprstatetype::apply_0); + + // TODO: revisit if we decide to use flexible array for arguments + + return new (mem) DApplySsm(applystate, fn_expr, args); } void @@ -98,6 +115,124 @@ namespace xo { return "?expect"; } + void + DApplySsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); + + switch (tk.tk_type()) { + case tokentype::tk_leftparen: + this->on_leftparen_token(tk, p_psm); + return; + case tokentype::tk_symbol: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_semicolon: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_invalid: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + Super::on_token(tk, p_psm); + } + + void + DApplySsm::on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (applystate_ == applyexprstatetype::apply_1) { + this->applystate_ = applyexprstatetype::apply_2; + + DExpectExprSsm::start(p_psm); + return; + } + + Super::on_token(tk, p_psm); + } + + void + DApplySsm::on_parsed_expression_with_token(obj expr, + const Token & tk) + { + if (applystate_ == applyexprstatetype::apply_2) { + if (args_expr_v_->size() == args_expr_v_->capacity()) { + // need to expand .args_expr_v_ capacity. + // Could use DArena checkpoint to redo this in place, + // since argument array must be on the top of the stack. + + obj mm(&(p_psm->parser_alloc())); + + DArray * argv_2x = DArray::empty(mm, 2 * args_expr_v_->capacity()); + + for (DArray::size_type i = 0, n = arg_expr_v_->size(); i < n; ++i) { + argv_2x->push_back((*argv_)[i]); + } + + this->args_expr_v_ = argv_2x; + } + + if (args_expr_v_->size() < args_expr_v_->capacity()) { + args_expr_v_->push_back(expr); + + } + + if (tk.tk_type() == tokentype::tk_rightparen) { + // expression completes apply + + // TODO: assemble apply expression.. + + assert(false); + } + + if ((tk.tk_type() == tokentype::tk_comma) + || (tk.tk_type() == tokentype::tk_rightparen)) { + + // do stuff, + //return; + } + + // complain + + assert(false); + } + + Super::on_parsed_expression_with_token(expr, tk); + } + #ifdef NOT_YET void apply_xs::on_expr(bp expr, @@ -154,25 +289,6 @@ namespace xo { } } - void - apply_xs::on_leftparen_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - log && log("applyxs_type", applyxs_type_); - - if (this->applyxs_type_ == applyexprstatetype::apply_1) { - this->applyxs_type_ = applyexprstatetype::apply_2; - expect_expr_xs::start(p_psm); - } else { - constexpr const char * c_self_name = "apply_xs::on_leftparen_token"; - const char * exp = this->get_expect_str(); - - this->illegal_input_on_token(c_self_name, tk, exp, p_psm); - } - } - void apply_xs::on_rightparen_token(const token_type & tk, parserstatemachine * p_psm) @@ -214,26 +330,6 @@ namespace xo { refrtag("fn_expr", fn_expr, fn_expr_present)); } -#ifdef NOT_YET - void - apply_xs::print(std::ostream & os) const - { - os << ""; - } - - bool - apply_xs::pretty_print(const xo::print::ppindentinfo & ppii) const - { - return ppii.pps()->pretty_struct(ppii, "apply_xs", - refrtag("applyxs_type", applyxs_type_), - refrtag("fn_expr", fn_expr_), - refrtag("args_expr_v", args_expr_v_)); - } - -#endif } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index b34ad135..5f609807 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -182,7 +182,8 @@ namespace xo { if (fastate_ == formalarglstatetype::argl_1a) { this->fastate_ = formalarglstatetype::argl_1b; - TypeRef typeref = TypeRef::dwim(TypeRef::prefix_type::from_chars("formal"), param_type); + TypeRef typeref + = TypeRef::dwim(TypeRef::prefix_type::from_chars("formal"), param_type); DVariable * var = DVariable::make(p_psm->expr_alloc(), param_name, diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 19d318f6..d3b8c3c3 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -267,11 +267,14 @@ namespace xo { this->on_leftparen_token(tk, p_psm); return; + case tokentype::tk_rightparen: + this->on_rightparen_token(tk, p_psm); + return; + // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_def: case tokentype::tk_if: - case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: @@ -937,6 +940,9 @@ namespace xo { this->lhs_ = obj(); DApplySsm::start(fn_expr, p_psm); + // + send leftparen to just-pushed apply + p_psm->on_token(tk); + return; } @@ -986,7 +992,40 @@ namespace xo { this->illegal_input_on_token(c_self_name, tk, exp, p_psm); } +#endif + void + DProgressSsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + /* note: implementation parallels .on_semicolon_token() */ + + scope log(XO_DEBUG(p_psm->debug_flag())); + + /* stack may be something like: + * + * [0] DProgressSsm + * [1] DExpectExprSsm + * [2] DApplySsm + * + * where we want rightparen to resolve in [2] DApplySsm, + * after triggering completion of [0] and [1] + */ + auto expr = this->assemble_expr(p_psm); + + if (expr) { + /* 1. popping self from parser stack.. */ + p_psm->pop_ssm(); + /* 2. report parsed subexpr to parent ssm, along with the triggering rightparen **/ + p_psm->on_parsed_expression_with_token(expr, tk); + + return; + } + + Super::on_token(tk, p_psm); + } + +#ifdef NOT_YET void progress_xs::on_rightparen_token(const token_type & tk, parserstatemachine * p_psm) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 77d9471c..cbf669fd 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1204,6 +1204,30 @@ namespace xo { REQUIRE(!result.is_error()); REQUIRE(result.is_incomplete()); } + + { + auto & result = parser.on_token(Token::i64_token("13")); + + log && log("after i64(13) token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::rightparen_token()); + + log && log("after rightparen token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } } } /*namespace ut*/ } /*namespace xo*/ From a15abd8b433ac6cd9da90cb654ada58e9a10224e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Feb 2026 00:02:56 -0500 Subject: [PATCH 196/342] xo-reader2: apply expr now parses up to rightparen --- include/xo/reader2/DApplySsm.hpp | 21 +++++++- src/reader2/DApplySsm.cpp | 89 +++++++++++++++++++++----------- 2 files changed, 79 insertions(+), 31 deletions(-) diff --git a/include/xo/reader2/DApplySsm.hpp b/include/xo/reader2/DApplySsm.hpp index e5d59f10..b9ff3d8b 100644 --- a/include/xo/reader2/DApplySsm.hpp +++ b/include/xo/reader2/DApplySsm.hpp @@ -81,7 +81,8 @@ namespace xo { * that we parse f before parser knows that it will be * followed by leftparen **/ - explicit DApplySsm(obj fn_expr, + explicit DApplySsm(applyexprstatetype applystate, + obj fn_expr, DArray * args); /** create instance using memory from @p parser_mm. @@ -140,6 +141,13 @@ namespace xo { void on_token(const Token & tk, ParserStateMachine * p_psm); + /** update this apply-ssm with data from nested ssm: + * expression @p expr, followed by token @p tk. + **/ + void on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm); + ///@} #ifdef NOT_YET @@ -165,6 +173,15 @@ namespace xo { ///@} private: + /** @defgroup ssm-applyssm-mpl-methods **/ + ///@{ + + ///@} + + private: + /** @defgroup ssm-applyssm-member-variables **/ + ///@{ + /** current state of parser for this apply expression **/ applyexprstatetype applystate_ = applyexprstatetype::apply_0; /** evaluates to function to be invoked **/ @@ -177,6 +194,8 @@ namespace xo { * place to optimize) **/ DArray * args_expr_v_ = nullptr; + + ///@} }; } /*namespace scm */ diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index bdcbe965..ad2f7fd6 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -5,12 +5,15 @@ #include "ApplySsm.hpp" #include "ExpectExprSsm.hpp" +#include +#include #include //#include "parserstatemachine.hpp" //#include "expect_expr_xs.hpp" namespace xo { + using xo::mm::AGCObject; using xo::print::APrintable; using xo::reflect::typeseq; @@ -45,21 +48,23 @@ namespace xo { DArray * args) : applystate_{applystate}, fn_expr_{fn_expr}, - arg_expr_v_{args} + args_expr_v_{args} { if (fn_expr) { this->applystate_ = applyexprstatetype::apply_1; } - assert(args->empty()); + assert(args->is_empty()); } DApplySsm * - DApplySsm::make(DArena & mm, + DApplySsm::make(DArena & arena, obj fn_expr) { - void * mem = mm.alloc(typeseq::id(), - sizeof(DApplySsm)); + obj mm(&arena); + + void * mem = arena.alloc(typeseq::id(), + sizeof(DApplySsm)); /* allocate room for 8 arguments (during parsing) * will reallocate to expand if needed. @@ -186,51 +191,75 @@ namespace xo { void DApplySsm::on_parsed_expression_with_token(obj expr, - const Token & tk) + const Token & tk, + ParserStateMachine * p_psm) { + /* maybe we'll find control comes here also on function position? + * hasn't come up when applyssm recognized via leftparen + */ + if (applystate_ == applyexprstatetype::apply_2) { + obj expr_gco = expr.to_facet(); + assert(expr_gco); + + obj mm(&(p_psm->parser_alloc())); + if (args_expr_v_->size() == args_expr_v_->capacity()) { // need to expand .args_expr_v_ capacity. // Could use DArena checkpoint to redo this in place, // since argument array must be on the top of the stack. - obj mm(&(p_psm->parser_alloc())); - DArray * argv_2x = DArray::empty(mm, 2 * args_expr_v_->capacity()); - for (DArray::size_type i = 0, n = arg_expr_v_->size(); i < n; ++i) { - argv_2x->push_back((*argv_)[i]); + for (DArray::size_type i = 0, n = args_expr_v_->size(); i < n; ++i) { + argv_2x->push_back((*args_expr_v_)[i]); } this->args_expr_v_ = argv_2x; } - if (args_expr_v_->size() < args_expr_v_->capacity()) { - args_expr_v_->push_back(expr); - - } + if (args_expr_v_->size() < args_expr_v_->capacity()) + args_expr_v_->push_back(expr_gco); if (tk.tk_type() == tokentype::tk_rightparen) { - // expression completes apply + // begin assemble_expr().. - // TODO: assemble apply expression.. + std::uint32_t n_args = args_expr_v_->size(); - assert(false); + DApplyExpr * apply + = (DApplyExpr::scaffold + (mm, + TypeRef::dwim(TypeRef::prefix_type::from_chars("apply"), + nullptr), + fn_expr_, + n_args)); + + for (std::uint32_t i_arg = 0; i_arg < n_args; ++i_arg) { + auto arg_expr + = args_expr_v_->at(i_arg).to_facet(); + + apply->assign_arg(i_arg, arg_expr); + } + + // ..end assemble_expr() + + obj apply_ex(apply); + + p_psm->pop_ssm(); + p_psm->on_parsed_expression(apply_ex); + + return; + } else if (tk.tk_type() == tokentype::tk_comma) { + // 1. want to remain in state apply_2 + // 2. expr from nested ssm already incorporated + // into .args_expr_v_ + // -> so updated state already achieved. + + return; } - - if ((tk.tk_type() == tokentype::tk_comma) - || (tk.tk_type() == tokentype::tk_rightparen)) { - - // do stuff, - //return; - } - - // complain - - assert(false); } - Super::on_parsed_expression_with_token(expr, tk); + Super::on_parsed_expression_with_token(expr, tk, p_psm); } #ifdef NOT_YET @@ -319,7 +348,7 @@ namespace xo { bool DApplySsm::pretty(const ppindentinfo & ppii) const { - // TODO: const-correct version of obj<> template + // TODO: const-correct version of obj<> template auto fn_expr = const_cast(this)->fn_expr_.to_facet(); bool fn_expr_present(fn_expr); From 9c677b28cce55f520a0a5800388fd45e29494f92 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Feb 2026 00:06:50 -0500 Subject: [PATCH 197/342] xo-reader2: utest for top-level apply passes --- utest/SchematikaParser.test.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index cbf669fd..54896a3f 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1228,6 +1228,19 @@ namespace xo { REQUIRE(!result.is_error()); REQUIRE(result.is_incomplete()); } + + { + auto & result = parser.on_token(Token::semicolon_token()); + + log && log("after semicolon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + } } } /*namespace ut*/ } /*namespace xo*/ From 3a516e28664422656c1b2e3b6d2f4ebd8ac9b472 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Feb 2026 00:43:46 -0500 Subject: [PATCH 198/342] xo-reader2: handle multiple args in apply + streamlined utest --- include/xo/reader2/DProgressSsm.hpp | 2 + src/reader2/DApplySsm.cpp | 2 +- src/reader2/DProgressSsm.cpp | 6 +-- utest/SchematikaParser.test.cpp | 84 +++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 4 deletions(-) diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 1a0e7186..c43caacd 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -142,6 +142,8 @@ namespace xo { void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); + void on_comma_token(const Token & tk, + ParserStateMachine * p_psm); void on_colon_token(const Token & tk, ParserStateMachine * p_psm); void on_singleassign_token(const Token & tk, diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index ad2f7fd6..4cd3aaec 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -253,8 +253,8 @@ namespace xo { // 1. want to remain in state apply_2 // 2. expr from nested ssm already incorporated // into .args_expr_v_ - // -> so updated state already achieved. + DExpectExprSsm::start(p_psm); return; } } diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index d3b8c3c3..20bfb998 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -224,6 +224,7 @@ namespace xo { switch (tk.tk_type()) { case tokentype::tk_then: case tokentype::tk_else: + case tokentype::tk_comma: this->on_completing_token(tk, p_psm); return; @@ -283,7 +284,6 @@ namespace xo { case tokentype::tk_lessequal: case tokentype::tk_greatequal: case tokentype::tk_dot: - case tokentype::tk_comma: case tokentype::tk_doublecolon: case tokentype::tk_assign: case tokentype::tk_yields: @@ -911,7 +911,7 @@ namespace xo { // input: /// <--- F1 ---> // (..........)(.. ).. - // <------ A1 -----> + // <------ A1 -----> // <------- X1 ------> // // F1: expression evaluating to a function, @@ -933,7 +933,7 @@ namespace xo { // 1. keep ProgressSsm on the stack in case input continues like: // fn_expr(args..) + .. // i.e. to allow for infix operator following apply - // + // obj fn_expr(this->lhs_); diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 54896a3f..0ecaff37 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1242,6 +1242,90 @@ namespace xo { REQUIRE(result.result_expr()); } } + + TEST_CASE("SchematikaParser-interactive-apply2", "[reader2][SchematikaParser]") + { + // top-level apply, with multiple arguments + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * (lambda (x : i64, y : i64) { x * y })(13, 15); + * + **/ + + std::vector tk_v{ + Token::leftparen_token(), + + /**/ Token::lambda_token(), + /* */ Token::leftparen_token(), + /* */ Token::symbol_token("x"), + /* */ Token::colon_token(), + /* */ Token::symbol_token("i64"), + /* */ Token::comma_token(), + /* */ Token::symbol_token("y"), + /* */ Token::colon_token(), + /* */ Token::symbol_token("i64"), + /* */ Token::rightparen_token(), + + /**/ Token::leftbrace_token(), + /* */ Token::symbol_token("x"), + /* */ Token::star_token(), + /* */ Token::symbol_token("y"), + /**/ Token::rightbrace_token(), + + Token::rightparen_token(), + + Token::leftparen_token(), + /**/ Token::i64_token("13"), + /**/ Token::comma_token(), + /**/ Token::i64_token("15"), + Token::rightparen_token(), + + Token::semicolon_token(), + }; + + size_t i_tk = 0; + size_t n_tk = tk_v.size(); + for (const auto & tk : tk_v) { + INFO(tostr(xtag("i_tk", i_tk), xtag("tk", tk))); + + auto & result = parser.on_token(tk); + + log && log("after token", xtag("i_tk", i_tk), xtag("tk", tk)); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + if (i_tk + 1 < n_tk) { + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } else { + /* last token in tk_v[] */ + + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + } + + ++i_tk; + } + + } } /*namespace ut*/ } /*namespace xo*/ From 3afe93b6c4e51059741e1f0bc99bd86efe011aa7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Feb 2026 15:21:35 -0500 Subject: [PATCH 199/342] xo-reader2 utest: less boilerplate! --- utest/SchematikaParser.test.cpp | 238 ++++++-------------------------- 1 file changed, 41 insertions(+), 197 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 0ecaff37..3bdf94cc 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1037,209 +1037,53 @@ namespace xo { * **/ - { - auto & result = parser.on_token(Token::leftparen_token()); + std::vector tk_v{ + Token::leftparen_token(), - log && log("after lparen token:"); + /**/ Token::lambda_token(), + /**/ Token::leftparen_token(), + /**/ Token::symbol_token("x"), + /**/ Token::colon_token(), + /**/ Token::symbol_token("i64"), + /**/ Token::rightparen_token(), + /**/ Token::leftbrace_token(), + /**/ Token::symbol_token("x"), + /**/ Token::star_token(), + /**/ Token::symbol_token("x"), + /**/ Token::rightbrace_token(), + /**/ Token::rightparen_token(), + /**/ Token::leftparen_token(), + /**/ Token::i64_token("13"), + /**/ Token::rightparen_token(), + + /**/ Token::semicolon_token(), + }; + + size_t i_tk = 0; + size_t n_tk = tk_v.size(); + for (const auto & tk : tk_v) { + INFO(tostr(xtag("i_tk", i_tk), xtag("tk", tk))); + + auto & result = parser.on_token(tk); + + log && log("after token", xtag("i_tk", i_tk), xtag("tk", tk)); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } + if (i_tk + 1 < n_tk) { + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } else { + /* last token in tk_v[] */ - { - auto & result = parser.on_token(Token::lambda_token()); + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + } - log && log("after lambda token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::leftparen_token()); - - log && log("after lparen token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("x")); - - log && log("after symbol(x) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::colon_token()); - - log && log("after colon token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("i64")); - - log && log("after symbol(i64) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::rightparen_token()); - - log && log("after rightparen token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::leftbrace_token()); - - log && log("after leftbrace token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("x")); - - log && log("after symbol(x) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::star_token()); - - log && log("after star(*) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("x")); - - log && log("after symbol(x) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::rightbrace_token()); - - log && log("after rightbrace(}) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::rightparen_token()); - - log && log("after rightparen token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::leftparen_token()); - - log && log("after leftparen token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::i64_token("13")); - - log && log("after i64(13) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::rightparen_token()); - - log && log("after rightparen token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::semicolon_token()); - - log && log("after semicolon token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == false); - REQUIRE(!result.is_error()); - REQUIRE(result.is_expression()); - REQUIRE(result.result_expr()); + ++i_tk; } } From 6a52c00b2e6e27e1d994ca3bf44e8600a58c4f6a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 17:24:23 -0500 Subject: [PATCH 200/342] xo-reader2 stack: handle comparison expression (x == y) --- include/xo/reader2/SchematikaParser.hpp | 3 + src/reader2/DProgressSsm.cpp | 29 ++++- src/reader2/SchematikaParser.cpp | 6 + utest/SchematikaParser.test.cpp | 157 ++++++++++++++++-------- 4 files changed, 143 insertions(+), 52 deletions(-) diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 8c3f51b1..4be59f04 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -193,6 +193,9 @@ namespace xo { /** top of parser stack **/ obj top_ssm() const; + /** current parser result. Value of last return from @ref on_token **/ + const ParserResult & result() const; + /** visit parser-owned memory pools; invoke visitor(info) for each **/ void visit_pools(const MemorySizeVisitor & visitor) const; diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 20bfb998..acffc851 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -292,11 +292,11 @@ namespace xo { break; case tokentype::tk_star: + case tokentype::tk_cmpeq: this->on_operator_token(tk, p_psm); return; case tokentype::tk_slash: - case tokentype::tk_cmpeq: case tokentype::tk_cmpne: case tokentype::tk_type: case tokentype::tk_lambda: @@ -1177,6 +1177,10 @@ namespace xo { ); } + namespace { + // make_builtin_apply_pm2 + } + obj DProgressSsm::assemble_expr(ParserStateMachine * p_psm) { @@ -1209,7 +1213,28 @@ namespace xo { return this->lhs_; case optype::op_assign: + assert(false); + break; + case optype::op_equal: + { + auto pm_obj = (with_facet::mkobj + (&Primitives::s_equal_gco_gco_pm)); + auto fn_expr = (DConstant::make + (p_psm->expr_alloc(), pm_obj)); + + // see note on op_multiply + + TypeRef tref = TypeRef::dwim + (TypeRef::prefix_type::from_chars("_equal_gco"), + nullptr); + + return DApplyExpr::make2(p_psm->expr_alloc(), + tref, + fn_expr, lhs_, rhs_); + } + break; + case optype::op_not_equal: case optype::op_less: case optype::op_less_equal: @@ -1217,6 +1242,7 @@ namespace xo { case optype::op_great_equal: case optype::op_add: case optype::op_subtract: + assert(false); break; case optype::op_multiply: @@ -1255,6 +1281,7 @@ namespace xo { break; case optype::op_divide: // TODO: implement binary operator expression assembly + assert(false); break; #ifdef NOT_YET diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index c53acc16..1973bbe7 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -47,6 +47,12 @@ namespace xo { return psm_.top_ssm(); } + const ParserResult & + SchematikaParser::result() const + { + return psm_.result(); + } + void SchematikaParser::visit_pools(const MemorySizeVisitor & visitor) const { diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 3bdf94cc..2c36ee96 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -411,6 +411,39 @@ namespace xo { //REQUIRE(result.error_description()); } + void + utest_tokenizer_loop(SchematikaParser * parser, std::vector & tk_v, bool debug_flag) + { + scope log(XO_DEBUG(debug_flag)); + + size_t i_tk = 0; + size_t n_tk = tk_v.size(); + for (const auto & tk : tk_v) { + INFO(tostr(xtag("i_tk", i_tk), xtag("tk", tk))); + + auto & result = parser->on_token(tk); + + log && log("after token", xtag("i_tk", i_tk), xtag("tk", tk)); + log && log(xtag("parser", parser)); + log && log(xtag("result", result)); + + if (i_tk + 1 < n_tk) { + REQUIRE(parser->has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } else { + /* last token in tk_v[] */ + + REQUIRE(parser->has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + } + + ++i_tk; + } + } + TEST_CASE("SchematikaParser-interactive-arith", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); @@ -435,54 +468,17 @@ namespace xo { * **/ + std::vector tk_v{ + Token::f64_token("3.14159265"), + Token::star_token(), + Token::f64_token("0.5"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); { - auto & result = parser.on_token(Token::f64_token("3.14159265")); - - log && log("after float(3.14159265) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::star_token()); - - log && log("after star token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::f64_token("0.5")); - - log && log("after float(0.5) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::semicolon_token()); - - log && log("after semicolon token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == false); - REQUIRE(!result.is_error()); - REQUIRE(result.is_expression()); - REQUIRE(result.result_expr()); - auto expr = obj::from(result.result_expr()); REQUIRE(expr); @@ -509,10 +505,69 @@ namespace xo { REQUIRE(rhs_f64); REQUIRE(rhs_f64->value() == 0.5); } + } - //REQUIRE(result.is_error()); - //// illegal input on token - //REQUIRE(result.error_description()); + TEST_CASE("SchematikaParser-interactive-cmp", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * 312 == 312 ; + * + **/ + + std::vector tk_v{ + Token::i64_token("312"), + Token::cmpeq_token(), + Token::i64_token("312"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + + REQUIRE(expr->n_args() == 2); + + auto fn = obj::from(expr->fn()); + REQUIRE(fn); + + auto pm = obj::from(fn->value()); + REQUIRE(pm); + REQUIRE(pm->name() == "_equal"); + + auto lhs = obj::from(expr->arg(0)); + REQUIRE(lhs); + + auto lhs_i64 = obj::from(lhs->value()); + REQUIRE(lhs_i64); + REQUIRE(lhs_i64->value() == 312); + + auto rhs = obj::from(expr->arg(1)); + REQUIRE(rhs); + + auto rhs_i64 = obj::from(rhs->value()); + REQUIRE(rhs_i64); + REQUIRE(rhs_i64->value() == 312); + } } TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]") @@ -1017,7 +1072,7 @@ namespace xo { TEST_CASE("SchematikaParser-interactive-apply", "[reader2][SchematikaParser]") { - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag)); ArenaConfig config; From 0baa458c5b2770c8ff5bb49f35c0426237d04abf Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 17:24:23 -0500 Subject: [PATCH 201/342] xo-reader2 stack: handle comparison expression (x == y) --- include/xo/tokenizer2/Token.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index ab3f0cb7..b211f967 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -129,6 +129,9 @@ namespace xo { /** token for @c "/" **/ static Token slash_token() { return Token(tokentype::tk_slash); } + /** token for @c "==" **/ + static Token cmpeq_token() { return Token(tokentype::tk_cmpeq); } + /** token representing keyword @c type **/ static Token type() { return Token(tokentype::tk_type); } /** token representing keyword @c def **/ From a759d3c92e13f05646f09300e295fdd4f2322b7f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 17:29:49 -0500 Subject: [PATCH 202/342] xo-reader2: streamline utest --- utest/SchematikaParser.test.cpp | 96 ++++----------------------------- 1 file changed, 10 insertions(+), 86 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 2c36ee96..f9601ad7 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -800,93 +800,17 @@ namespace xo { * **/ - { - auto & result = parser.on_token(Token::if_token()); + std::vector tk_v{ + Token::if_token(), + Token::bool_token("true"), + Token::then_token(), + Token::i64_token("777"), + Token::else_token(), + Token::string_token("fooey"), + Token::semicolon_token(), + }; - log && log("after if token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::bool_token("true")); - - log && log("after true token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::then_token()); - - log && log("after then token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::i64_token("777")); - - log && log("after i64 token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::else_token()); - - log && log("after else token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::string_token("fooey")); - - log && log("after string token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::semicolon_token()); - - log && log("after semicolon token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == false); - REQUIRE(!result.is_error()); - REQUIRE(!result.is_incomplete()); - } - - //REQUIRE(result.is_error()); - //// illegal input on token - //REQUIRE(result.error_description()); + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); } TEST_CASE("SchematikaParser-interactive-lambda2", "[reader2][SchematikaParser]") From 9b8e5baf53c28f1886d33b249d9be52b4f78f2fc Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 17:36:29 -0500 Subject: [PATCH 203/342] xo-reader2: streamline a utest --- utest/SchematikaParser.test.cpp | 169 +++++++++----------------------- 1 file changed, 46 insertions(+), 123 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index f9601ad7..b424fb8f 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -47,6 +47,39 @@ namespace xo { static InitEvidence s_init = (InitSubsys::require()); namespace ut { + void + utest_tokenizer_loop(SchematikaParser * parser, std::vector & tk_v, bool debug_flag) + { + scope log(XO_DEBUG(debug_flag)); + + size_t i_tk = 0; + size_t n_tk = tk_v.size(); + for (const auto & tk : tk_v) { + INFO(tostr(xtag("i_tk", i_tk), xtag("tk", tk))); + + auto & result = parser->on_token(tk); + + log && log("after token", xtag("i_tk", i_tk), xtag("tk", tk)); + log && log(xtag("parser", parser)); + log && log(xtag("result", result)); + + if (i_tk + 1 < n_tk) { + REQUIRE(parser->has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } else { + /* last token in tk_v[] */ + + REQUIRE(parser->has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + } + + ++i_tk; + } + } + TEST_CASE("SchematikaParser-ctor", "[reader2][SchematikaParser]") { ArenaConfig config; @@ -120,100 +153,23 @@ namespace xo { * **/ + std::vector tk_v{ + Token::def_token(), + Token::symbol_token("foo"), + Token::colon_token(), + Token::symbol_token("f64"), + Token::singleassign_token(), + Token::f64_token("3.141593"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); { - auto & result = parser.on_token(Token::def_token()); - - // after begin_interactive_session, parser has toplevel exprseq - // but is still "at toplevel" in the sense of ready for input - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(result.is_incomplete()); - - log && log("after def token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - } - - { - auto & result = parser.on_token(Token::symbol_token("foo")); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(result.is_incomplete()); - - log && log("after lhs symbol token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - } - - { - auto & result = parser.on_token(Token::colon_token()); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(result.is_incomplete()); - - log && log("after colon token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - } - - { - auto & result = parser.on_token(Token::symbol_token("f64")); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(result.is_incomplete()); - - log && log("after typename symbol token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - } - - { - auto & result = parser.on_token(Token::singleassign_token()); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(result.is_incomplete()); - - log && log("after typename symbol token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - auto exp_ssm - = obj::from(parser.top_ssm()); - - REQUIRE(exp_ssm); - REQUIRE(exp_ssm.data()->ssm_type() == syntaxstatetype::expect_rhs_expression); - REQUIRE(exp_ssm.data()->allow_defs() == false); - REQUIRE(exp_ssm.data()->cxl_on_rightbrace() == false); - } - - { - // future-proofing for Token only holding a string_view - const DString * str = DString::from_cstr(expr_alloc, "3.141593"); - - auto & result = parser.on_token(Token::f64_token(std::string(*str))); - - REQUIRE(parser.has_incomplete_expr() == true); - - log && log("after f64 token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - } - - { - auto & result = parser.on_token(Token::semicolon_token()); - - log && log("after semicolon token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == false); - auto expr = obj::from(result.result_expr()); REQUIRE(expr); } - - // define-expressions not properly implemented - - //REQUIRE(result.error_description()); } TEST_CASE("SchematikaParser-interactive-integer", "[reader2][SchematikaParser]") @@ -411,39 +367,6 @@ namespace xo { //REQUIRE(result.error_description()); } - void - utest_tokenizer_loop(SchematikaParser * parser, std::vector & tk_v, bool debug_flag) - { - scope log(XO_DEBUG(debug_flag)); - - size_t i_tk = 0; - size_t n_tk = tk_v.size(); - for (const auto & tk : tk_v) { - INFO(tostr(xtag("i_tk", i_tk), xtag("tk", tk))); - - auto & result = parser->on_token(tk); - - log && log("after token", xtag("i_tk", i_tk), xtag("tk", tk)); - log && log(xtag("parser", parser)); - log && log(xtag("result", result)); - - if (i_tk + 1 < n_tk) { - REQUIRE(parser->has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } else { - /* last token in tk_v[] */ - - REQUIRE(parser->has_incomplete_expr() == false); - REQUIRE(!result.is_error()); - REQUIRE(result.is_expression()); - REQUIRE(result.result_expr()); - } - - ++i_tk; - } - } - TEST_CASE("SchematikaParser-interactive-arith", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); From dcb4a8d2401fab5763e9734922e36f70fe1cf20e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 17:43:00 -0500 Subject: [PATCH 204/342] xo-reader2: streamline another utest --- utest/SchematikaParser.test.cpp | 172 +++----------------------------- 1 file changed, 16 insertions(+), 156 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index b424fb8f..5ea74fd8 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -758,163 +758,23 @@ namespace xo { * **/ - { - auto & result = parser.on_token(Token::lambda_token()); - - log && log("after lambda token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::leftparen_token()); - - log && log("after lparen token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("x")); - - log && log("after symbol(n) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::colon_token()); - - log && log("after colon token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("i64")); - - log && log("after symbol(i64) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::rightparen_token()); - - log && log("after rightparen token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::yields_token()); - - log && log("after yields token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("i64")); - - log && log("after symbol(i64) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::leftbrace_token()); - - log && log("after leftbrace token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("x")); - - log && log("after symbol(x) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::star_token()); - - log && log("after star(*) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("x")); - - log && log("after symbol(x) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::rightbrace_token()); - - log && log("after rightbrace(}) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == false); - REQUIRE(!result.is_error()); - REQUIRE(result.is_expression()); - REQUIRE(result.result_expr()); - } + std::vector tk_v{ + /**/ Token::lambda_token(), + /**/ Token::leftparen_token(), + /**/ Token::symbol_token("x"), + /**/ Token::colon_token(), + /**/ Token::symbol_token("i64"), + /**/ Token::rightparen_token(), + /**/ Token::yields_token(), + /**/ Token::symbol_token("i64"), + /**/ Token::leftbrace_token(), + /**/ Token::symbol_token("x"), + /**/ Token::star_token(), + /**/ Token::symbol_token("x"), + /**/ Token::rightbrace_token(), + }; + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); } TEST_CASE("SchematikaParser-interactive-apply", "[reader2][SchematikaParser]") From 5ac64cbfdb13b014f010697df421fc1ea3ddbc36 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 17:49:57 -0500 Subject: [PATCH 205/342] xo-reader2: number token sequence in parser utest --- utest/SchematikaParser.test.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 5ea74fd8..189b8e69 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -754,24 +754,26 @@ namespace xo { /** Walkthrough parsing input equivalent to: * - * lambda (x : i64) -> i64 { x * x }; - * + * lambda (x : i64) -> i64 { x * x } + * ^ ^^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * 0 1| 3 4 5 6 7 8 9 a b c + * 2 **/ std::vector tk_v{ - /**/ Token::lambda_token(), - /**/ Token::leftparen_token(), - /**/ Token::symbol_token("x"), - /**/ Token::colon_token(), - /**/ Token::symbol_token("i64"), - /**/ Token::rightparen_token(), - /**/ Token::yields_token(), - /**/ Token::symbol_token("i64"), - /**/ Token::leftbrace_token(), - /**/ Token::symbol_token("x"), - /**/ Token::star_token(), - /**/ Token::symbol_token("x"), - /**/ Token::rightbrace_token(), + /* [ 0] */ Token::lambda_token(), + /* [ 1] */ Token::leftparen_token(), + /* [ 2] */ Token::symbol_token("x"), + /* [ 3] */ Token::colon_token(), + /* [ 4] */ Token::symbol_token("i64"), + /* [ 5] */ Token::rightparen_token(), + /* [ 6] */ Token::yields_token(), + /* [ 7] */ Token::symbol_token("i64"), + /* [ 8] */ Token::leftbrace_token(), + /* [ 9] */ Token::symbol_token("x"), + /* [ a] */ Token::star_token(), + /* [ b] */ Token::symbol_token("x"), + /* [ c] */ Token::rightbrace_token(), }; utest_tokenizer_loop(&parser, tk_v, c_debug_flag); From 85883c74e8b300881b1ad14c40feb0c728ba14e4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 17:52:06 -0500 Subject: [PATCH 206/342] xo-reader2: utest: label test in console output --- utest/SchematikaParser.test.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 189b8e69..ea301a4c 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -738,8 +738,10 @@ namespace xo { TEST_CASE("SchematikaParser-interactive-lambda2", "[reader2][SchematikaParser]") { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; config.name_ = "test-arena"; From 0d74c4f4ab1fead3a3f4652533eea3d5ac7cf4ba Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 17:58:25 -0500 Subject: [PATCH 207/342] xo-reader2: refactor interactive-if utest to streamline --- utest/SchematikaParser.test.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index ea301a4c..703cccbf 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -703,8 +703,10 @@ namespace xo { TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]") { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; config.name_ = "test-arena"; @@ -720,17 +722,18 @@ namespace xo { /** Walkthrough parsing input equivalent to: * * if true then 777 else "fooey" ; - * + * ^ ^ ^ ^ ^ ^ ^ + * 0 1 2 3 4 5 6 **/ std::vector tk_v{ - Token::if_token(), - Token::bool_token("true"), - Token::then_token(), - Token::i64_token("777"), - Token::else_token(), - Token::string_token("fooey"), - Token::semicolon_token(), + /* [0] */ Token::if_token(), + /* [1] */ Token::bool_token("true"), + /* [2] */ Token::then_token(), + /* [3] */ Token::i64_token("777"), + /* [4] */ Token::else_token(), + /* [5] */ Token::string_token("fooey"), + /* [6] */ Token::semicolon_token(), }; utest_tokenizer_loop(&parser, tk_v, c_debug_flag); From 5f45f368c01997b818a2e50b764622f03c35ad19 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 18:02:55 -0500 Subject: [PATCH 208/342] xo-reader-2: refactor interactive-apply utest --- utest/SchematikaParser.test.cpp | 72 ++++++++++++--------------------- 1 file changed, 25 insertions(+), 47 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 703cccbf..35afc88c 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -786,8 +786,10 @@ namespace xo { TEST_CASE("SchematikaParser-interactive-apply", "[reader2][SchematikaParser]") { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; config.name_ = "test-arena"; @@ -802,58 +804,34 @@ namespace xo { /** Walkthrough parsing input equivalent to: * - * (lambda (x : i64) { x * x })(13); - * + * (lambda (x : i64) { x * x })(13) ; + * ^^ ^^ ^ ^ ^ ^ ^ ^ ^ ^^^^ ^ ^ + * 0| 2| 4 5 6 7 8 9 a b|d| f g + * 1 3 c e **/ std::vector tk_v{ - Token::leftparen_token(), + /* [ 0] */ Token::leftparen_token(), - /**/ Token::lambda_token(), - /**/ Token::leftparen_token(), - /**/ Token::symbol_token("x"), - /**/ Token::colon_token(), - /**/ Token::symbol_token("i64"), - /**/ Token::rightparen_token(), - /**/ Token::leftbrace_token(), - /**/ Token::symbol_token("x"), - /**/ Token::star_token(), - /**/ Token::symbol_token("x"), - /**/ Token::rightbrace_token(), - /**/ Token::rightparen_token(), - /**/ Token::leftparen_token(), - /**/ Token::i64_token("13"), - /**/ Token::rightparen_token(), - - /**/ Token::semicolon_token(), + /* [ 1] */ Token::lambda_token(), + /* [ 2] */ Token::leftparen_token(), + /* [ 3] */ Token::symbol_token("x"), + /* [ 4] */ Token::colon_token(), + /* [ 5] */ Token::symbol_token("i64"), + /* [ 6] */ Token::rightparen_token(), + /* [ 7] */ Token::leftbrace_token(), + /* [ 8] */ Token::symbol_token("x"), + /* [ 9] */ Token::star_token(), + /* [ a] */ Token::symbol_token("x"), + /* [ b] */ Token::rightbrace_token(), + /* [ c] */ Token::rightparen_token(), + /* [ d] */ Token::leftparen_token(), + /* [ e] */ Token::i64_token("13"), + /* [ f] */ Token::rightparen_token(), + /* [ g] */ Token::semicolon_token(), }; - size_t i_tk = 0; - size_t n_tk = tk_v.size(); - for (const auto & tk : tk_v) { - INFO(tostr(xtag("i_tk", i_tk), xtag("tk", tk))); - - auto & result = parser.on_token(tk); - - log && log("after token", xtag("i_tk", i_tk), xtag("tk", tk)); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - if (i_tk + 1 < n_tk) { - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } else { - /* last token in tk_v[] */ - - REQUIRE(parser.has_incomplete_expr() == false); - REQUIRE(!result.is_error()); - REQUIRE(result.is_expression()); - REQUIRE(result.result_expr()); - } - - ++i_tk; - } + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); } TEST_CASE("SchematikaParser-interactive-apply2", "[reader2][SchematikaParser]") From 955eb6d0c1126f4f5988ccd60b182ef2d76b012e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 18:06:38 -0500 Subject: [PATCH 209/342] xo-reader2: utest: refactor w/ syntax annotation for apply2 utest --- utest/SchematikaParser.test.cpp | 84 ++++++++++++--------------------- 1 file changed, 31 insertions(+), 53 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 35afc88c..0addfb7c 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -838,8 +838,10 @@ namespace xo { { // top-level apply, with multiple arguments + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; config.name_ = "test-arena"; @@ -854,68 +856,44 @@ namespace xo { /** Walkthrough parsing input equivalent to: * - * (lambda (x : i64, y : i64) { x * y })(13, 15); - * + * (lambda (x : i64, y : i64) { x * y })(13, 15) ; + * ^^ ^^ ^ ^ ^ ^^ ^ ^ ^ ^ ^ ^ ^^^^ ^ ^ ^ ^ + * 0| 2| 4 5 6 7| 9 a b c d e f|h| j k l m + * 1 3 8 g i **/ std::vector tk_v{ - Token::leftparen_token(), + /* [ 0] */ Token::leftparen_token(), - /**/ Token::lambda_token(), - /* */ Token::leftparen_token(), - /* */ Token::symbol_token("x"), - /* */ Token::colon_token(), - /* */ Token::symbol_token("i64"), - /* */ Token::comma_token(), - /* */ Token::symbol_token("y"), - /* */ Token::colon_token(), - /* */ Token::symbol_token("i64"), - /* */ Token::rightparen_token(), + /* [ 1] */ Token::lambda_token(), + /* [ 2] */ Token::leftparen_token(), + /* [ 3] */ Token::symbol_token("x"), + /* [ 4] */ Token::colon_token(), + /* [ 5] */ Token::symbol_token("i64"), + /* [ 6] */ Token::comma_token(), + /* [ 7] */ Token::symbol_token("y"), + /* [ 8] */ Token::colon_token(), + /* [ 9] */ Token::symbol_token("i64"), + /* [ a] */ Token::rightparen_token(), - /**/ Token::leftbrace_token(), - /* */ Token::symbol_token("x"), - /* */ Token::star_token(), - /* */ Token::symbol_token("y"), - /**/ Token::rightbrace_token(), + /* [ b] */ Token::leftbrace_token(), + /* [ c] */ Token::symbol_token("x"), + /* [ d] */ Token::star_token(), + /* [ e] */ Token::symbol_token("y"), + /* [ f] */ Token::rightbrace_token(), - Token::rightparen_token(), + /* [ g] */ Token::rightparen_token(), - Token::leftparen_token(), - /**/ Token::i64_token("13"), - /**/ Token::comma_token(), - /**/ Token::i64_token("15"), - Token::rightparen_token(), + /* [ h] */ Token::leftparen_token(), + /* [ i] */ Token::i64_token("13"), + /* [ j] */ Token::comma_token(), + /* [ k] */ Token::i64_token("15"), + /* [ l] */ Token::rightparen_token(), - Token::semicolon_token(), + /* [ m] */ Token::semicolon_token(), }; - size_t i_tk = 0; - size_t n_tk = tk_v.size(); - for (const auto & tk : tk_v) { - INFO(tostr(xtag("i_tk", i_tk), xtag("tk", tk))); - - auto & result = parser.on_token(tk); - - log && log("after token", xtag("i_tk", i_tk), xtag("tk", tk)); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - if (i_tk + 1 < n_tk) { - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } else { - /* last token in tk_v[] */ - - REQUIRE(parser.has_incomplete_expr() == false); - REQUIRE(!result.is_error()); - REQUIRE(result.is_expression()); - REQUIRE(result.result_expr()); - } - - ++i_tk; - } - + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); } } /*namespace ut*/ } /*namespace xo*/ From 91804f1e578901226f0ccd0f32c63fe77f1036d8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 18:11:08 -0500 Subject: [PATCH 210/342] xo-reader2: utest: refactor w/ syntax annotation etc. --- utest/SchematikaParser.test.cpp | 209 ++++---------------------------- 1 file changed, 24 insertions(+), 185 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 0addfb7c..609bfe57 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -495,8 +495,10 @@ namespace xo { TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]") { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; config.name_ = "test-arena"; @@ -512,193 +514,30 @@ namespace xo { /** Walkthrough parsing input equivalent to: * * lambda (n : i64, r : i64) -> i64 { 123 } - * + * ^ ^^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * 0 1| 3 4 5 6 7 8 9 a b c d e + * 2 **/ - { - auto & result = parser.on_token(Token::lambda_token()); + std::vector tk_v{ + /* [ 0] */ Token::lambda_token(), + /* [ 1] */ Token::leftparen_token(), + /* [ 2] */ Token::symbol_token("n"), + /* [ 3] */ Token::colon_token(), + /* [ 4] */ Token::symbol_token("i64"), + /* [ 5] */ Token::comma_token(), + /* [ 6] */ Token::symbol_token("r"), + /* [ 7] */ Token::colon_token(), + /* [ 8] */ Token::symbol_token("i64"), + /* [ 9] */ Token::rightparen_token(), + /* [ a] */ Token::yields_token(), + /* [ b] */ Token::symbol_token("i64"), + /* [ c] */ Token::leftbrace_token(), + /* [ d] */ Token::i64_token("123"), + /* [ e] */ Token::rightbrace_token(), + }; - log && log("after lambda token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::leftparen_token()); - - log && log("after lparen token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("n")); - - log && log("after symbol(n) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::colon_token()); - - log && log("after colon token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("i64")); - - log && log("after symbol(i64) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::comma_token()); - - log && log("after comma token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("r")); - - log && log("after symbol(r) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::colon_token()); - - log && log("after colon token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("i64")); - - log && log("after symbol(i64) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::rightparen_token()); - - log && log("after rightparen token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::yields_token()); - - log && log("after yields token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::symbol_token("i64")); - - log && log("after symbol(i64) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::leftbrace_token()); - - log && log("after leftbrace token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::i64_token("123")); - - log && log("after f64(123) token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == true); - REQUIRE(!result.is_error()); - REQUIRE(result.is_incomplete()); - } - - { - auto & result = parser.on_token(Token::rightbrace_token()); - - log && log("after rightbrace token:"); - log && log(xtag("parser", &parser)); - log && log(xtag("result", result)); - - REQUIRE(parser.has_incomplete_expr() == false); - REQUIRE(!result.is_error()); - REQUIRE(result.is_expression()); - REQUIRE(result.result_expr()); - } - - //REQUIRE(result.is_error()); - //// illegal input on token - //REQUIRE(result.error_description()); + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); } TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]") From 57981d93ef1d99492db1501cb8f53817472e6d33 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Feb 2026 18:13:10 -0500 Subject: [PATCH 211/342] xo-reader2: utest: annotate syntax --- utest/SchematikaParser.test.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 609bfe57..d6f74edc 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -451,14 +451,15 @@ namespace xo { /** Walkthrough parsing input equivalent to: * * 312 == 312 ; - * + * ^ ^ ^ ^ + * 0 1 2 3 **/ std::vector tk_v{ - Token::i64_token("312"), - Token::cmpeq_token(), - Token::i64_token("312"), - Token::semicolon_token(), + /* [0] */ Token::i64_token("312"), + /* [1] */ Token::cmpeq_token(), + /* [2] */ Token::i64_token("312"), + /* [3] */ Token::semicolon_token(), }; utest_tokenizer_loop(&parser, tk_v, c_debug_flag); From fc17a6f856400e60b757bd5a008218e9c45b346b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Feb 2026 14:10:47 -0500 Subject: [PATCH 212/342] xo-reader2: drop temporary debug flag --- src/reader2/DProgressSsm.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index acffc851..94efb30d 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -497,7 +497,7 @@ namespace xo { DProgressSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) { - const bool c_debug_flag = p_psm->debug_flag() || true; + const bool c_debug_flag = p_psm->debug_flag(); scope log(XO_DEBUG(c_debug_flag)); @@ -516,7 +516,7 @@ namespace xo { const Token & tk, ParserStateMachine * p_psm) { - const bool c_debug_flag = p_psm->debug_flag() || true; + const bool c_debug_flag = p_psm->debug_flag(); scope log(XO_DEBUG(c_debug_flag), xtag("expr", expr), @@ -1215,7 +1215,7 @@ namespace xo { case optype::op_assign: assert(false); break; - + case optype::op_equal: { auto pm_obj = (with_facet::mkobj From 78f1b8a0b6b058fbaa443544b7a553ad0ab05ddf Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Feb 2026 14:13:38 -0500 Subject: [PATCH 213/342] xo-interpreter2 stack: plumbing for aux_mm and use opportunistically --- example/readerreplxx/readerreplxx.cpp | 22 ++++++-- include/xo/reader2/ParserStateMachine.hpp | 27 +++++++++- include/xo/reader2/SchematikaParser.hpp | 10 ++-- include/xo/reader2/SchematikaReader.hpp | 9 +++- src/reader2/ParserStateMachine.cpp | 9 ++-- src/reader2/SchematikaParser.cpp | 5 +- src/reader2/SchematikaReader.cpp | 4 +- utest/SchematikaParser.test.cpp | 66 ++++++++++++++--------- 8 files changed, 110 insertions(+), 42 deletions(-) diff --git a/example/readerreplxx/readerreplxx.cpp b/example/readerreplxx/readerreplxx.cpp index c95dd101..292c3a43 100644 --- a/example/readerreplxx/readerreplxx.cpp +++ b/example/readerreplxx/readerreplxx.cpp @@ -2,8 +2,9 @@ #include #include -#include +#include #include +#include #include #include #include @@ -137,6 +138,7 @@ namespace { struct AppConfig { using ReaderConfig = xo::scm::ReaderConfig; using X1CollectorConfig = xo::mm::X1CollectorConfig; + using ArenaConfig = xo::mm::ArenaConfig; AppConfig() { rdr_config_.reader_debug_flag_ = true; @@ -147,17 +149,24 @@ struct AppConfig { std::size_t max_history_size_ = 1000; std::string repl_history_fname_ = "repl_history.txt";; ReaderConfig rdr_config_; - X1CollectorConfig x1_config_ = (X1CollectorConfig().with_size(4*1024*1024)); + X1CollectorConfig x1_config_ = (X1CollectorConfig().with_name("gc").with_size(4*1024*1024)); + ArenaConfig fixed_config_ = (ArenaConfig().with_name("fixed").with_size(4*1024)); }; struct AppContext { + using AAllocator = xo::mm::AAllocator; using DX1Collector = xo::mm::DX1Collector; using X1CollectorConfig = xo::mm::X1CollectorConfig; + using DArena = xo::mm::DArena; + using ArenaConfig = xo::mm::ArenaConfig; using Replxx = replxx::Replxx; AppContext(const AppConfig & cfg = AppConfig()) : config_{cfg}, - x1_{X1CollectorConfig().with_size(4*1024*1024)}, - rdr_{config_.rdr_config_, x1_.ref()} + x1_{cfg.x1_config_}, + fixed_{cfg.fixed_config_}, + rdr_{config_.rdr_config_, + x1_.ref(), + obj(&fixed_)} { rx_.set_max_history_size(config_.max_history_size_); rx_.history_load(config_.repl_history_fname_); @@ -167,9 +176,12 @@ struct AppContext { AppConfig config_; Replxx rx_; + /** collector/allocator for schematika expressions **/ DX1Collector x1_; + /** e.g. for DArenaHashMap within global symtab **/ + DArena fixed_; SchematikaReader rdr_; -}; +}; int main() diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index d8dc8da9..74a3e9bb 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -41,9 +41,21 @@ namespace xo { using size_type = std::size_t; public: + /** + * @p config arena configuration for parser state + * @p max_stringtable_capacity + * hard max size for unique stringtable + * @p expr_alloc allocator for schematika expressions. + * Probably shared with execution. + * @p aux_alloc auxiliary allocator for non-copyable memory + * (e.g. DArenaHashMap for global symtable). + * If not using X1Collector, this can be the + * same as @p expr_alloc. + **/ ParserStateMachine(const ArenaConfig & config, size_type max_stringtable_capacity, - obj expr_alloc); + obj expr_alloc, + obj aux_alloc); /** @defgroup scm-parserstatemachine-accessors accessor methods **/ ///@{ @@ -280,6 +292,19 @@ namespace xo { **/ obj expr_alloc_; + /** Allocator for data with lifetime bounded by this ParserStateMachine + * + * Cannot be DX1Collector; for example DArenaHashMap will + * for global symtab will be allocated from here, + * and does not support gc. + * + * If @ref expr_alloc_ is an ordinary arena (e.g. DArenaAlloc) + * can have aux_alloc_ = expr_alloc_. + * When expr_alloc_ is a garbage collector (e.g. DX1Collector) + * this needs to be distinct. + **/ + obj aux_alloc_; + /** symbol table with local bindings. * non-null during parsing of lambda expressions. * Always allocated from @p expr_alloc_. diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 4be59f04..13cb18ee 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -164,14 +164,18 @@ namespace xo { /** create parser in initial state; * parser is ready to receive tokens via @ref include_token * - * @p config arena configuration for parser stack - * @p expr_alloc allocator for schematika expressions. - * Probably shared with execution. + * @p config arena configuration for parser stack + * @p expr_alloc allocator for schematika expressions. + * Probably shared with execution. + * @p aux_alloc aux allocator for non-copyable memory + * with lifetime bounded by this + * SchematikeParser itself * @p debug_flag true to enable debug logging **/ SchematikaParser(const ArenaConfig & config, size_t max_stringtable_capacity, obj expr_alloc, + obj aux_alloc, bool debug_flag); /** scm-schematikaparser-access-methods **/ diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index ee3de91f..6f2b325e 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -41,8 +41,15 @@ namespace xo { using size_type = std::size_t; public: + /** + * @p expr_alloc. allocator for Schematika expressions + * @p aux_alloc. allocator for miscellaneous objects + * (e.g. DArenaHashMap for global symtab) + * that have lifetime bounded by Schematika reader itself. + **/ SchematikaReader(const ReaderConfig & config, - obj expr_alloc); + obj expr_alloc, + obj fixed_alloc); /** visit reader-owned memory pools; call visitor(info) for each. * Specifically exclude expr_alloc, since we don't consider diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 58119789..5541e8a0 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -24,13 +24,14 @@ namespace xo { namespace scm { ParserStateMachine::ParserStateMachine(const ArenaConfig & config, size_type max_stringtable_capacity, - obj expr_alloc) + obj expr_alloc, + obj aux_alloc) : stringtable_{max_stringtable_capacity}, parser_alloc_{DArena::map(config)}, expr_alloc_{expr_alloc}, + aux_alloc_{aux_alloc}, debug_flag_{config.debug_flag_} { - } bool @@ -60,8 +61,8 @@ namespace xo { stringtable_.visit_pools(visitor); parser_alloc_.visit_pools(visitor); - // not counting expr_alloc_. We don't consider - // that to be owned by ParserStateMachine + // not counting {expr_alloc_, fixed_alloc_}. We don't consider + // either to be owned by ParserStateMachine } void diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 1973bbe7..1b8b1904 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -23,9 +23,10 @@ namespace xo { SchematikaParser::SchematikaParser(const ArenaConfig & config, size_t max_stringtable_capacity, obj expr_alloc, + obj fixed_alloc, bool debug_flag) - : psm_{config, max_stringtable_capacity, expr_alloc}, - debug_flag_{debug_flag} + : psm_{config, max_stringtable_capacity, expr_alloc, fixed_alloc}, + debug_flag_{debug_flag} { } diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index 47140d63..f2e70824 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -10,12 +10,14 @@ namespace xo { namespace scm { SchematikaReader::SchematikaReader(const ReaderConfig & config, - obj expr_alloc) + obj expr_alloc, + obj fixed_alloc) : tokenizer_{config.tk_buffer_config_, config.tk_debug_flag_}, parser_{config.parser_arena_config_, config.max_stringtable_cap_, expr_alloc, + fixed_alloc, config.parser_debug_flag_}, debug_flag_{config.reader_debug_flag_} { diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index d6f74edc..94e8218d 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -88,8 +88,9 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); REQUIRE(parser.debug_flag() == false); REQUIRE(parser.is_at_toplevel() == true); @@ -103,8 +104,9 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -121,8 +123,9 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_batch_session(); @@ -133,17 +136,20 @@ namespace xo { TEST_CASE("SchematikaParser-batch-def", "[reader2][SchematikaParser]") { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; - config.name_ = "test-arena"; + config.name_ = testname; config.size_ = 16 * 1024; DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_batch_session(); @@ -185,8 +191,9 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -250,8 +257,9 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -315,8 +323,9 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -380,8 +389,9 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -435,16 +445,17 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + scope log(XO_DEBUG(c_debug_flag), + xtag("test", testname)); - ArenaConfig config; - config.name_ = "test-arena"; - config.size_ = 16 * 1024; + ArenaConfig config + = (ArenaConfig().with_name(testname).with_size(16 * 1024)); DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); + auto expr_alloc = obj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -507,8 +518,9 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -517,7 +529,7 @@ namespace xo { * lambda (n : i64, r : i64) -> i64 { 123 } * ^ ^^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ * 0 1| 3 4 5 6 7 8 9 a b c d e - * 2 + * 2 **/ std::vector tk_v{ @@ -549,13 +561,14 @@ namespace xo { scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; - config.name_ = "test-arena"; + config.name_ = testname; config.size_ = 16 * 1024; DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -592,8 +605,9 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -632,13 +646,14 @@ namespace xo { scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ArenaConfig config; - config.name_ = "test-arena"; + config.name_ = testname; config.size_ = 16 * 1024; DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -689,8 +704,9 @@ namespace xo { DArena expr_arena = DArena::map(config); obj expr_alloc = with_facet::mkobj(&expr_arena); + auto aux_alloc = expr_alloc; - SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/); + SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); parser.begin_interactive_session(); @@ -699,7 +715,7 @@ namespace xo { * (lambda (x : i64, y : i64) { x * y })(13, 15) ; * ^^ ^^ ^ ^ ^ ^^ ^ ^ ^ ^ ^ ^ ^^^^ ^ ^ ^ ^ * 0| 2| 4 5 6 7| 9 a b c d e f|h| j k l m - * 1 3 8 g i + * 1 3 8 g i **/ std::vector tk_v{ From c0e61744bbbafbd350a58fff25452542aad5b444 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Feb 2026 14:26:33 -0500 Subject: [PATCH 214/342] xo-interpreter2 stack: mark non-trivial dtors b/c DGlobalSymtab --- include/xo/reader2/ParserStateMachine.hpp | 9 ++++++--- include/xo/reader2/SchematikaParser.hpp | 3 +++ include/xo/reader2/SchematikaReader.hpp | 3 +++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 74a3e9bb..38cff2b8 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -57,6 +57,9 @@ namespace xo { obj expr_alloc, obj aux_alloc); + /** non-trivial dtor for @ref global_symtab_ **/ + ~ParserStateMachine() = default; + /** @defgroup scm-parserstatemachine-accessors accessor methods **/ ///@{ @@ -313,12 +316,12 @@ namespace xo { **/ DLocalSymtab * local_symtab_ = nullptr; -#ifdef NOT_YET /** global symbol table. * Toplevel definitions go here. + * + * Uses mmap -> non-trivial destructor. **/ - DGlobalSymtab * global_symtab_ = nullptr; -#endif + dp global_symtab_; /** current output from parser **/ ParserResult result_; diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 13cb18ee..ee86e6d5 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -178,6 +178,9 @@ namespace xo { obj aux_alloc, bool debug_flag); + /** non-trivial dtor because of @ref psm_ **/ + ~SchematikaParser() = default; + /** scm-schematikaparser-access-methods **/ ///@{ diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index 6f2b325e..73b8166b 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -51,6 +51,9 @@ namespace xo { obj expr_alloc, obj fixed_alloc); + /** non-trivial dtor because of @p parser **/ + ~SchematikaReader() = default; + /** visit reader-owned memory pools; call visitor(info) for each. * Specifically exclude expr_alloc, since we don't consider * that reader-owned From 9ce05973f4e2b1668b9ba2857348361e755cbf66 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Feb 2026 16:16:02 -0500 Subject: [PATCH 215/342] xo-reader2 stack: streamline + mem sizing + bugfixes --- include/xo/reader2/ParserConfig.hpp | 49 +++++ include/xo/reader2/ParserStateMachine.hpp | 7 + include/xo/reader2/ReaderConfig.hpp | 15 ++ include/xo/reader2/SchematikaParser.hpp | 11 +- src/reader2/ParserStateMachine.cpp | 3 + src/reader2/SchematikaParser.cpp | 14 +- src/reader2/SchematikaReader.cpp | 9 +- utest/SchematikaParser.test.cpp | 238 +++++++++++----------- 8 files changed, 210 insertions(+), 136 deletions(-) create mode 100644 include/xo/reader2/ParserConfig.hpp diff --git a/include/xo/reader2/ParserConfig.hpp b/include/xo/reader2/ParserConfig.hpp new file mode 100644 index 00000000..ce781b16 --- /dev/null +++ b/include/xo/reader2/ParserConfig.hpp @@ -0,0 +1,49 @@ +/** @file SchematikaParserConfig.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include +#include + +namespace xo { + namespace scm { + + /** @brief Configuration for SchematikaParser **/ + struct ParserConfig { + using ArenaHashMapConfig = xo::map::ArenaHashMapConfig; + using ArenaConfig = xo::mm::ArenaConfig; + + /** arena configuration for parser stack **/ + ArenaConfig parser_arena_config_ { .name_ = "parser-arena", + .size_ = 2*1024*1024, + .hugepage_z_ = 2*1024*1024, + .store_header_flag_ = false, + .header_{}, + .debug_flag_ = false }; + + /** configuration for hash map for global symbol table + * + * reminder: ownership chain + * SchematikaReader + * ->SchematikaParser + * ->ParserStateMachine + * ->DGlobalSymtab + **/ + ArenaHashMapConfig symtab_config_ { .name_ = "global-symtab", + .hint_max_capacity_ = 64*1024, + .debug_flag_ = false }; + + /** max capacity for unique string table **/ + size_t max_stringtable_capacity_ = 4096; + + /** control SchematikaParser debug logging **/ + bool debug_flag_ = false; + }; + + } +} + +/* end SchematikaParserConfig.hpp */ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 38cff2b8..97c8c6e5 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace xo { @@ -38,11 +39,14 @@ namespace xo { using ArenaConfig = xo::mm::ArenaConfig; using DArena = xo::mm::DArena; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; + using ArenaHashMapConfig = xo::map::ArenaHashMapConfig; using size_type = std::size_t; public: /** * @p config arena configuration for parser state + * @p symtab_config configuration for global symtab + * (maps separate dedicated memory) * @p max_stringtable_capacity * hard max size for unique stringtable * @p expr_alloc allocator for schematika expressions. @@ -53,6 +57,7 @@ namespace xo { * same as @p expr_alloc. **/ ParserStateMachine(const ArenaConfig & config, + const ArenaHashMapConfig & symtab_config, size_type max_stringtable_capacity, obj expr_alloc, obj aux_alloc); @@ -320,6 +325,8 @@ namespace xo { * Toplevel definitions go here. * * Uses mmap -> non-trivial destructor. + * + * TODO: may want to move ownership upstairs **/ dp global_symtab_; diff --git a/include/xo/reader2/ReaderConfig.hpp b/include/xo/reader2/ReaderConfig.hpp index 62e0e758..e139e9eb 100644 --- a/include/xo/reader2/ReaderConfig.hpp +++ b/include/xo/reader2/ReaderConfig.hpp @@ -6,6 +6,7 @@ #pragma once #include +#include #include namespace xo { @@ -14,6 +15,7 @@ namespace xo { /** @brief Configuration for SchematikaReader **/ struct ReaderConfig { + using ArenaHashMapConfig = xo::map::ArenaHashMapConfig; using CircularBufferConfig = xo::mm::CircularBufferConfig; using ArenaConfig = xo::mm::ArenaConfig; using size_t = std::size_t; @@ -34,6 +36,19 @@ namespace xo { .store_header_flag_ = false, .header_{}, .debug_flag_ = false }; + + /** configuration for hash map for global symbol table + * + * reminder: ownership chain + * SchematikaReader + * ->SchematikaParser + * ->ParserStateMachine + * ->DGlobalSymtab + **/ + ArenaHashMapConfig symtab_config_ { .name_ = "global-symtab", + .hint_max_capacity_ = 64*1024, + .debug_flag_ = false }; + /** debug flag for schematika parser **/ bool parser_debug_flag_ = false; diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index ee86e6d5..45b45c19 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -5,6 +5,7 @@ #pragma once +#include "ParserConfig.hpp" #include "ParserStateMachine.hpp" #include "ParserResult.hpp" #include @@ -154,6 +155,7 @@ namespace xo { class SchematikaParser { public: using token_type = Token; + using ArenaHashMapConfig = xo::map::ArenaHashMapConfig; using ArenaConfig = xo::mm::ArenaConfig; using AAllocator = xo::mm::AAllocator; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; @@ -164,19 +166,16 @@ namespace xo { /** create parser in initial state; * parser is ready to receive tokens via @ref include_token * - * @p config arena configuration for parser stack + * @p config parser configuration * @p expr_alloc allocator for schematika expressions. * Probably shared with execution. * @p aux_alloc aux allocator for non-copyable memory * with lifetime bounded by this * SchematikeParser itself - * @p debug_flag true to enable debug logging **/ - SchematikaParser(const ArenaConfig & config, - size_t max_stringtable_capacity, + SchematikaParser(const ParserConfig & config, obj expr_alloc, - obj aux_alloc, - bool debug_flag); + obj aux_alloc); /** non-trivial dtor because of @ref psm_ **/ ~SchematikaParser() = default; diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 5541e8a0..bbb4841e 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -23,6 +23,7 @@ namespace xo { namespace scm { ParserStateMachine::ParserStateMachine(const ArenaConfig & config, + const ArenaHashMapConfig & symtab_config, size_type max_stringtable_capacity, obj expr_alloc, obj aux_alloc) @@ -30,6 +31,7 @@ namespace xo { parser_alloc_{DArena::map(config)}, expr_alloc_{expr_alloc}, aux_alloc_{aux_alloc}, + global_symtab_{DGlobalSymtab::make(expr_alloc, aux_alloc, symtab_config)}, debug_flag_{config.debug_flag_} { } @@ -60,6 +62,7 @@ namespace xo { { stringtable_.visit_pools(visitor); parser_alloc_.visit_pools(visitor); + global_symtab_->visit_pools(visitor); // not counting {expr_alloc_, fixed_alloc_}. We don't consider // either to be owned by ParserStateMachine diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 1b8b1904..48e109da 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -20,13 +20,15 @@ namespace xo { namespace scm { // ----- SchematikaParser ----- - SchematikaParser::SchematikaParser(const ArenaConfig & config, - size_t max_stringtable_capacity, + SchematikaParser::SchematikaParser(const ParserConfig & cfg, obj expr_alloc, - obj fixed_alloc, - bool debug_flag) - : psm_{config, max_stringtable_capacity, expr_alloc, fixed_alloc}, - debug_flag_{debug_flag} + obj fixed_alloc) + : psm_{cfg.parser_arena_config_, + cfg.symtab_config_, + cfg.max_stringtable_capacity_, + expr_alloc, + fixed_alloc}, + debug_flag_{cfg.debug_flag_} { } diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index f2e70824..e02eefa2 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -14,11 +14,12 @@ namespace xo { obj fixed_alloc) : tokenizer_{config.tk_buffer_config_, config.tk_debug_flag_}, - parser_{config.parser_arena_config_, - config.max_stringtable_cap_, + parser_{ParserConfig(config.parser_arena_config_, + config.symtab_config_, + config.max_stringtable_cap_, + config.parser_debug_flag_), expr_alloc, - fixed_alloc, - config.parser_debug_flag_}, + fixed_alloc}, debug_flag_{config.reader_debug_flag_} { } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 94e8218d..5265922a 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -20,6 +20,7 @@ #include namespace xo { + using xo::scm::ParserConfig; using xo::scm::SchematikaParser; using xo::scm::ASyntaxStateMachine; using xo::scm::syntaxstatetype; @@ -39,14 +40,64 @@ namespace xo { using xo::scm::DFloat; using xo::scm::DInteger; + using xo::facet::FacetRegistry; + using xo::mm::ArenaConfig; using xo::mm::AAllocator; using xo::mm::DArena; + using xo::mm::MemorySizeInfo; using xo::facet::with_facet; static InitEvidence s_init = (InitSubsys::require()); namespace ut { + struct ParserFixture { + ParserFixture(const std::string & testname, bool debug_flag) + { + this->aux_arena_ + = std::move(DArena(ArenaConfig().with_name(testname).with_size(4 * 1024))); + obj aux_mm(&aux_arena_); + + this->expr_arena_ + = dp::make(aux_mm, + ArenaConfig().with_name("expr").with_size(16 * 1024)); + obj expr_mm(expr_arena_.data()); + + ParserConfig cfg; + cfg.parser_arena_config_.size_ = 16 * 1024; + cfg.symtab_config_.hint_max_capacity_ = 512; + cfg.max_stringtable_capacity_ = 512; + cfg.debug_flag_ = false; + + this->parser_ + = dp::make(aux_mm, cfg, expr_mm, aux_mm); + } + + ParserFixture(const ParserFixture & other) = delete; + ParserFixture(const ParserFixture && other) = delete; + + bool log_memory_layout(scope * p_log) { + auto visitor = [p_log](const MemorySizeInfo & info) { + *p_log && (*p_log)(xtag("resource", info.resource_name_), + xtag("used", info.used_), + xtag("alloc", info.allocated_), + xtag("commit", info.committed_), + xtag("resv", info.reserved_)); + }; + + aux_arena_.visit_pools(visitor); + FacetRegistry::instance().visit_pools(visitor); + expr_arena_->visit_pools(visitor); + parser_->visit_pools(visitor); + + return true; + } + + DArena aux_arena_; + dp expr_arena_; + dp parser_; + }; + void utest_tokenizer_loop(SchematikaParser * parser, std::vector & tk_v, bool debug_flag) { @@ -82,56 +133,56 @@ namespace xo { TEST_CASE("SchematikaParser-ctor", "[reader2][SchematikaParser]") { - ArenaConfig config; - config.name_ = "test-arena"; - config.size_ = 16 * 1024; + const auto & testname = Catch::getResultCapture().getCurrentTestName(); - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); REQUIRE(parser.debug_flag() == false); REQUIRE(parser.is_at_toplevel() == true); + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-begin-interactive", "[reader2][SchematikaParser]") { - ArenaConfig config; - config.name_ = "test-arena"; - config.size_ = 16 * 1024; + const auto & testname = Catch::getResultCapture().getCurrentTestName(); - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_interactive_session(); // after begin_interactive_session, parser has toplevel exprseq // but is still "at toplevel" in the sense of ready for input REQUIRE(parser.has_incomplete_expr() == false); + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-begin-batch", "[reader2][SchematikaParser]") { - ArenaConfig config; - config.name_ = "test-arena"; - config.size_ = 16 * 1024; + const auto & testname = Catch::getResultCapture().getCurrentTestName(); - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_batch_session(); // after begin_translation_unit, parser has toplevel exprseq // but is still "at toplevel" in the sense of ready for input REQUIRE(parser.has_incomplete_expr() == false); + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-batch-def", "[reader2][SchematikaParser]") @@ -141,15 +192,8 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ArenaConfig config; - config.name_ = testname; - config.size_ = 16 * 1024; - - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; - - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_batch_session(); @@ -176,6 +220,8 @@ namespace xo { auto expr = obj::from(result.result_expr()); REQUIRE(expr); } + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-interactive-integer", "[reader2][SchematikaParser]") @@ -185,15 +231,8 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ArenaConfig config; - config.name_ = "test-arena"; - config.size_ = 16 * 1024; - - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; - - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_interactive_session(); @@ -242,6 +281,8 @@ namespace xo { //REQUIRE(result.is_error()); //// illegal input on token //REQUIRE(result.error_description()); + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-interactive-float", "[reader2][SchematikaParser]") @@ -251,15 +292,8 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ArenaConfig config; - config.name_ = "test-arena"; - config.size_ = 16 * 1024; - - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; - - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_interactive_session(); @@ -308,6 +342,8 @@ namespace xo { //REQUIRE(result.is_error()); //// illegal input on token //REQUIRE(result.error_description()); + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-interactive-string", "[reader2][SchematikaParser]") @@ -317,15 +353,8 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ArenaConfig config; - config.name_ = "test-arena"; - config.size_ = 16 * 1024; - - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; - - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_interactive_session(); @@ -374,6 +403,8 @@ namespace xo { //REQUIRE(result.is_error()); //// illegal input on token //REQUIRE(result.error_description()); + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-interactive-arith", "[reader2][SchematikaParser]") @@ -383,15 +414,8 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ArenaConfig config; - config.name_ = "test-arena"; - config.size_ = 16 * 1024; - - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; - - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_interactive_session(); @@ -438,24 +462,20 @@ namespace xo { REQUIRE(rhs_f64); REQUIRE(rhs_f64->value() == 0.5); } + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-interactive-cmp", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ArenaConfig config - = (ArenaConfig().with_name(testname).with_size(16 * 1024)); - - DArena expr_arena = DArena::map(config); - auto expr_alloc = obj(&expr_arena); - auto aux_alloc = expr_alloc; - - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_interactive_session(); @@ -503,6 +523,8 @@ namespace xo { REQUIRE(rhs_i64); REQUIRE(rhs_i64->value() == 312); } + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]") @@ -512,15 +534,8 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ArenaConfig config; - config.name_ = "test-arena"; - config.size_ = 16 * 1024; - - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; - - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_interactive_session(); @@ -551,6 +566,8 @@ namespace xo { }; utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]") @@ -560,15 +577,8 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ArenaConfig config; - config.name_ = testname; - config.size_ = 16 * 1024; - - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; - - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_interactive_session(); @@ -590,6 +600,8 @@ namespace xo { }; utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-interactive-lambda2", "[reader2][SchematikaParser]") @@ -599,15 +611,8 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ArenaConfig config; - config.name_ = "test-arena"; - config.size_ = 16 * 1024; - - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; - - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_interactive_session(); @@ -636,6 +641,8 @@ namespace xo { }; utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-interactive-apply", "[reader2][SchematikaParser]") @@ -645,15 +652,8 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ArenaConfig config; - config.name_ = testname; - config.size_ = 16 * 1024; - - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; - - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_interactive_session(); @@ -687,6 +687,8 @@ namespace xo { }; utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); } TEST_CASE("SchematikaParser-interactive-apply2", "[reader2][SchematikaParser]") @@ -698,15 +700,8 @@ namespace xo { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ArenaConfig config; - config.name_ = "test-arena"; - config.size_ = 16 * 1024; - - DArena expr_arena = DArena::map(config); - obj expr_alloc = with_facet::mkobj(&expr_arena); - auto aux_alloc = expr_alloc; - - SchematikaParser parser(config, 4096, expr_alloc, aux_alloc, false /*debug_flag*/); + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); parser.begin_interactive_session(); @@ -750,7 +745,10 @@ namespace xo { }; utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); } + } /*namespace ut*/ } /*namespace xo*/ From ba7ec387cc7ecf5b2d24ba1f5bb7926bd15ec05a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Feb 2026 22:57:15 -0500 Subject: [PATCH 216/342] xo-reader2 stack: + TypeRegistry --- utest/SchematikaParser.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 5265922a..2f2272ab 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -78,7 +78,7 @@ namespace xo { bool log_memory_layout(scope * p_log) { auto visitor = [p_log](const MemorySizeInfo & info) { - *p_log && (*p_log)(xtag("resource", info.resource_name_), + *p_log && (*p_log)(xtag("name", info.resource_name_), xtag("used", info.used_), xtag("alloc", info.allocated_), xtag("commit", info.committed_), From fc9ca649dd8e266adf1c91969ecc25eb65125848 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Feb 2026 22:57:15 -0500 Subject: [PATCH 217/342] xo-reader2 stack: + TypeRegistry --- include/xo/reflectutil/type_name.hpp | 94 ++++++++++++++++++++++++++++ include/xo/reflectutil/typeseq.hpp | 89 +++++++++++++++++--------- 2 files changed, 153 insertions(+), 30 deletions(-) create mode 100644 include/xo/reflectutil/type_name.hpp diff --git a/include/xo/reflectutil/type_name.hpp b/include/xo/reflectutil/type_name.hpp new file mode 100644 index 00000000..bdce1b0a --- /dev/null +++ b/include/xo/reflectutil/type_name.hpp @@ -0,0 +1,94 @@ +/* @file type_name.hpp */ + +#pragma once + +//#include +#include +#include // std::array +#include // std::index_sequence + +namespace xo { + namespace reflect { + + template + constexpr auto + substring_as_array(std::string_view str, + std::index_sequence indexes) + { + //return std::array{str[Idxs]..., '\n'}; + return std::array{str[Idxs]...}; + } /*substring_as_array*/ + + template constexpr auto type_name_array() { +#if defined(__clang__) + constexpr auto prefix = std::string_view{"[T = "}; + constexpr auto suffix = std::string_view{"]"}; + constexpr auto function = std::string_view{__PRETTY_FUNCTION__}; +#elif defined(__GNUC__) + constexpr auto prefix = std::string_view{"with T = "}; + constexpr auto suffix = std::string_view{"]"}; + constexpr auto function = std::string_view{__PRETTY_FUNCTION__}; +#elif defined(_MSC_VER) + constexpr auto prefix = std::string_view{"type_name_array<"}; + constexpr auto suffix = std::string_view{">(void)"}; + constexpr auto function = std::string_view{__FUNCSIG__}; +#else +# error type_name_array: Unsupported compiler +#endif + + constexpr auto start = function.find(prefix) + prefix.size(); + constexpr auto end = function.rfind(suffix); + + //static_assert(start < end); + + constexpr auto name = function.substr(start, (end - start)); + + constexpr auto ixseq = std::make_index_sequence{}; + + return substring_as_array(name, ixseq); + } /*type_name_array*/ + + template + struct type_name_holder { + static inline constexpr auto value = type_name_array(); + }; + + /** report name of type T as a string_view; + * using constexpr deps so runs at **/ + template + constexpr auto type_name() -> std::string_view + { + constexpr auto& value = type_name_holder::value; + return std::string_view{value.data(), value.size()}; + } + +#ifdef NOT_IN_USE + template + struct join + { + // Join all strings into a single std::array of chars + static constexpr auto impl() noexcept + { + constexpr std::size_t len = (Strs.size() + ... + 0); + std::array arr{}; + auto append = [i = 0, &arr](auto const& s) mutable { + for (auto c : s) arr[i++] = c; + }; + (append(Strs), ...); + arr[len] = 0; + return arr; + } + // Give the joined string static storage + static constexpr auto arr = impl(); + // View as a std::string_view + static constexpr std::string_view value {arr.data(), arr.size() - 1}; + }; + + // Helper to get the value out + template + static constexpr auto join_v = join::value; +#endif + } /*namespace reflect*/ +} /*namespace xo*/ + +/* end type_name.hpp */ diff --git a/include/xo/reflectutil/typeseq.hpp b/include/xo/reflectutil/typeseq.hpp index d2f888cd..336f011c 100644 --- a/include/xo/reflectutil/typeseq.hpp +++ b/include/xo/reflectutil/typeseq.hpp @@ -5,22 +5,20 @@ #pragma once +#include "type_name.hpp" #include #include namespace xo { namespace reflect { - /** - * Tag here so we can preserve header-only implementation - * and still have static variable - */ - template - struct typeseq_impl { - /** create sentinel value **/ - typeseq_impl() = default; +// template + struct typerecd { + /** sentinel value **/ + typerecd() = default; - /** typeseq with specific unique id **/ - explicit typeseq_impl(int32_t s) : seqno_{s} {} + /** type-record with specific, unique id **/ + explicit typerecd(int32_t s, + std::string_view n) : seqno_{s}, name_{n} {} /** Can't have this be constexpr. * We need ids in shared libraries to be generated @@ -35,57 +33,88 @@ namespace xo { * when using clang. **/ template - static typeseq_impl id() { - static bool armed = true; + static typerecd recd() { + // reminder: {armed, id} are distint for each T + static bool s_armed = true; static int32_t id = 0; - if (armed) { - armed = false; - id = ++s_next_id; + if (s_armed) { + s_armed = false; + id = require_next_id(); } - return typeseq_impl(id); + return typerecd(id, xo::reflect::type_name()); } + static int32_t require_next_id() { + static int32_t s_next_id = 0; + return s_next_id++; + } + + int32_t seqno() const { return seqno_; } + std::string_view name() const { return name_; } + + /** sentinel typerecd instance **/ + static typerecd sentinel() { + return typerecd(-1, "_%sentinel%_"); + } + + private: + int32_t seqno_ = 0; + std::string_view name_; + }; + + //template + //int32_t typerecd_impl::s_next_id = 0; + + /** + * Tag here so we can preserve header-only implementation + * and still have static variable + */ + struct typeseq { + /** create sentinel value **/ + typeseq() = default; + + /** typeseq with specific unique id **/ + explicit typeseq(int32_t s) : seqno_{s} {} + /** 'anonymous' sentinel type. * Niche uses for this, e.g. untyped allocator **/ - static typeseq_impl anon() { - return typeseq_impl(-1); + static typeseq sentinel() { + return typeseq(typerecd::sentinel().seqno()); + } + + template + static typeseq id() { + return typeseq(xo::reflect::typerecd::recd().seqno()); } int32_t seqno() const { return seqno_; } private: - static int32_t s_next_id; - int32_t seqno_ = 0; }; - template - int32_t typeseq_impl::s_next_id = 0; + //template + //int32_t typeseq_impl::s_next_id = 0; - template inline bool - operator==(const typeseq_impl & lhs, const typeseq_impl & rhs) { + operator==(const typeseq & lhs, const typeseq & rhs) { return lhs.seqno() == rhs.seqno(); } - template inline bool - operator!=(const typeseq_impl & lhs, const typeseq_impl & rhs) { + operator!=(const typeseq & lhs, const typeseq & rhs) { return lhs.seqno() != rhs.seqno(); } - template inline std::ostream & - operator<<(std::ostream & s, const typeseq_impl & x) { + operator<<(std::ostream & s, const typeseq & x) { s << x.seqno(); return s; } - - using typeseq = typeseq_impl<>; } /*namespace reflect*/ } /*namespace xo*/ From 65bd5502ff9ee659a36d84db8bf35a59b0074d08 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 00:48:00 -0500 Subject: [PATCH 218/342] xo-expression2 stack: expand MemorySizeInfo w/ per-type detail --- utest/SchematikaParser.test.cpp | 62 +++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 2f2272ab..46385c56 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include namespace xo { @@ -55,17 +56,23 @@ namespace xo { ParserFixture(const std::string & testname, bool debug_flag) { this->aux_arena_ - = std::move(DArena(ArenaConfig().with_name(testname).with_size(4 * 1024))); + = std::move(DArena(ArenaConfig() + .with_name(testname) + .with_size(4 * 1024))); obj aux_mm(&aux_arena_); this->expr_arena_ = dp::make(aux_mm, - ArenaConfig().with_name("expr").with_size(16 * 1024)); + (ArenaConfig() + .with_name("expr") + .with_size(16 * 1024) + .with_store_header_flag(true))); obj expr_mm(expr_arena_.data()); ParserConfig cfg; cfg.parser_arena_config_.size_ = 16 * 1024; - cfg.symtab_config_.hint_max_capacity_ = 512; + /* editor bait: symbol table */ + cfg.symtab_config_.hint_max_capacity_ = 128; cfg.max_stringtable_capacity_ = 512; cfg.debug_flag_ = false; @@ -77,12 +84,32 @@ namespace xo { ParserFixture(const ParserFixture && other) = delete; bool log_memory_layout(scope * p_log) { + using xo::facet::TypeRegistry; + using xo::mm::MemorySizeDetail; + auto visitor = [p_log](const MemorySizeInfo & info) { - *p_log && (*p_log)(xtag("name", info.resource_name_), - xtag("used", info.used_), - xtag("alloc", info.allocated_), + *p_log && (*p_log)(xtag("name", info.resource_name_), + xtag("used", info.used_), + xtag("alloc", info.allocated_), xtag("commit", info.committed_), - xtag("resv", info.reserved_)); + xtag("resv", info.reserved_)); + if (*p_log && info.detail_) { + (*p_log)("detail", + xtag("n", (*info.detail_)[0].n_alloc_), + xtag("z", (*info.detail_)[0].z_alloc_)); + for (size_t i = 1; i < info.detail_->size(); ++i) { + const MemorySizeDetail & d = (*info.detail_)[i]; + + if (d.tseq_.is_sentinel()) + break; + + (*p_log)("[",i,"]", + xtag("tseq",d.tseq_), + xtag("type", TypeRegistry::id2name(d.tseq_)), + xtag("n", d.n_alloc_), + xtag("z", d.z_alloc_)); + } + } }; aux_arena_.visit_pools(visitor); @@ -144,14 +171,29 @@ namespace xo { REQUIRE(parser.debug_flag() == false); REQUIRE(parser.is_at_toplevel() == true); + // baseline: + // SchematikaParser-ctor :used 1408 + // facets-ctl :used 73 // facet hashtable + // facets-slots :used 1168 // facet hashtable + // expr :used 2056 + // [1] :type xo::scm::DArray :n 1 :z 2056 // DArray of DUniqueString* + // [2] :type ? :n 1 : z 16 + // strings :used 0 + // stringkeys-ctl :used 0 + // strinkeys-slots :used 0 + // parser-arena :used 0 + // global-symtab-ctl :used 0 + // global-symtab-slots :used 0 + log && fixture.log_memory_layout(&log); } - TEST_CASE("SchematikaParser-begin-interactive", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-begin-interactive", + "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; + constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -697,7 +739,7 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); From f655dbb86a2fac08bada154aed1902b8af2c926c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 00:48:00 -0500 Subject: [PATCH 219/342] xo-expression2 stack: expand MemorySizeInfo w/ per-type detail --- include/xo/reflectutil/typeseq.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/xo/reflectutil/typeseq.hpp b/include/xo/reflectutil/typeseq.hpp index 336f011c..d337cd5b 100644 --- a/include/xo/reflectutil/typeseq.hpp +++ b/include/xo/reflectutil/typeseq.hpp @@ -61,7 +61,7 @@ namespace xo { } private: - int32_t seqno_ = 0; + int32_t seqno_ = -1; std::string_view name_; }; @@ -91,10 +91,11 @@ namespace xo { return typeseq(xo::reflect::typerecd::recd().seqno()); } + bool is_sentinel() const { return seqno_ == -1; } int32_t seqno() const { return seqno_; } private: - int32_t seqno_ = 0; + int32_t seqno_ = -1; }; //template From 797970cdea2cf33fc3787748c3d0c8dfc866a6de Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 09:32:53 -0500 Subject: [PATCH 220/342] xo-expression2: register DGlobalSymtab type + rename --- include/xo/reader2/SchematikaReader.hpp | 2 +- src/reader2/SchematikaParser.cpp | 4 ++-- src/reader2/SchematikaReader.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index 73b8166b..5a4243a1 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -49,7 +49,7 @@ namespace xo { **/ SchematikaReader(const ReaderConfig & config, obj expr_alloc, - obj fixed_alloc); + obj aux_alloc); /** non-trivial dtor because of @p parser **/ ~SchematikaReader() = default; diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 48e109da..37ebdd05 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -22,12 +22,12 @@ namespace xo { SchematikaParser::SchematikaParser(const ParserConfig & cfg, obj expr_alloc, - obj fixed_alloc) + obj aux_alloc) : psm_{cfg.parser_arena_config_, cfg.symtab_config_, cfg.max_stringtable_capacity_, expr_alloc, - fixed_alloc}, + aux_alloc}, debug_flag_{cfg.debug_flag_} { } diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index e02eefa2..98d44112 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -11,7 +11,7 @@ namespace xo { namespace scm { SchematikaReader::SchematikaReader(const ReaderConfig & config, obj expr_alloc, - obj fixed_alloc) + obj aux_alloc) : tokenizer_{config.tk_buffer_config_, config.tk_debug_flag_}, parser_{ParserConfig(config.parser_arena_config_, @@ -19,7 +19,7 @@ namespace xo { config.max_stringtable_cap_, config.parser_debug_flag_), expr_alloc, - fixed_alloc}, + aux_alloc}, debug_flag_{config.reader_debug_flag_} { } From 6b7533559a4ddc28999ca75a9f1bc18a414d7843 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 09:33:51 -0500 Subject: [PATCH 221/342] xo-reader2: register SchematikaParser type --- src/reader2/reader2_register_facets.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index eb39f6ac..e45d542f 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -47,6 +47,7 @@ namespace xo { using xo::print::APrintable; using xo::facet::FacetRegistry; + using xo::facet::TypeRegistry; using xo::facet::typeseq; namespace scm { @@ -93,6 +94,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + // misc types showing up in aux arena + TypeRegistry::register_type(); + log && log(xtag("DExprSeqState.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); log && log(xtag("DLambdaSsm.tseq", typeseq::id())); From 4724a781a48dfc457dd2823b5578116b14015c54 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 09:34:06 -0500 Subject: [PATCH 222/342] xo-reader2: use alloc headers in utest for visibility --- src/reader2/reader2_register_facets.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index e45d542f..39e51a07 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -21,23 +21,29 @@ #include "SequenceSsm.hpp" #include "ParenSsm.hpp" +//#include #include #include +//#include #include #include +//#include #include #include +//#include #include #include -#include -#include +#include +//#include +//#include -#include -#include +#include +//#include +//#include #include #include From 37739467056716401f611b8b9a7582a5b33d741a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 09:34:40 -0500 Subject: [PATCH 223/342] xo-reader2: use alloc headers in utest for visibility --- src/reader2/reader2_register_facets.cpp | 10 ++++++++-- utest/SchematikaParser.test.cpp | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 39e51a07..ab279f56 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -5,15 +5,21 @@ #include "reader2_register_facets.hpp" +#include + +//#include #include #include +//#include #include #include -#include -#include +#include +//#include +//#include +//#include #include #include diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 46385c56..5d831b13 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -58,7 +58,8 @@ namespace xo { this->aux_arena_ = std::move(DArena(ArenaConfig() .with_name(testname) - .with_size(4 * 1024))); + .with_size(4 * 1024) + .with_store_header_flag(true))); obj aux_mm(&aux_arena_); this->expr_arena_ From 1cab3657704ba52ab085681016d2dd07c6c1a29e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 09:45:36 -0500 Subject: [PATCH 224/342] xo-reader2: + convenience headers --- include/xo/reader2/DefineSsm.hpp | 12 ++++++ include/xo/reader2/ExpectFormalArgSsm.hpp | 12 ++++++ include/xo/reader2/ExpectFormalArglistSsm.hpp | 12 ++++++ include/xo/reader2/ExpectSymbolSsm.hpp | 12 ++++++ include/xo/reader2/ExpectTypeSsm.hpp | 12 ++++++ include/xo/reader2/ExprSeqState.hpp | 12 ++++++ include/xo/reader2/IfElseSsm.hpp | 12 ++++++ src/reader2/reader2_register_facets.cpp | 42 ++++--------------- 8 files changed, 91 insertions(+), 35 deletions(-) create mode 100644 include/xo/reader2/DefineSsm.hpp create mode 100644 include/xo/reader2/ExpectFormalArgSsm.hpp create mode 100644 include/xo/reader2/ExpectFormalArglistSsm.hpp create mode 100644 include/xo/reader2/ExpectSymbolSsm.hpp create mode 100644 include/xo/reader2/ExpectTypeSsm.hpp create mode 100644 include/xo/reader2/ExprSeqState.hpp create mode 100644 include/xo/reader2/IfElseSsm.hpp diff --git a/include/xo/reader2/DefineSsm.hpp b/include/xo/reader2/DefineSsm.hpp new file mode 100644 index 00000000..4a4489a0 --- /dev/null +++ b/include/xo/reader2/DefineSsm.hpp @@ -0,0 +1,12 @@ +/** @file DefineSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DDefineSsm.hpp" +#include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" +#include "ssm/IPrintable_DDefineSsm.hpp" + +/* end DefineSsm.hpp */ diff --git a/include/xo/reader2/ExpectFormalArgSsm.hpp b/include/xo/reader2/ExpectFormalArgSsm.hpp new file mode 100644 index 00000000..f0aaa9ed --- /dev/null +++ b/include/xo/reader2/ExpectFormalArgSsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectFormalArgSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DExpectFormalArgSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" +#include "ssm/IPrintable_DExpectFormalArgSsm.hpp" + +/* end ExpectFormalArgSsm.hpp */ diff --git a/include/xo/reader2/ExpectFormalArglistSsm.hpp b/include/xo/reader2/ExpectFormalArglistSsm.hpp new file mode 100644 index 00000000..35ffcf04 --- /dev/null +++ b/include/xo/reader2/ExpectFormalArglistSsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectFormalArglistSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DExpectFormalArglistSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" +#include "ssm/IPrintable_DExpectFormalArglistSsm.hpp" + +/* end ExpectFormalArglistSsm.hpp */ diff --git a/include/xo/reader2/ExpectSymbolSsm.hpp b/include/xo/reader2/ExpectSymbolSsm.hpp new file mode 100644 index 00000000..66e44aef --- /dev/null +++ b/include/xo/reader2/ExpectSymbolSsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectSymbolSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DExpectSymbolSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp" +#include "ssm/IPrintable_DExpectSymbolSsm.hpp" + +/* end ExpectSymbolSsm.hpp */ diff --git a/include/xo/reader2/ExpectTypeSsm.hpp b/include/xo/reader2/ExpectTypeSsm.hpp new file mode 100644 index 00000000..2c189551 --- /dev/null +++ b/include/xo/reader2/ExpectTypeSsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectTypeSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DExpectTypeSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp" +#include "ssm/IPrintable_DExpectTypeSsm.hpp" + +/* end ExpectTypeSsm.hpp */ diff --git a/include/xo/reader2/ExprSeqState.hpp b/include/xo/reader2/ExprSeqState.hpp new file mode 100644 index 00000000..912650b9 --- /dev/null +++ b/include/xo/reader2/ExprSeqState.hpp @@ -0,0 +1,12 @@ +/** @file ExprSeqState.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DExprSeqState.hpp" +#include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" +#include "ssm/IPrintable_DExprSeqState.hpp" + +/* end ExprSeqState.hpp */ diff --git a/include/xo/reader2/IfElseSsm.hpp b/include/xo/reader2/IfElseSsm.hpp new file mode 100644 index 00000000..eaa6948d --- /dev/null +++ b/include/xo/reader2/IfElseSsm.hpp @@ -0,0 +1,12 @@ +/** @file IfElseSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DIfElseSsm.hpp" +#include "ssm/ISyntaxStateMachine_DIfElseSsm.hpp" +#include "ssm/IPrintable_DIfElseSsm.hpp" + +/* end IfElseSsm.hpp */ diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index ab279f56..4f5784e5 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -7,49 +7,21 @@ #include -//#include -#include -#include - -//#include -#include -#include - +#include +#include #include -//#include -//#include - -//#include -#include -#include +#include #include "ApplySsm.hpp" #include "SequenceSsm.hpp" #include "ParenSsm.hpp" -//#include -#include -#include - -//#include -#include -#include - -//#include -#include -#include - -//#include -#include -#include - +#include +#include +#include +#include #include -//#include -//#include - #include -//#include -//#include #include #include From ce655ed6bd9a098172bf1d03fe3eb031c511b053 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 09:49:11 -0500 Subject: [PATCH 225/342] xo-reader2: code layout - include file spelling --- include/xo/reader2/.gitkeep | 0 src/reader2/reader2_register_facets.cpp | 27 +++++++++++-------------- 2 files changed, 12 insertions(+), 15 deletions(-) delete mode 100644 include/xo/reader2/.gitkeep diff --git a/include/xo/reader2/.gitkeep b/include/xo/reader2/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 4f5784e5..7a653954 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -5,25 +5,22 @@ #include "reader2_register_facets.hpp" -#include - -#include -#include -#include -#include - +#include "SchematikaParser.hpp" +#include "ExprSeqState.hpp" +#include "DefineSsm.hpp" +#include "LambdaSsm.hpp" +#include "IfElseSsm.hpp" #include "ApplySsm.hpp" #include "SequenceSsm.hpp" #include "ParenSsm.hpp" +#include "ExpectFormalArglistSsm.hpp" +#include "ExpectFormalArgSsm.hpp" +#include "ExpectSymbolSsm.hpp" +#include "ExpectTypeSsm.hpp" +#include "ExpectExprSsm.hpp" +#include "ProgressSsm.hpp" +#include "SyntaxStateMachine.hpp" -#include -#include -#include -#include -#include -#include - -#include #include #include #include From 66d9bc5cd6ed26c4f8e6ce5fcc6a26d755a5fc73 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 11:03:09 -0500 Subject: [PATCH 226/342] xo-reader2: bugfix: checkpoint before allocating SSMs --- include/xo/reader2/DDefineSsm.hpp | 8 ++++++-- include/xo/reader2/DParenSsm.hpp | 5 ++++- include/xo/reader2/ParserStack.hpp | 4 +++- include/xo/reader2/ParserStateMachine.hpp | 6 ++++-- src/reader2/DApplySsm.cpp | 6 +++--- src/reader2/DDefineSsm.cpp | 20 +++++++++++++------- src/reader2/DExpectExprSsm.cpp | 4 +++- src/reader2/DExpectFormalArgSsm.cpp | 4 +++- src/reader2/DExpectFormalArglistSsm.cpp | 4 +++- src/reader2/DExpectSymbolSsm.cpp | 4 +++- src/reader2/DExpectTypeSsm.cpp | 4 +++- src/reader2/DIfElseSsm.cpp | 4 +++- src/reader2/DLambdaSsm.cpp | 4 +++- src/reader2/DParenSsm.cpp | 14 ++++++++++---- src/reader2/DProgressSsm.cpp | 6 +++--- src/reader2/DSequenceSsm.cpp | 6 ++++-- src/reader2/ParserStack.cpp | 3 ++- src/reader2/ParserStateMachine.cpp | 8 +++++--- 18 files changed, 78 insertions(+), 36 deletions(-) diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index d42246ef..6380a233 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -87,8 +87,12 @@ namespace xo { /** create instance using memory from @p parser_mm. * Initial expression scaffold @p def_expr **/ - static DDefineSsm * make(DArena & parser_mm, - DDefineExpr * def_expr); + static DDefineSsm * _make(DArena & parser_mm, + DDefineExpr * def_expr); + + /** create fop referring to new DDefineSsm **/ + static obj make(DArena & parser_mm, + DDefineExpr * def_expr); /** start nested parser for a define-expression, * on top of parser state machine @p p_psm diff --git a/include/xo/reader2/DParenSsm.hpp b/include/xo/reader2/DParenSsm.hpp index 6f359b65..818e0470 100644 --- a/include/xo/reader2/DParenSsm.hpp +++ b/include/xo/reader2/DParenSsm.hpp @@ -62,7 +62,10 @@ namespace xo { /** create instance using memory from @p parser_mm **/ - static DParenSsm * make(DArena & parser_mm); + static DParenSsm * _make(DArena & parser_mm); + + /** create fop pointing with new DParenSsm using memory from @p parser_mm **/ + static obj make(DArena & parser_mm); /** push DParenSsm instance onto @p p_psm stack **/ static void start(ParserStateMachine * p_psm); diff --git a/include/xo/reader2/ParserStack.hpp b/include/xo/reader2/ParserStack.hpp index 936c57e5..ef5705e9 100644 --- a/include/xo/reader2/ParserStack.hpp +++ b/include/xo/reader2/ParserStack.hpp @@ -30,9 +30,11 @@ namespace xo { ParserStack * parent); /** create new top of stack for syntax @p ssm, using memory from @p mm. - * previous stack given by @p parent + * previous stack given by @p parent. + * Checkpoint @p ckp will refer to stack _before_ allocating @p ssm **/ static ParserStack * push(ParserStack * stack, + DArena::Checkpoint ckp, DArena & mm, obj ssm); diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 97c8c6e5..2dfba437 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -97,8 +97,10 @@ namespace xo { /** establish toplevel @p ssm. Must have empty stack **/ void establish_toplevel_ssm(obj ssm); - /** push syntax @p ssm onto @ref stack_ **/ - void push_ssm(obj ssm); + /** push syntax @p ssm onto @ref stack_, restore parser stack to @p ckp + * when popped + **/ + void push_ssm(DArena::Checkpoint ckp, obj ssm); /** pop syntax state machine from top of @ref stack_ **/ void pop_ssm(); diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index 4cd3aaec..a741ce4b 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -89,14 +89,14 @@ namespace xo { { scope log(XO_DEBUG(p_psm->debug_flag())); + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + DApplySsm * apply_ssm = DApplySsm::make(p_psm->parser_alloc(), fn_expr); obj ssm(apply_ssm); - p_psm->push_ssm(ssm); - //OBSOLETE //p_psm->top_exprstate().on_expr(fn_expr.get(), p_psm); - //OBSOLETE //p_psm->on_token(token_type::leftparen(), p_psm); + p_psm->push_ssm(ckp, ssm); } syntaxstatetype diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 2d2ecb0b..78e29250 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -343,8 +343,8 @@ namespace xo { {} DDefineSsm * - DDefineSsm::make(DArena & mm, - DDefineExpr * def_expr) + DDefineSsm::_make(DArena & mm, + DDefineExpr * def_expr) { void * mem = mm.alloc(typeseq::id(), sizeof(DDefineSsm)); @@ -352,6 +352,13 @@ namespace xo { return new (mem) DDefineSsm(def_expr); } + obj + DDefineSsm::make(DArena & mm, + DDefineExpr * def_expr) + { + return obj(_make(mm, def_expr)); + } + void DDefineSsm::start(DArena & mm, obj expr_mm, @@ -361,14 +368,13 @@ namespace xo { assert(p_psm->stack()); + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + DDefineExpr * def_expr = DDefineExpr::make_empty(expr_mm); - DDefineSsm * define_ssm = DDefineSsm::make(mm, def_expr); + auto define_ssm = DDefineSsm::make(mm, def_expr); - obj ssm - = with_facet::mkobj(define_ssm); - - p_psm->push_ssm(ssm); + p_psm->push_ssm(ckp, define_ssm); // note: triggers poly dispatch p_psm->on_token(Token::def_token()); diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index c763e2a4..767df9bf 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -69,6 +69,8 @@ namespace xo { bool cxl_on_rightbrace, ParserStateMachine * p_psm) { + DArena::Checkpoint ckp = mm.checkpoint(); + DExpectExprSsm * exp_expr = DExpectExprSsm::make(mm, allow_defs, @@ -76,7 +78,7 @@ namespace xo { obj ssm = with_facet::mkobj(exp_expr); - p_psm->push_ssm(ssm); + p_psm->push_ssm(ckp, ssm); } void diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index d865cd71..47d55f6a 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -56,7 +56,9 @@ namespace xo { void DExpectFormalArgSsm::start(ParserStateMachine * p_psm) { - p_psm->push_ssm(DExpectFormalArgSsm::make(p_psm->parser_alloc())); + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DExpectFormalArgSsm::make(p_psm->parser_alloc())); DExpectSymbolSsm::start(p_psm); } diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 5f609807..3ce11ae8 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -87,7 +87,9 @@ namespace xo { void DExpectFormalArglistSsm::start(ParserStateMachine * p_psm) { - p_psm->push_ssm(DExpectFormalArglistSsm::make(p_psm->parser_alloc())); + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DExpectFormalArglistSsm::make(p_psm->parser_alloc())); } syntaxstatetype diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index b252055b..6f289edd 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -31,6 +31,8 @@ namespace xo { void DExpectSymbolSsm::start(ParserStateMachine * p_psm) { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + DExpectSymbolSsm * sym_ssm = DExpectSymbolSsm::make(p_psm->parser_alloc()); @@ -40,7 +42,7 @@ namespace xo { obj ssm = with_facet::mkobj(sym_ssm); - p_psm->push_ssm(ssm); + p_psm->push_ssm(ckp, ssm); } syntaxstatetype diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index f7ee3689..412a5cab 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -34,13 +34,15 @@ namespace xo { void DExpectTypeSsm::start(ParserStateMachine * p_psm) { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + DExpectTypeSsm * expect_type_ssm = DExpectTypeSsm::make(p_psm->parser_alloc()); auto ssm = with_facet::mkobj(expect_type_ssm); - p_psm->push_ssm(ssm); + p_psm->push_ssm(ckp, ssm); } syntaxstatetype diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index ccf4705f..521a59a1 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -70,13 +70,15 @@ namespace xo { { scope log(XO_DEBUG(p_psm->debug_flag())); + DArena::Checkpoint ckp = parser_mm.checkpoint(); + DIfElseExpr * if_expr = DIfElseExpr::_make_empty(expr_mm); DIfElseSsm * if_ssm = DIfElseSsm::_make(parser_mm, if_expr); obj ssm = with_facet::mkobj(if_ssm); - p_psm->push_ssm(ssm); + p_psm->push_ssm(ckp, ssm); // note: triggers poly dispatch p_psm->on_token(Token::if_token()); diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index a2c2dfbd..6308ae08 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -78,7 +78,9 @@ namespace xo { void DLambdaSsm::start(ParserStateMachine * p_psm) { - p_psm->push_ssm(DLambdaSsm::make(p_psm->parser_alloc())); + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DLambdaSsm::make(p_psm->parser_alloc())); p_psm->on_token(Token::lambda_token()); } diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index 972d503a..ad86ddd5 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -40,7 +40,7 @@ namespace xo { {} DParenSsm * - DParenSsm::make(DArena & mm) + DParenSsm::_make(DArena & mm) { void * mem = mm.alloc(typeseq::id(), sizeof(DParenSsm)); @@ -48,14 +48,20 @@ namespace xo { return new (mem) DParenSsm(); } + obj + DParenSsm::make(DArena & mm) + { + return obj(_make(mm)); + } + void DParenSsm::start(ParserStateMachine * p_psm) { - DParenSsm * paren_ssm = DParenSsm::make(p_psm->parser_alloc()); + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); - auto ssm = with_facet::mkobj(paren_ssm); + auto paren_ssm = DParenSsm::make(p_psm->parser_alloc()); - p_psm->push_ssm(ssm); + p_psm->push_ssm(ckp, paren_ssm); } syntaxstatetype diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 94efb30d..e4cdf46b 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -164,12 +164,14 @@ namespace xo { optype op, ParserStateMachine * p_psm) { + DArena::Checkpoint ckp = parser_mm.checkpoint(); + DProgressSsm * progress_ssm = DProgressSsm::make(parser_mm, lhs, op); obj ssm(progress_ssm); - p_psm->push_ssm(ssm); + p_psm->push_ssm(ckp, ssm); } void @@ -324,8 +326,6 @@ namespace xo { { scope log(XO_DEBUG(p_psm->debug_flag())); - (void)tk; - obj expr = this->assemble_expr(p_psm); p_psm->pop_ssm(); // completes self diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index 7a65d60d..87460804 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -22,8 +22,10 @@ namespace xo { void DSequenceSsm::start(ParserStateMachine * p_psm) { - p_psm->push_ssm(DSequenceSsm::make(p_psm->parser_alloc(), - p_psm->expr_alloc())); + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DSequenceSsm::make(p_psm->parser_alloc(), + p_psm->expr_alloc())); /* want to accept anything that starts an expression, * except that rightbrace '}' ends it */ diff --git a/src/reader2/ParserStack.cpp b/src/reader2/ParserStack.cpp index e3ffb290..9ab919b2 100644 --- a/src/reader2/ParserStack.cpp +++ b/src/reader2/ParserStack.cpp @@ -22,11 +22,12 @@ namespace xo { ParserStack * ParserStack::push(ParserStack * stack, + DArena::Checkpoint ckp, DArena & mm, obj ssm) { - DArena::Checkpoint ckp = mm.checkpoint(); + //DArena::Checkpoint ckp = mm.checkpoint(); // wrong, must precede allocation of ssm void * mem = mm.alloc(typeseq::id(), sizeof(ParserStack)); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index bbb4841e..1223abe2 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -75,18 +75,20 @@ namespace xo { assert(stack_ == nullptr); - this->stack_ = ParserStack::push(nullptr /*stack*/, parser_alloc_, ssm); + DArena::Checkpoint ckp = parser_alloc_.checkpoint(); + + this->stack_ = ParserStack::push(nullptr /*stack*/, ckp, parser_alloc_, ssm); this->parser_alloc_ckp_ = parser_alloc_.checkpoint(); } void - ParserStateMachine::push_ssm(obj ssm) + ParserStateMachine::push_ssm(DArena::Checkpoint ckp, obj ssm) { scope log(XO_DEBUG(debug_flag_)); // note: using parser_alloc_ for parser stack, since stacklike behavior - this->stack_ = ParserStack::push(stack_, parser_alloc_, ssm); + this->stack_ = ParserStack::push(stack_, ckp, parser_alloc_, ssm); } void From 8a4f1db08d74a83fb11fe8359f1c4bfa5e30c234 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 11:03:36 -0500 Subject: [PATCH 227/342] xo-reader2: enable alloc headers for parser stack --- include/xo/reader2/ParserConfig.hpp | 2 +- src/reader2/reader2_register_facets.cpp | 2 ++ utest/SchematikaParser.test.cpp | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/xo/reader2/ParserConfig.hpp b/include/xo/reader2/ParserConfig.hpp index ce781b16..080238c7 100644 --- a/include/xo/reader2/ParserConfig.hpp +++ b/include/xo/reader2/ParserConfig.hpp @@ -20,7 +20,7 @@ namespace xo { ArenaConfig parser_arena_config_ { .name_ = "parser-arena", .size_ = 2*1024*1024, .hugepage_z_ = 2*1024*1024, - .store_header_flag_ = false, + .store_header_flag_ = true, .header_{}, .debug_flag_ = false }; diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 7a653954..845b8d8e 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -77,6 +77,8 @@ namespace xo { // misc types showing up in aux arena TypeRegistry::register_type(); + // misc types showing up in parser stack arena + TypeRegistry::register_type(); log && log(xtag("DExprSeqState.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 5d831b13..a0557fa6 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -194,7 +194,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -740,7 +740,7 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; + constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); From 52247994791bbebca48bf536e59f85c6794cccf0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 11:08:21 -0500 Subject: [PATCH 228/342] xo-reader2: bugfix: move toplevel ExprSeqState to parser stack --- include/xo/reader2/DExprSeqState.hpp | 5 +++-- src/reader2/DExprSeqState.cpp | 9 +++++---- src/reader2/SchematikaParser.cpp | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index 83448b5e..150303c6 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -41,16 +41,17 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; public: explicit DExprSeqState(exprseqtype ty); /** start interactive top-level session **/ - static void establish_interactive(obj mm, + static void establish_interactive(DArena & mm, ParserStateMachine * p_psm); /** start non-interactive top-level session **/ - static void establish_batch(obj mm, + static void establish_batch(DArena & mm, ParserStateMachine * p_psm); public: diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 1d9b38a3..8261b506 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -35,6 +35,7 @@ namespace xo { using xo::scm::DFloat; using xo::mm::AGCObject; using xo::mm::AAllocator; + using xo::mm::DArena; using xo::facet::with_facet; using xo::reflect::typeseq; @@ -59,7 +60,7 @@ namespace xo { namespace { obj - make_exprseq_ssm(obj mm, + make_exprseq_ssm(DArena & mm, exprseqtype seqtype) { void * mem = mm.alloc(typeseq::id(), @@ -67,12 +68,12 @@ namespace xo { DExprSeqState * ssm = new (mem) DExprSeqState(seqtype); - return with_facet::mkobj(ssm); + return obj(ssm); } } void - DExprSeqState::establish_interactive(obj mm, + DExprSeqState::establish_interactive(DArena & mm, ParserStateMachine * p_psm) { p_psm->establish_toplevel_ssm(make_exprseq_ssm @@ -81,7 +82,7 @@ namespace xo { } void - DExprSeqState::establish_batch(obj mm, + DExprSeqState::establish_batch(DArena & mm, ParserStateMachine * p_psm) { p_psm->establish_toplevel_ssm(make_exprseq_ssm diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 37ebdd05..3a30b18a 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -65,14 +65,14 @@ namespace xo { void SchematikaParser::begin_interactive_session() { - DExprSeqState::establish_interactive(psm_.expr_alloc(), &psm_); + DExprSeqState::establish_interactive(psm_.parser_alloc(), &psm_); } void SchematikaParser::begin_batch_session() { - DExprSeqState::establish_batch(psm_.expr_alloc(), &psm_); + DExprSeqState::establish_batch(psm_.parser_alloc(), &psm_); } const ParserResult & From da58e187796500c0d4811863472c76b6214d8066 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 11:15:30 -0500 Subject: [PATCH 229/342] xo-reader2: rename DExprSeqState -> DToplevelSeqSsm --- CMakeLists.txt | 12 ++-- DESIGN.md | 2 +- ...json5 => IPrintable_DToplevelSeqSsm.json5} | 6 +- ...ISyntaxStateMachine_DToplevelSeqSsm.json5} | 6 +- ...{DExprSeqState.hpp => DToplevelSeqSsm.hpp} | 14 ++-- include/xo/reader2/ExprSeqState.hpp | 12 ---- include/xo/reader2/ToplevelSeqSsm.hpp | 12 ++++ ...ate.hpp => IPrintable_DToplevelSeqSsm.hpp} | 22 +++--- ...> ISyntaxStateMachine_DToplevelSeqSsm.hpp} | 38 +++++----- include/xo/reader2/syntaxstatetype.hpp | 2 +- src/reader2/CMakeLists.txt | 6 +- ...{DExprSeqState.cpp => DToplevelSeqSsm.cpp} | 64 ++++++++--------- ...ate.cpp => IPrintable_DToplevelSeqSsm.cpp} | 12 ++-- .../ISyntaxStateMachine_DExprSeqState.cpp | 69 ------------------- .../ISyntaxStateMachine_DToplevelSeqSsm.cpp | 69 +++++++++++++++++++ src/reader2/SchematikaParser.cpp | 6 +- src/reader2/reader2_register_facets.cpp | 8 +-- 17 files changed, 180 insertions(+), 180 deletions(-) rename idl/{IPrintable_DExprSeqState.json5 => IPrintable_DToplevelSeqSsm.json5} (64%) rename idl/{ISyntaxStateMachine_DExprSeqState.json5 => ISyntaxStateMachine_DToplevelSeqSsm.json5} (62%) rename include/xo/reader2/{DExprSeqState.hpp => DToplevelSeqSsm.hpp} (93%) delete mode 100644 include/xo/reader2/ExprSeqState.hpp create mode 100644 include/xo/reader2/ToplevelSeqSsm.hpp rename include/xo/reader2/ssm/{IPrintable_DExprSeqState.hpp => IPrintable_DToplevelSeqSsm.hpp} (68%) rename include/xo/reader2/ssm/{ISyntaxStateMachine_DExprSeqState.hpp => ISyntaxStateMachine_DToplevelSeqSsm.hpp} (54%) rename src/reader2/{DExprSeqState.cpp => DToplevelSeqSsm.cpp} (87%) rename src/reader2/{IPrintable_DExprSeqState.cpp => IPrintable_DToplevelSeqSsm.cpp} (54%) delete mode 100644 src/reader2/ISyntaxStateMachine_DExprSeqState.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bfc86f1..b2153df4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,11 +38,11 @@ xo_add_genfacet( # note: manual target; generated code committed to git xo_add_genfacetimpl( - TARGET xo-reader2-facetimpl-syntaxstatemachine-exprseqstate + TARGET xo-reader2-facetimpl-syntaxstatemachine-toplevelseqssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ExprSeqState - INPUT idl/ISyntaxStateMachine_DExprSeqState.json5 + REPR ToplevelSeqSsm + INPUT idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm OUTPUT_CPP_DIR src/reader2 @@ -50,11 +50,11 @@ xo_add_genfacetimpl( # note: manual target; generated code committed to git xo_add_genfacetimpl( - TARGET xo-reader2-facetimpl-printable-exprseqstate + TARGET xo-reader2-facetimpl-printable-toplevelseqssm FACET_PKG xo_printable2 FACET Printable - REPR ExprSeqState - INPUT idl/IPrintable_DExprSeqState.json5 + REPR ToplevelSeqSsm + INPUT idl/IPrintable_DToplevelSeqSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm OUTPUT_CPP_DIR src/reader2 diff --git a/DESIGN.md b/DESIGN.md index 69596c44..73e863e3 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -7,6 +7,6 @@ Composition of nested state machines. a state machine dedicated to some particular Schematika syntax. Examples: if-expression, type declaration, function call -## DExprSeqState +## DToplevelSeqSsm top-level expression sequence diff --git a/idl/IPrintable_DExprSeqState.json5 b/idl/IPrintable_DToplevelSeqSsm.json5 similarity index 64% rename from idl/IPrintable_DExprSeqState.json5 rename to idl/IPrintable_DToplevelSeqSsm.json5 index d0315c58..0c0f0200 100644 --- a/idl/IPrintable_DExprSeqState.json5 +++ b/idl/IPrintable_DToplevelSeqSsm.json5 @@ -6,8 +6,8 @@ namespace1: "xo", namespace2: "scm", facet_idl: "idl/Printable.json5", - brief: "provide APrintable interface for DExprSeqState", + brief: "provide APrintable interface for DToplevelSeqSsm", using_doxygen: true, - repr: "DExprSeqState", - doc: [ "implement APrintable for DExprSeqState" ], + repr: "DToplevelSeqSsm", + doc: [ "implement APrintable for DToplevelSeqSsm" ], } diff --git a/idl/ISyntaxStateMachine_DExprSeqState.json5 b/idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 similarity index 62% rename from idl/ISyntaxStateMachine_DExprSeqState.json5 rename to idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 index 0d0cdcac..f13b3137 100644 --- a/idl/ISyntaxStateMachine_DExprSeqState.json5 +++ b/idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 @@ -6,8 +6,8 @@ namespace1: "xo", namespace2: "scm", facet_idl: "idl/SyntaxStateMachine.json5", - brief: "provide ASyntaxStateMachine interface for DExprSeqState", + brief: "provide ASyntaxStateMachine interface for DToplevelSeqSsm", using_doxygen: true, - repr: "DExprSeqState", - doc: [ "implement ASyntaxStateMachine for DExprSeqState" ], + repr: "DToplevelSeqSsm", + doc: [ "implement ASyntaxStateMachine for DToplevelSeqSsm" ], } diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DToplevelSeqSsm.hpp similarity index 93% rename from include/xo/reader2/DExprSeqState.hpp rename to include/xo/reader2/DToplevelSeqSsm.hpp index 150303c6..743d2133 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DToplevelSeqSsm.hpp @@ -1,4 +1,4 @@ -/** @file DExprSeqState.hpp +/** @file DToplevelSeqSsm.hpp * * @author Roland Conybeare, Jan 2026 **/ @@ -31,21 +31,21 @@ namespace xo { return os; } - /** @class DExprSeqState + /** @class DToplevelSeqSsm * @brief state machine for parsing a sequence of expression * * Similar to exprseq_xs in xo-expresion **/ - class DExprSeqState : public DSyntaxStateMachine { + class DToplevelSeqSsm : public DSyntaxStateMachine { public: - using Super = DSyntaxStateMachine; + using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; public: - explicit DExprSeqState(exprseqtype ty); + explicit DToplevelSeqSsm(exprseqtype ty); /** start interactive top-level session **/ static void establish_interactive(DArena & mm, @@ -55,7 +55,7 @@ namespace xo { ParserStateMachine * p_psm); public: - static const char * ssm_classname() { return "DExprSeqState"; } + static const char * ssm_classname() { return "DToplevelSeqSsm"; } /** @defgroup scm-exprseq-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -152,4 +152,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end DExprSeqState.hpp */ +/* end DToplevelSeqSsm.hpp */ diff --git a/include/xo/reader2/ExprSeqState.hpp b/include/xo/reader2/ExprSeqState.hpp deleted file mode 100644 index 912650b9..00000000 --- a/include/xo/reader2/ExprSeqState.hpp +++ /dev/null @@ -1,12 +0,0 @@ -/** @file ExprSeqState.hpp - * - * @author Roland Conybeare, Feb 2026 - **/ - -#pragma once - -#include "DExprSeqState.hpp" -#include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" -#include "ssm/IPrintable_DExprSeqState.hpp" - -/* end ExprSeqState.hpp */ diff --git a/include/xo/reader2/ToplevelSeqSsm.hpp b/include/xo/reader2/ToplevelSeqSsm.hpp new file mode 100644 index 00000000..35cd8362 --- /dev/null +++ b/include/xo/reader2/ToplevelSeqSsm.hpp @@ -0,0 +1,12 @@ +/** @file ToplevelSeqSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DToplevelSeqSsm.hpp" +#include "ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp" +#include "ssm/IPrintable_DToplevelSeqSsm.hpp" + +/* end ToplevelSeqSsm.hpp */ diff --git a/include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp b/include/xo/reader2/ssm/IPrintable_DToplevelSeqSsm.hpp similarity index 68% rename from include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp rename to include/xo/reader2/ssm/IPrintable_DToplevelSeqSsm.hpp index 0dd14190..d411a87e 100644 --- a/include/xo/reader2/ssm/IPrintable_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/IPrintable_DToplevelSeqSsm.hpp @@ -1,14 +1,14 @@ -/** @file IPrintable_DExprSeqState.hpp +/** @file IPrintable_DToplevelSeqSsm.hpp * * Generated automagically from ingredients: * 1. code generator: * [xo-facet/codegen/genfacet] * arguments: - * --input [idl/IPrintable_DExprSeqState.json5] + * --input [idl/IPrintable_DToplevelSeqSsm.json5] * 2. jinja2 template for abstract facet .hpp file: * [iface_facet_repr.hpp.j2] * 3. idl for facet methods - * [idl/IPrintable_DExprSeqState.json5] + * [idl/IPrintable_DToplevelSeqSsm.json5] **/ #pragma once @@ -16,28 +16,28 @@ #include "Printable.hpp" #include #include -#include "DExprSeqState.hpp" +#include "DToplevelSeqSsm.hpp" -namespace xo { namespace scm { class IPrintable_DExprSeqState; } } +namespace xo { namespace scm { class IPrintable_DToplevelSeqSsm; } } namespace xo { namespace facet { template <> struct FacetImplementation + xo::scm::DToplevelSeqSsm> { using ImplType = xo::print::IPrintable_Xfer - ; + ; }; } } namespace xo { namespace scm { - /** @class IPrintable_DExprSeqState + /** @class IPrintable_DToplevelSeqSsm **/ - class IPrintable_DExprSeqState { + class IPrintable_DToplevelSeqSsm { public: /** @defgroup scm-printable-dexprseqstate-type-traits **/ ///@{ @@ -50,7 +50,7 @@ namespace xo { // const methods /** Pretty-printing support for this object. See [xo-indentlog/xo/indentlog/pretty.hpp] **/ - static bool pretty(const DExprSeqState & self, const ppindentinfo & ppii); + static bool pretty(const DToplevelSeqSsm & self, const ppindentinfo & ppii); // non-const methods ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp similarity index 54% rename from include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp rename to include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp index cfb92548..3bf58e17 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp @@ -1,14 +1,14 @@ -/** @file ISyntaxStateMachine_DExprSeqState.hpp +/** @file ISyntaxStateMachine_DToplevelSeqSsm.hpp * * Generated automagically from ingredients: * 1. code generator: * [xo-facet/codegen/genfacet] * arguments: - * --input [idl/ISyntaxStateMachine_DExprSeqState.json5] + * --input [idl/ISyntaxStateMachine_DToplevelSeqSsm.json5] * 2. jinja2 template for abstract facet .hpp file: * [iface_facet_repr.hpp.j2] * 3. idl for facet methods - * [idl/ISyntaxStateMachine_DExprSeqState.json5] + * [idl/ISyntaxStateMachine_DToplevelSeqSsm.json5] **/ #pragma once @@ -16,28 +16,28 @@ #include "SyntaxStateMachine.hpp" #include "SyntaxStateMachine.hpp" #include "ssm/ISyntaxStateMachine_Xfer.hpp" -#include "DExprSeqState.hpp" +#include "DToplevelSeqSsm.hpp" -namespace xo { namespace scm { class ISyntaxStateMachine_DExprSeqState; } } +namespace xo { namespace scm { class ISyntaxStateMachine_DToplevelSeqSsm; } } namespace xo { namespace facet { template <> struct FacetImplementation + xo::scm::DToplevelSeqSsm> { using ImplType = xo::scm::ISyntaxStateMachine_Xfer - ; + ; }; } } namespace xo { namespace scm { - /** @class ISyntaxStateMachine_DExprSeqState + /** @class ISyntaxStateMachine_DToplevelSeqSsm **/ - class ISyntaxStateMachine_DExprSeqState { + class ISyntaxStateMachine_DToplevelSeqSsm { public: /** @defgroup scm-syntaxstatemachine-dexprseqstate-type-traits **/ ///@{ @@ -49,25 +49,25 @@ namespace xo { ///@{ // const methods /** identify a type of syntax state machine **/ - static syntaxstatetype ssm_type(const DExprSeqState & self) noexcept; + static syntaxstatetype ssm_type(const DToplevelSeqSsm & self) noexcept; /** text describing expected/allowed input to this ssm in current state **/ - static std::string_view get_expect_str(const DExprSeqState & self) noexcept; + static std::string_view get_expect_str(const DToplevelSeqSsm & self) noexcept; // non-const methods /** operate state machine for incoming token @p tk **/ - static void on_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); + static void on_token(DToplevelSeqSsm & self, const Token & tk, ParserStateMachine * p_psm); /** update stat machine for incoming parsed symbol @p sym **/ - static void on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm); + static void on_parsed_symbol(DToplevelSeqSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ - static void on_parsed_typedescr(DExprSeqState & self, TypeDescr td, ParserStateMachine * p_psm); + static void on_parsed_typedescr(DToplevelSeqSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ - static void on_parsed_formal(DExprSeqState & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + static void on_parsed_formal(DToplevelSeqSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ - static void on_parsed_formal_arglist(DExprSeqState & self, DArray * arglist, ParserStateMachine * p_psm); + static void on_parsed_formal_arglist(DToplevelSeqSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ - static void on_parsed_expression(DExprSeqState & self, obj expr, ParserStateMachine * p_psm); + static void on_parsed_expression(DToplevelSeqSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ - static void on_parsed_expression_with_token(DExprSeqState & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + static void on_parsed_expression_with_token(DToplevelSeqSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 147b7770..957272e8 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -39,7 +39,7 @@ namespace xo { /** expression enclosed in parentheses. See @ref DParenSsm **/ paren, - /** toplevel of some translation unit. See @ref DExprSeqState **/ + /** toplevel of some translation unit. See @ref DToplevelSeqSsm **/ expect_toplevel_expression_sequence, /** expecting a formal argument list (sub-syntax within lambda-expression) **/ diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 5c98e209..6ad71cdf 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -17,9 +17,9 @@ set(SELF_SRCS syntaxstatetype.cpp ISyntaxStateMachine_Any.cpp - DExprSeqState.cpp - ISyntaxStateMachine_DExprSeqState.cpp - IPrintable_DExprSeqState.cpp + DToplevelSeqSsm.cpp + ISyntaxStateMachine_DToplevelSeqSsm.cpp + IPrintable_DToplevelSeqSsm.cpp DDefineSsm.cpp ISyntaxStateMachine_DDefineSsm.cpp diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DToplevelSeqSsm.cpp similarity index 87% rename from src/reader2/DExprSeqState.cpp rename to src/reader2/DToplevelSeqSsm.cpp index 8261b506..e294d078 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -1,10 +1,10 @@ -/** @file DExprSeqState.cpp +/** @file DToplevelSeqSsm.cpp * * @author Roland Conybeare, Jan 2026 **/ -#include "DExprSeqState.hpp" -#include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" +#include "DToplevelSeqSsm.hpp" +#include "ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp" #include "DDefineSsm.hpp" #include "DLambdaSsm.hpp" #include "ProgressSsm.hpp" @@ -55,7 +55,7 @@ namespace xo { return "exprseqtype?"; } - DExprSeqState::DExprSeqState(exprseqtype ty) : seqtype_{ty} + DToplevelSeqSsm::DToplevelSeqSsm(exprseqtype ty) : seqtype_{ty} {} namespace { @@ -63,17 +63,17 @@ namespace xo { make_exprseq_ssm(DArena & mm, exprseqtype seqtype) { - void * mem = mm.alloc(typeseq::id(), - sizeof(DExprSeqState)); + void * mem = mm.alloc(typeseq::id(), + sizeof(DToplevelSeqSsm)); - DExprSeqState * ssm = new (mem) DExprSeqState(seqtype); + DToplevelSeqSsm * ssm = new (mem) DToplevelSeqSsm(seqtype); - return obj(ssm); + return obj(ssm); } } void - DExprSeqState::establish_interactive(DArena & mm, + DToplevelSeqSsm::establish_interactive(DArena & mm, ParserStateMachine * p_psm) { p_psm->establish_toplevel_ssm(make_exprseq_ssm @@ -82,7 +82,7 @@ namespace xo { } void - DExprSeqState::establish_batch(DArena & mm, + DToplevelSeqSsm::establish_batch(DArena & mm, ParserStateMachine * p_psm) { p_psm->establish_toplevel_ssm(make_exprseq_ssm @@ -93,13 +93,13 @@ namespace xo { // SyntaxStateMachine facet methods syntaxstatetype - DExprSeqState::ssm_type() const noexcept + DToplevelSeqSsm::ssm_type() const noexcept { return syntaxstatetype::expect_toplevel_expression_sequence; } std::string_view - DExprSeqState::get_expect_str() const noexcept + DToplevelSeqSsm::get_expect_str() const noexcept { // TODO: provisional. Will expand as more syntax implemented @@ -113,11 +113,11 @@ namespace xo { } assert(false); - return "impossible-DExprSeqState::get_expr_str"; + return "impossible-DToplevelSeqSsm::get_expr_str"; } void - DExprSeqState::on_token(const Token & tk, + DToplevelSeqSsm::on_token(const Token & tk, ParserStateMachine * p_psm) { scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); @@ -197,13 +197,13 @@ namespace xo { break; } - p_psm->illegal_input_on_token("DExprSeqState::on_token", + p_psm->illegal_input_on_token("DToplevelSeqSsm::on_token", tk, this->get_expect_str()); } void - DExprSeqState::on_symbol_token(const Token & tk, + DToplevelSeqSsm::on_symbol_token(const Token & tk, ParserStateMachine * p_psm) { switch (seqtype_) { @@ -215,7 +215,7 @@ namespace xo { if (var) { DProgressSsm::start(var, p_psm); } else { - p_psm->unknown_variable_error("DExprSeqState::on_symbol_token", + p_psm->unknown_variable_error("DToplevelSeqSsm::on_symbol_token", tk, this->get_expect_str(), p_psm); @@ -234,7 +234,7 @@ namespace xo { } void - DExprSeqState::on_def_token(const Token & tk, + DToplevelSeqSsm::on_def_token(const Token & tk, ParserStateMachine * p_psm) { (void)tk; @@ -250,7 +250,7 @@ namespace xo { } void - DExprSeqState::on_lambda_token(const Token & tk, + DToplevelSeqSsm::on_lambda_token(const Token & tk, ParserStateMachine * p_psm) { (void)tk; @@ -271,7 +271,7 @@ namespace xo { } void - DExprSeqState::on_if_token(const Token & tk, + DToplevelSeqSsm::on_if_token(const Token & tk, ParserStateMachine * p_psm) { switch (seqtype_) { @@ -291,7 +291,7 @@ namespace xo { } void - DExprSeqState::on_string_token(const Token & tk, + DToplevelSeqSsm::on_string_token(const Token & tk, ParserStateMachine * p_psm) { switch (seqtype_) { @@ -318,7 +318,7 @@ namespace xo { } void - DExprSeqState::on_f64_token(const Token & tk, + DToplevelSeqSsm::on_f64_token(const Token & tk, ParserStateMachine * p_psm) { switch (seqtype_) { @@ -344,7 +344,7 @@ namespace xo { } void - DExprSeqState::on_i64_token(const Token & tk, + DToplevelSeqSsm::on_i64_token(const Token & tk, ParserStateMachine * p_psm) { switch (seqtype_) { @@ -370,7 +370,7 @@ namespace xo { } void - DExprSeqState::on_bool_token(const Token & tk, + DToplevelSeqSsm::on_bool_token(const Token & tk, ParserStateMachine * p_psm) { switch (seqtype_) { @@ -396,7 +396,7 @@ namespace xo { } void - DExprSeqState::on_leftparen_token(const Token & tk, + DToplevelSeqSsm::on_leftparen_token(const Token & tk, ParserStateMachine * p_psm) { switch (seqtype_) { @@ -423,21 +423,21 @@ namespace xo { } void - DExprSeqState::on_parsed_expression(obj expr, + DToplevelSeqSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) { // toplevel expr sequence accepts an arbitrary number of expressions. - p_psm->capture_result("DExprSeqState::on_parsed_expression", expr); + p_psm->capture_result("DToplevelSeqSsm::on_parsed_expression", expr); } void - DExprSeqState::on_parsed_expression_with_token(obj expr, + DToplevelSeqSsm::on_parsed_expression_with_token(obj expr, const Token & tk, ParserStateMachine * p_psm) { if (tk.tk_type() == tokentype::tk_semicolon) { - p_psm->capture_result("DExprSeqState::on_parsed_expression_with_token", expr); + p_psm->capture_result("DToplevelSeqSsm::on_parsed_expression_with_token", expr); return; } @@ -445,14 +445,14 @@ namespace xo { } bool - DExprSeqState::pretty(const ppindentinfo & ppii) const + DToplevelSeqSsm::pretty(const ppindentinfo & ppii) const { return ppii.pps()->pretty_struct (ppii, - "DExprSeqState", + "DToplevelSeqSsm", refrtag("seqtype", seqtype_)); } } /*namespace scm*/ } /*namespace xo*/ -/* end DExprSeqState.cpp */ +/* end DToplevelSeqSsm.cpp */ diff --git a/src/reader2/IPrintable_DExprSeqState.cpp b/src/reader2/IPrintable_DToplevelSeqSsm.cpp similarity index 54% rename from src/reader2/IPrintable_DExprSeqState.cpp rename to src/reader2/IPrintable_DToplevelSeqSsm.cpp index 36cfbd78..7a958fa8 100644 --- a/src/reader2/IPrintable_DExprSeqState.cpp +++ b/src/reader2/IPrintable_DToplevelSeqSsm.cpp @@ -1,22 +1,22 @@ -/** @file IPrintable_DExprSeqState.cpp +/** @file IPrintable_DToplevelSeqSsm.cpp * * Generated automagically from ingredients: * 1. code generator: * [xo-facet/codegen/genfacet] * arguments: - * --input [idl/IPrintable_DExprSeqState.json5] + * --input [idl/IPrintable_DToplevelSeqSsm.json5] * 2. jinja2 template for abstract facet .hpp file: * [iface_facet_any.hpp.j2] * 3. idl for facet methods - * [idl/IPrintable_DExprSeqState.json5] + * [idl/IPrintable_DToplevelSeqSsm.json5] **/ -#include "ssm/IPrintable_DExprSeqState.hpp" +#include "ssm/IPrintable_DToplevelSeqSsm.hpp" namespace xo { namespace scm { auto - IPrintable_DExprSeqState::pretty(const DExprSeqState & self, const ppindentinfo & ppii) -> bool + IPrintable_DToplevelSeqSsm::pretty(const DToplevelSeqSsm & self, const ppindentinfo & ppii) -> bool { return self.pretty(ppii); } @@ -25,4 +25,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end IPrintable_DExprSeqState.cpp */ +/* end IPrintable_DToplevelSeqSsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp deleted file mode 100644 index 71b0cc1a..00000000 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/** @file ISyntaxStateMachine_DExprSeqState.cpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/ISyntaxStateMachine_DExprSeqState.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_any.hpp.j2] - * 3. idl for facet methods - * [idl/ISyntaxStateMachine_DExprSeqState.json5] -**/ - -#include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" - -namespace xo { - namespace scm { - auto - ISyntaxStateMachine_DExprSeqState::ssm_type(const DExprSeqState & self) noexcept -> syntaxstatetype - { - return self.ssm_type(); - } - - auto - ISyntaxStateMachine_DExprSeqState::get_expect_str(const DExprSeqState & self) noexcept -> std::string_view - { - return self.get_expect_str(); - } - - auto - ISyntaxStateMachine_DExprSeqState::on_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_parsed_symbol(DExprSeqState & self, std::string_view sym, ParserStateMachine * p_psm) -> void - { - self.on_parsed_symbol(sym, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_parsed_typedescr(DExprSeqState & self, TypeDescr td, ParserStateMachine * p_psm) -> void - { - self.on_parsed_typedescr(td, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_parsed_formal(DExprSeqState & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void - { - self.on_parsed_formal(param_name, param_type, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_parsed_formal_arglist(DExprSeqState & self, DArray * arglist, ParserStateMachine * p_psm) -> void - { - self.on_parsed_formal_arglist(arglist, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_parsed_expression(DExprSeqState & self, obj expr, ParserStateMachine * p_psm) -> void - { - self.on_parsed_expression(expr, p_psm); - } - auto - ISyntaxStateMachine_DExprSeqState::on_parsed_expression_with_token(DExprSeqState & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_parsed_expression_with_token(expr, tk, p_psm); - } - - } /*namespace scm*/ -} /*namespace xo*/ - -/* end ISyntaxStateMachine_DExprSeqState.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp new file mode 100644 index 00000000..4dfe35a8 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp @@ -0,0 +1,69 @@ +/** @file ISyntaxStateMachine_DToplevelSeqSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DToplevelSeqSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DToplevelSeqSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DToplevelSeqSsm::ssm_type(const DToplevelSeqSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DToplevelSeqSsm::get_expect_str(const DToplevelSeqSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DToplevelSeqSsm::on_token(DToplevelSeqSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DToplevelSeqSsm::on_parsed_symbol(DToplevelSeqSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DToplevelSeqSsm::on_parsed_typedescr(DToplevelSeqSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DToplevelSeqSsm::on_parsed_formal(DToplevelSeqSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DToplevelSeqSsm::on_parsed_formal_arglist(DToplevelSeqSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DToplevelSeqSsm::on_parsed_expression(DToplevelSeqSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DToplevelSeqSsm::on_parsed_expression_with_token(DToplevelSeqSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DToplevelSeqSsm.cpp */ diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 3a30b18a..9272cfc2 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -6,7 +6,7 @@ #include "SchematikaParser.hpp" #include "ParserStateMachine.hpp" #include "ParserStack.hpp" -#include "DExprSeqState.hpp" +#include "DToplevelSeqSsm.hpp" #include #include #include @@ -65,14 +65,14 @@ namespace xo { void SchematikaParser::begin_interactive_session() { - DExprSeqState::establish_interactive(psm_.parser_alloc(), &psm_); + DToplevelSeqSsm::establish_interactive(psm_.parser_alloc(), &psm_); } void SchematikaParser::begin_batch_session() { - DExprSeqState::establish_batch(psm_.parser_alloc(), &psm_); + DToplevelSeqSsm::establish_batch(psm_.parser_alloc(), &psm_); } const ParserResult & diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 845b8d8e..59d91907 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -6,7 +6,7 @@ #include "reader2_register_facets.hpp" #include "SchematikaParser.hpp" -#include "ExprSeqState.hpp" +#include "ToplevelSeqSsm.hpp" #include "DefineSsm.hpp" #include "LambdaSsm.hpp" #include "IfElseSsm.hpp" @@ -37,8 +37,8 @@ namespace xo { { scope log(XO_DEBUG(true)); - FacetRegistry::register_impl(); - FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); FacetRegistry::register_impl(); @@ -80,7 +80,7 @@ namespace xo { // misc types showing up in parser stack arena TypeRegistry::register_type(); - log && log(xtag("DExprSeqState.tseq", typeseq::id())); + log && log(xtag("DToplevelSeqSsm.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); log && log(xtag("DLambdaSsm.tseq", typeseq::id())); log && log(xtag("DIfElseSsm.tseq", typeseq::id())); From 9a97bb2680b7fc6c91bfcb2896f66e27e1a0b04c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 16:50:57 -0500 Subject: [PATCH 230/342] xo-reader2: refactor: make() + _make() pair for each ssm --- include/xo/reader2/DApplySsm.hpp | 8 ++++++-- include/xo/reader2/DExpectExprSsm.hpp | 11 ++++++++--- include/xo/reader2/DExpectSymbolSsm.hpp | 5 ++++- include/xo/reader2/DExpectTypeSsm.hpp | 6 +++++- include/xo/reader2/DIfElseSsm.hpp | 12 ++++-------- include/xo/reader2/DProgressSsm.hpp | 11 ++++++++--- src/reader2/DApplySsm.cpp | 16 ++++++++++------ src/reader2/DExpectExprSsm.cpp | 21 ++++++++++++--------- src/reader2/DExpectSymbolSsm.cpp | 17 ++++++++--------- src/reader2/DExpectTypeSsm.cpp | 14 ++++++++------ src/reader2/DIfElseSsm.cpp | 11 ++++++++--- src/reader2/DProgressSsm.cpp | 19 +++++++++++-------- 12 files changed, 92 insertions(+), 59 deletions(-) diff --git a/include/xo/reader2/DApplySsm.hpp b/include/xo/reader2/DApplySsm.hpp index b9ff3d8b..d53b3c5c 100644 --- a/include/xo/reader2/DApplySsm.hpp +++ b/include/xo/reader2/DApplySsm.hpp @@ -88,8 +88,12 @@ namespace xo { /** create instance using memory from @p parser_mm. * with function to be called supplied by @p fn_expr. **/ - static DApplySsm * make(DArena & parser_mm, - obj fn_expr); + static DApplySsm * _make(DArena & parser_mm, + obj fn_expr); + + /** create fop referring to new DApplySsm **/ + static obj make(DArena & parser_mm, + obj fn_expr); /** * Start apply. Will trigger this after input like diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 473a89d3..c963c9c1 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -25,9 +25,14 @@ namespace xo { explicit DExpectExprSsm(bool allow_defs, bool cxl_on_rightparen); - static DExpectExprSsm * make(DArena & parser_mm, - bool allow_defs, - bool cxl_on_rightbrace); + static DExpectExprSsm * _make(DArena & parser_mm, + bool allow_defs, + bool cxl_on_rightbrace); + + /** create fop referring to new DExpectExprSsm **/ + static obj make(DArena & parser_mm, + bool allow_defs, + bool cxl_on_rightbrace); static void start(DArena & parser_mm, bool allow_defs, diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index d1cf3a3c..b621985b 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -29,7 +29,10 @@ namespace xo { DExpectSymbolSsm(); /** create instance using memory from @p parser_mm **/ - static DExpectSymbolSsm * make(DArena & parser_mm); + static DExpectSymbolSsm * _make(DArena & parser_mm); + + /** create fop referring to new DExpectSymbolSsm **/ + static obj make(DArena & parser_mm); /** start nested parser expecting a symbol, * on top of parser state machine @p p_psm. diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 6719bfb8..8d67b448 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -6,6 +6,7 @@ #pragma once #include "DSyntaxStateMachine.hpp" +#include #include namespace xo { @@ -31,7 +32,10 @@ namespace xo { public: DExpectTypeSsm(); - static DExpectTypeSsm * make(DArena & parser_mm); + static DExpectTypeSsm * _make(DArena & parser_mm); + + /** create fop referring to new DExpectTypeSsm **/ + static obj make(DArena & parser_mm); static void start(ParserStateMachine * p_psm); diff --git a/include/xo/reader2/DIfElseSsm.hpp b/include/xo/reader2/DIfElseSsm.hpp index 986ffcd7..345f3fa5 100644 --- a/include/xo/reader2/DIfElseSsm.hpp +++ b/include/xo/reader2/DIfElseSsm.hpp @@ -65,20 +65,16 @@ namespace xo { ///@{ explicit DIfElseSsm(DIfElseExpr * ifelse_expr); -#ifdef NOT_YET - /** create instance using memory from @p parser_mm - * with initial scaffold @p ifelse_expr - **/ - static obj make(DArena & parser_mm, - DIfElseExpr * ifelse_expr); -#endif - /** create instance using memory from @p parser_mm * with initial scaffold @p ifelse_expr. **/ static DIfElseSsm * _make(DArena & parser_mm, DIfElseExpr * ifelse_expr); + /** create fop referring to new DIfElseSsm **/ + static obj make(DArena & parser_mm, + DIfElseExpr * ifelse_expr); + /** start nested parser for an if-else expression * on top of parser state machine @p p_psm. * Use @p parser_mm to allocate syntax state machines diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index c43caacd..cc0eb0c5 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -96,9 +96,14 @@ namespace xo { public: DProgressSsm(obj lhs, optype op); - static DProgressSsm * make(DArena & parser_mm, - obj lhs, - optype op); + static DProgressSsm * _make(DArena & parser_mm, + obj lhs, + optype op); + + /** create fop referring to new DProgressSsm **/ + static obj make(DArena & parser_mm, + obj lhs, + optype op); static void start(DArena & parser_mm, ParserStateMachine * p_psm); diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index a741ce4b..d6f5e151 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -58,8 +58,8 @@ namespace xo { } DApplySsm * - DApplySsm::make(DArena & arena, - obj fn_expr) + DApplySsm::_make(DArena & arena, + obj fn_expr) { obj mm(&arena); @@ -83,6 +83,13 @@ namespace xo { return new (mem) DApplySsm(applystate, fn_expr, args); } + obj + DApplySsm::make(DArena & arena, + obj fn_expr) + { + return obj(_make(arena, fn_expr)); + } + void DApplySsm::start(obj fn_expr, ParserStateMachine * p_psm) @@ -91,10 +98,7 @@ namespace xo { DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); - DApplySsm * apply_ssm - = DApplySsm::make(p_psm->parser_alloc(), fn_expr); - - obj ssm(apply_ssm); + auto ssm = DApplySsm::make(p_psm->parser_alloc(), fn_expr); p_psm->push_ssm(ckp, ssm); } diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 767df9bf..a2db5967 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -52,9 +52,9 @@ namespace xo { } DExpectExprSsm * - DExpectExprSsm::make(DArena & mm, - bool allow_defs, - bool cxl_on_rightbrace) + DExpectExprSsm::_make(DArena & mm, + bool allow_defs, + bool cxl_on_rightbrace) { void * mem = mm.alloc(typeseq::id(), sizeof(DExpectExprSsm)); @@ -63,6 +63,14 @@ namespace xo { cxl_on_rightbrace); } + obj + DExpectExprSsm::make(DArena & mm, + bool allow_defs, + bool cxl_on_rightbrace) + { + return obj(_make(mm, allow_defs, cxl_on_rightbrace)); + } + void DExpectExprSsm::start(DArena & mm, bool allow_defs, @@ -71,12 +79,7 @@ namespace xo { { DArena::Checkpoint ckp = mm.checkpoint(); - DExpectExprSsm * exp_expr - = DExpectExprSsm::make(mm, - allow_defs, - cxl_on_rightbrace); - obj ssm - = with_facet::mkobj(exp_expr); + auto ssm = DExpectExprSsm::make(mm, allow_defs, cxl_on_rightbrace); p_psm->push_ssm(ckp, ssm); } diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 6f289edd..8a750751 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -20,7 +20,7 @@ namespace xo { {} DExpectSymbolSsm * - DExpectSymbolSsm::make(DArena & mm) + DExpectSymbolSsm::_make(DArena & mm) { void * mem = mm.alloc(typeseq::id(), sizeof(DExpectSymbolSsm)); @@ -28,19 +28,18 @@ namespace xo { return new (mem) DExpectSymbolSsm(); } + obj + DExpectSymbolSsm::make(DArena & mm) + { + return obj(_make(mm)); + } + void DExpectSymbolSsm::start(ParserStateMachine * p_psm) { DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); - DExpectSymbolSsm * sym_ssm - = DExpectSymbolSsm::make(p_psm->parser_alloc()); - - // note: - // relying on [ISyntaxStateMachine_DExpectedSymbolSsm.hpp] - // - obj ssm - = with_facet::mkobj(sym_ssm); + auto ssm = DExpectSymbolSsm::make(p_psm->parser_alloc()); p_psm->push_ssm(ckp, ssm); } diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 412a5cab..b4fa8819 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -23,7 +23,7 @@ namespace xo { {} DExpectTypeSsm * - DExpectTypeSsm::make(DArena & mm) + DExpectTypeSsm::_make(DArena & mm) { void * mem = mm.alloc(typeseq::id(), sizeof(DArena)); @@ -31,16 +31,18 @@ namespace xo { return new (mem) DExpectTypeSsm(); } + obj + DExpectTypeSsm::make(DArena & mm) + { + return obj(_make(mm)); + } + void DExpectTypeSsm::start(ParserStateMachine * p_psm) { DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); - DExpectTypeSsm * expect_type_ssm - = DExpectTypeSsm::make(p_psm->parser_alloc()); - - auto ssm - = with_facet::mkobj(expect_type_ssm); + auto ssm = DExpectTypeSsm::make(p_psm->parser_alloc()); p_psm->push_ssm(ckp, ssm); } diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index 521a59a1..e78d187b 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -63,6 +63,13 @@ namespace xo { return new (mem) DIfElseSsm(ifelse_expr); } + obj + DIfElseSsm::make(DArena & mm, + DIfElseExpr * ifelse_expr) + { + return obj(_make(mm, ifelse_expr)); + } + void DIfElseSsm::start(DArena & parser_mm, obj expr_mm, @@ -73,10 +80,8 @@ namespace xo { DArena::Checkpoint ckp = parser_mm.checkpoint(); DIfElseExpr * if_expr = DIfElseExpr::_make_empty(expr_mm); - DIfElseSsm * if_ssm = DIfElseSsm::_make(parser_mm, if_expr); - obj ssm - = with_facet::mkobj(if_ssm); + auto ssm = DIfElseSsm::make(parser_mm, if_expr); p_psm->push_ssm(ckp, ssm); diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index e4cdf46b..4af449c0 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -146,16 +146,22 @@ namespace xo { } DProgressSsm * - DProgressSsm::make(DArena & mm, - obj lhs, - optype op) + DProgressSsm::_make(DArena & mm, + obj lhs, + optype op) { void * mem = mm.alloc(typeseq::id(), sizeof(DProgressSsm)); return new (mem) DProgressSsm(lhs, op); + } - //return std::make_unique(progress_xs(std::move(valex), op)); + obj + DProgressSsm::make(DArena & mm, + obj lhs, + optype op) + { + return obj(_make(mm, lhs, op)); } void @@ -166,10 +172,7 @@ namespace xo { { DArena::Checkpoint ckp = parser_mm.checkpoint(); - DProgressSsm * progress_ssm - = DProgressSsm::make(parser_mm, lhs, op); - - obj ssm(progress_ssm); + auto ssm = DProgressSsm::make(parser_mm, lhs, op); p_psm->push_ssm(ckp, ssm); } From f761a38723bd3725f1f20a138273df7400fbcae9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 17:46:51 -0500 Subject: [PATCH 231/342] xo-interpreter2 stack: OUTPUT_CPP_DIR cmake->idl/ --- CMakeLists.txt | 27 ------------------- idl/IPrintable_DApplySsm.json5 | 1 + idl/IPrintable_DDefineSsm.json5 | 1 + idl/IPrintable_DExpectExprSsm.json5 | 1 + idl/IPrintable_DExpectFormalArgSsm.json5 | 1 + idl/IPrintable_DExpectFormalArglistSsm.json5 | 1 + idl/IPrintable_DExpectSymbolSsm.json5 | 1 + idl/IPrintable_DExpectTypeSsm.json5 | 1 + idl/IPrintable_DIfElseSsm.json5 | 1 + idl/IPrintable_DLambdaSsm.json5 | 1 + idl/IPrintable_DParenSsm.json5 | 1 + idl/IPrintable_DProgressSsm.json5 | 1 + idl/IPrintable_DSequenceSsm.json5 | 1 + idl/IPrintable_DToplevelSeqSsm.json5 | 1 + idl/ISyntaxStateMachine_DApplySsm.json5 | 1 + idl/ISyntaxStateMachine_DDefineSsm.json5 | 1 + idl/ISyntaxStateMachine_DExpectExprSsm.json5 | 1 + ...ntaxStateMachine_DExpectFormalArgSsm.json5 | 1 + ...StateMachine_DExpectFormalArglistSsm.json5 | 1 + ...ISyntaxStateMachine_DExpectSymbolSsm.json5 | 1 + idl/ISyntaxStateMachine_DExpectTypeSsm.json5 | 1 + idl/ISyntaxStateMachine_DIfElseSsm.json5 | 1 + idl/ISyntaxStateMachine_DLambdaSsm.json5 | 1 + idl/ISyntaxStateMachine_DParenSsm.json5 | 1 + idl/ISyntaxStateMachine_DProgressSsm.json5 | 1 + idl/ISyntaxStateMachine_DSequenceSsm.json5 | 1 + idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 | 1 + idl/SyntaxStateMachine.json5 | 1 + .../ssm/IPrintable_DToplevelSeqSsm.hpp | 4 +-- .../ISyntaxStateMachine_DToplevelSeqSsm.hpp | 4 +-- 30 files changed, 31 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2153df4..f098bd5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,6 @@ xo_add_genfacet( INPUT idl/SyntaxStateMachine.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -45,7 +44,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -57,7 +55,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DToplevelSeqSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -71,7 +68,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DDefineSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -83,7 +79,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DDefineSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -97,7 +92,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DLambdaSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -109,7 +103,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DLambdaSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -123,7 +116,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DParenSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -135,7 +127,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DParenSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -149,7 +140,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -161,7 +151,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DExpectFormalArglistSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -175,7 +164,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -187,7 +175,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DExpectFormalArgSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -201,7 +188,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DIfElseSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -213,7 +199,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DIfElseSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -227,7 +212,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DSequenceSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -239,7 +223,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DSequenceSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -253,7 +236,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DApplySsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -265,7 +247,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DApplySsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -279,7 +260,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -291,7 +271,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DExpectSymbolSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -305,7 +284,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DExpectTypeSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -317,7 +295,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DExpectTypeSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -331,7 +308,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DExpectExprSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -343,7 +319,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DExpectExprSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- @@ -357,7 +332,6 @@ xo_add_genfacetimpl( INPUT idl/ISyntaxStateMachine_DProgressSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # note: manual target; generated code committed to git @@ -369,7 +343,6 @@ xo_add_genfacetimpl( INPUT idl/IPrintable_DProgressSsm.json5 OUTPUT_HPP_DIR include/xo/reader2 OUTPUT_IMPL_SUBDIR ssm - OUTPUT_CPP_DIR src/reader2 ) # ---------------------------------------------------------------- diff --git a/idl/IPrintable_DApplySsm.json5 b/idl/IPrintable_DApplySsm.json5 index cdcd32ca..5895578d 100644 --- a/idl/IPrintable_DApplySsm.json5 +++ b/idl/IPrintable_DApplySsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DDefineSsm.json5 b/idl/IPrintable_DDefineSsm.json5 index e79017f8..3975396e 100644 --- a/idl/IPrintable_DDefineSsm.json5 +++ b/idl/IPrintable_DDefineSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DExpectExprSsm.json5 b/idl/IPrintable_DExpectExprSsm.json5 index 72d19cd7..b6b0caa1 100644 --- a/idl/IPrintable_DExpectExprSsm.json5 +++ b/idl/IPrintable_DExpectExprSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DExpectFormalArgSsm.json5 b/idl/IPrintable_DExpectFormalArgSsm.json5 index 854a458e..6b1bf863 100644 --- a/idl/IPrintable_DExpectFormalArgSsm.json5 +++ b/idl/IPrintable_DExpectFormalArgSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DExpectFormalArglistSsm.json5 b/idl/IPrintable_DExpectFormalArglistSsm.json5 index 44f474dd..7f566150 100644 --- a/idl/IPrintable_DExpectFormalArglistSsm.json5 +++ b/idl/IPrintable_DExpectFormalArglistSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DExpectSymbolSsm.json5 b/idl/IPrintable_DExpectSymbolSsm.json5 index 1d662986..1d003791 100644 --- a/idl/IPrintable_DExpectSymbolSsm.json5 +++ b/idl/IPrintable_DExpectSymbolSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DExpectTypeSsm.json5 b/idl/IPrintable_DExpectTypeSsm.json5 index 1a4ddca2..4c3b8964 100644 --- a/idl/IPrintable_DExpectTypeSsm.json5 +++ b/idl/IPrintable_DExpectTypeSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DIfElseSsm.json5 b/idl/IPrintable_DIfElseSsm.json5 index 28fab147..9c54fc71 100644 --- a/idl/IPrintable_DIfElseSsm.json5 +++ b/idl/IPrintable_DIfElseSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DLambdaSsm.json5 b/idl/IPrintable_DLambdaSsm.json5 index 63fad901..9f2187df 100644 --- a/idl/IPrintable_DLambdaSsm.json5 +++ b/idl/IPrintable_DLambdaSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DParenSsm.json5 b/idl/IPrintable_DParenSsm.json5 index 495729b5..9af85828 100644 --- a/idl/IPrintable_DParenSsm.json5 +++ b/idl/IPrintable_DParenSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DProgressSsm.json5 b/idl/IPrintable_DProgressSsm.json5 index cc5a8dda..eb420da3 100644 --- a/idl/IPrintable_DProgressSsm.json5 +++ b/idl/IPrintable_DProgressSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DSequenceSsm.json5 b/idl/IPrintable_DSequenceSsm.json5 index a217b24c..929060b0 100644 --- a/idl/IPrintable_DSequenceSsm.json5 +++ b/idl/IPrintable_DSequenceSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DToplevelSeqSsm.json5 b/idl/IPrintable_DToplevelSeqSsm.json5 index 0c0f0200..8349bb04 100644 --- a/idl/IPrintable_DToplevelSeqSsm.json5 +++ b/idl/IPrintable_DToplevelSeqSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "", "" ], local_types: [], diff --git a/idl/ISyntaxStateMachine_DApplySsm.json5 b/idl/ISyntaxStateMachine_DApplySsm.json5 index 7806d2cb..2f08ccc5 100644 --- a/idl/ISyntaxStateMachine_DApplySsm.json5 +++ b/idl/ISyntaxStateMachine_DApplySsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DDefineSsm.json5 b/idl/ISyntaxStateMachine_DDefineSsm.json5 index 11d2c5f7..7aef2f5a 100644 --- a/idl/ISyntaxStateMachine_DDefineSsm.json5 +++ b/idl/ISyntaxStateMachine_DDefineSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DExpectExprSsm.json5 b/idl/ISyntaxStateMachine_DExpectExprSsm.json5 index 068ac481..0b04e3d6 100644 --- a/idl/ISyntaxStateMachine_DExpectExprSsm.json5 +++ b/idl/ISyntaxStateMachine_DExpectExprSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 b/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 index 4b83866e..83627a07 100644 --- a/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 +++ b/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 b/idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 index d3e16953..535e713f 100644 --- a/idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 +++ b/idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 b/idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 index 24b754e4..288b8256 100644 --- a/idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 +++ b/idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DExpectTypeSsm.json5 b/idl/ISyntaxStateMachine_DExpectTypeSsm.json5 index d46aaff4..04617d60 100644 --- a/idl/ISyntaxStateMachine_DExpectTypeSsm.json5 +++ b/idl/ISyntaxStateMachine_DExpectTypeSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DIfElseSsm.json5 b/idl/ISyntaxStateMachine_DIfElseSsm.json5 index 5e7e828b..23a4e35d 100644 --- a/idl/ISyntaxStateMachine_DIfElseSsm.json5 +++ b/idl/ISyntaxStateMachine_DIfElseSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DLambdaSsm.json5 b/idl/ISyntaxStateMachine_DLambdaSsm.json5 index a24f0147..bd32a95b 100644 --- a/idl/ISyntaxStateMachine_DLambdaSsm.json5 +++ b/idl/ISyntaxStateMachine_DLambdaSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DParenSsm.json5 b/idl/ISyntaxStateMachine_DParenSsm.json5 index 521e7ba8..9d24338d 100644 --- a/idl/ISyntaxStateMachine_DParenSsm.json5 +++ b/idl/ISyntaxStateMachine_DParenSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DProgressSsm.json5 b/idl/ISyntaxStateMachine_DProgressSsm.json5 index 807e5ec3..9a141775 100644 --- a/idl/ISyntaxStateMachine_DProgressSsm.json5 +++ b/idl/ISyntaxStateMachine_DProgressSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DSequenceSsm.json5 b/idl/ISyntaxStateMachine_DSequenceSsm.json5 index 7538c09b..c9319948 100644 --- a/idl/ISyntaxStateMachine_DSequenceSsm.json5 +++ b/idl/ISyntaxStateMachine_DSequenceSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 b/idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 index f13b3137..e94779f5 100644 --- a/idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 +++ b/idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 @@ -1,5 +1,6 @@ { mode: "implementation", + output_cpp_dir: "src/reader2", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 4e33e468..d204a265 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -1,5 +1,6 @@ { mode: "facet", + output_cpp_dir: "src/reader2", // includes in ASyntaxStateMachine.hpp includes: [ "\"ParserStateMachine.hpp\"", diff --git a/include/xo/reader2/ssm/IPrintable_DToplevelSeqSsm.hpp b/include/xo/reader2/ssm/IPrintable_DToplevelSeqSsm.hpp index d411a87e..b219b589 100644 --- a/include/xo/reader2/ssm/IPrintable_DToplevelSeqSsm.hpp +++ b/include/xo/reader2/ssm/IPrintable_DToplevelSeqSsm.hpp @@ -39,13 +39,13 @@ namespace xo { **/ class IPrintable_DToplevelSeqSsm { public: - /** @defgroup scm-printable-dexprseqstate-type-traits **/ + /** @defgroup scm-printable-dtoplevelseqssm-type-traits **/ ///@{ using ppindentinfo = xo::print::APrintable::ppindentinfo; using Copaque = xo::print::APrintable::Copaque; using Opaque = xo::print::APrintable::Opaque; ///@} - /** @defgroup scm-printable-dexprseqstate-methods **/ + /** @defgroup scm-printable-dtoplevelseqssm-methods **/ ///@{ // const methods /** Pretty-printing support for this object. diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp index 3bf58e17..1d91c13d 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp @@ -39,13 +39,13 @@ namespace xo { **/ class ISyntaxStateMachine_DToplevelSeqSsm { public: - /** @defgroup scm-syntaxstatemachine-dexprseqstate-type-traits **/ + /** @defgroup scm-syntaxstatemachine-dtoplevelseqssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} - /** @defgroup scm-syntaxstatemachine-dexprseqstate-methods **/ + /** @defgroup scm-syntaxstatemachine-dtoplevelseqssm-methods **/ ///@{ // const methods /** identify a type of syntax state machine **/ From 595dc47deef5f77230fa57428638a2509e463234 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 19:07:37 -0500 Subject: [PATCH 232/342] xo-reader2: bugfix: detecting toplevel for upsert global var --- src/reader2/DDefineSsm.cpp | 2 ++ src/reader2/ParserStateMachine.cpp | 44 ++++++++++++++++++++++++++++-- src/reader2/SchematikaParser.cpp | 2 +- utest/SchematikaParser.test.cpp | 2 +- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 78e29250..aae07b90 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -678,6 +678,8 @@ namespace xo { Super::on_parsed_expression_with_token(expr, tk, p_psm); } + // ----- printable facet ----- + bool DDefineSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 1223abe2..0b2367ad 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -6,6 +6,8 @@ #include "ParserStateMachine.hpp" #include "ParserStack.hpp" #include "SyntaxStateMachine.hpp" +#include "ToplevelSeqSsm.hpp" +#include "DefineSsm.hpp" #include #include #include @@ -39,16 +41,52 @@ namespace xo { bool ParserStateMachine::is_at_toplevel() const noexcept { - return ((stack_ == nullptr) - || (stack_->parent() == nullptr)); + /* top-level alwyas has DToplevelSeqSsm */ + + ParserStack * s = stack_; + + if (s) { + auto def = obj::from(s->top()); + + if (def) { + /* carve-out for top-level DefineSsm: report 'at top-level' when + * that top-level DefineSsm is on the stack, so we detect + * this condition inside DefineSsm's event handling + */ + s = stack_->parent(); + } + + if (s && s->parent() == nullptr) { + auto top = obj::from(s->top()); + + return top; + } + } else { + /** this isn't a normal operating state, still need a batch/interactive toplevel seq. + * just the same seems better to call it top-level + **/ + return true; + } + + return false; } bool ParserStateMachine::has_incomplete_expr() const noexcept { + scope log(XO_DEBUG(debug_flag_)); + // don't count toplevel expression - return !(this->is_at_toplevel()); + ParserStack * s = stack_; + + if (s) { + auto top = obj::from(s->top()); + + return !top; + } else { + return false; + } } obj diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 9272cfc2..1bb188cb 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -41,7 +41,7 @@ namespace xo { bool SchematikaParser::has_incomplete_expr() const { - return !(this->is_at_toplevel()); + return psm_.has_incomplete_expr(); } obj diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index a0557fa6..665342dc 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -232,7 +232,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; + constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); From e72ab344196806cf6370a0416e333a565ba4ee37 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 19:48:14 -0500 Subject: [PATCH 233/342] xo-expression2: upsert global vars works in DDefineSsm --- src/reader2/ParserStateMachine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 0b2367ad..6df9133b 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -229,8 +229,9 @@ namespace xo { void ParserStateMachine::upsert_var(DVariable * var) { - scope log(XO_DEBUG(true), "stub impl"); - log && log(xtag("var", std::string_view(*(var->name())))); + assert(global_symtab_); + + global_symtab_->upsert_variable(this->expr_alloc(), var); } void From 221fd85f61776681a5e0b5b1194c04e1c9dbc956 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 22:33:32 -0500 Subject: [PATCH 234/342] xo-facet: move output-hpp-dir + subdir to idl/*.json5 --- idl/IPrintable_DApplySsm.json5 | 2 ++ idl/IPrintable_DDefineSsm.json5 | 2 ++ idl/IPrintable_DExpectExprSsm.json5 | 2 ++ idl/IPrintable_DExpectFormalArgSsm.json5 | 2 ++ idl/IPrintable_DExpectFormalArglistSsm.json5 | 2 ++ idl/IPrintable_DExpectSymbolSsm.json5 | 2 ++ idl/IPrintable_DExpectTypeSsm.json5 | 2 ++ idl/IPrintable_DIfElseSsm.json5 | 2 ++ idl/IPrintable_DLambdaSsm.json5 | 2 ++ idl/IPrintable_DParenSsm.json5 | 2 ++ idl/IPrintable_DProgressSsm.json5 | 2 ++ idl/IPrintable_DSequenceSsm.json5 | 2 ++ idl/IPrintable_DToplevelSeqSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DApplySsm.json5 | 2 ++ idl/ISyntaxStateMachine_DDefineSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DExpectExprSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DExpectTypeSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DIfElseSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DLambdaSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DParenSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DProgressSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DSequenceSsm.json5 | 2 ++ idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 | 2 ++ idl/SyntaxStateMachine.json5 | 2 ++ 27 files changed, 54 insertions(+) diff --git a/idl/IPrintable_DApplySsm.json5 b/idl/IPrintable_DApplySsm.json5 index 5895578d..6f2a531d 100644 --- a/idl/IPrintable_DApplySsm.json5 +++ b/idl/IPrintable_DApplySsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DDefineSsm.json5 b/idl/IPrintable_DDefineSsm.json5 index 3975396e..28463e92 100644 --- a/idl/IPrintable_DDefineSsm.json5 +++ b/idl/IPrintable_DDefineSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DExpectExprSsm.json5 b/idl/IPrintable_DExpectExprSsm.json5 index b6b0caa1..f5465709 100644 --- a/idl/IPrintable_DExpectExprSsm.json5 +++ b/idl/IPrintable_DExpectExprSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DExpectFormalArgSsm.json5 b/idl/IPrintable_DExpectFormalArgSsm.json5 index 6b1bf863..73389166 100644 --- a/idl/IPrintable_DExpectFormalArgSsm.json5 +++ b/idl/IPrintable_DExpectFormalArgSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DExpectFormalArglistSsm.json5 b/idl/IPrintable_DExpectFormalArglistSsm.json5 index 7f566150..1aa3c951 100644 --- a/idl/IPrintable_DExpectFormalArglistSsm.json5 +++ b/idl/IPrintable_DExpectFormalArglistSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DExpectSymbolSsm.json5 b/idl/IPrintable_DExpectSymbolSsm.json5 index 1d003791..fee89873 100644 --- a/idl/IPrintable_DExpectSymbolSsm.json5 +++ b/idl/IPrintable_DExpectSymbolSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DExpectTypeSsm.json5 b/idl/IPrintable_DExpectTypeSsm.json5 index 4c3b8964..463cb399 100644 --- a/idl/IPrintable_DExpectTypeSsm.json5 +++ b/idl/IPrintable_DExpectTypeSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DIfElseSsm.json5 b/idl/IPrintable_DIfElseSsm.json5 index 9c54fc71..dbcdbb0a 100644 --- a/idl/IPrintable_DIfElseSsm.json5 +++ b/idl/IPrintable_DIfElseSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DLambdaSsm.json5 b/idl/IPrintable_DLambdaSsm.json5 index 9f2187df..035f71f1 100644 --- a/idl/IPrintable_DLambdaSsm.json5 +++ b/idl/IPrintable_DLambdaSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DParenSsm.json5 b/idl/IPrintable_DParenSsm.json5 index 9af85828..9750cb31 100644 --- a/idl/IPrintable_DParenSsm.json5 +++ b/idl/IPrintable_DParenSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DProgressSsm.json5 b/idl/IPrintable_DProgressSsm.json5 index eb420da3..d3d298b1 100644 --- a/idl/IPrintable_DProgressSsm.json5 +++ b/idl/IPrintable_DProgressSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DSequenceSsm.json5 b/idl/IPrintable_DSequenceSsm.json5 index 929060b0..f5c89aca 100644 --- a/idl/IPrintable_DSequenceSsm.json5 +++ b/idl/IPrintable_DSequenceSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/IPrintable_DToplevelSeqSsm.json5 b/idl/IPrintable_DToplevelSeqSsm.json5 index 8349bb04..d3c78474 100644 --- a/idl/IPrintable_DToplevelSeqSsm.json5 +++ b/idl/IPrintable_DToplevelSeqSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "", "" ], local_types: [], diff --git a/idl/ISyntaxStateMachine_DApplySsm.json5 b/idl/ISyntaxStateMachine_DApplySsm.json5 index 2f08ccc5..bc433fdf 100644 --- a/idl/ISyntaxStateMachine_DApplySsm.json5 +++ b/idl/ISyntaxStateMachine_DApplySsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DDefineSsm.json5 b/idl/ISyntaxStateMachine_DDefineSsm.json5 index 7aef2f5a..8b3fff2a 100644 --- a/idl/ISyntaxStateMachine_DDefineSsm.json5 +++ b/idl/ISyntaxStateMachine_DDefineSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DExpectExprSsm.json5 b/idl/ISyntaxStateMachine_DExpectExprSsm.json5 index 0b04e3d6..d1c78ad2 100644 --- a/idl/ISyntaxStateMachine_DExpectExprSsm.json5 +++ b/idl/ISyntaxStateMachine_DExpectExprSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 b/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 index 83627a07..e3486759 100644 --- a/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 +++ b/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 b/idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 index 535e713f..019573d0 100644 --- a/idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 +++ b/idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 b/idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 index 288b8256..49248b62 100644 --- a/idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 +++ b/idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DExpectTypeSsm.json5 b/idl/ISyntaxStateMachine_DExpectTypeSsm.json5 index 04617d60..68883ef0 100644 --- a/idl/ISyntaxStateMachine_DExpectTypeSsm.json5 +++ b/idl/ISyntaxStateMachine_DExpectTypeSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DIfElseSsm.json5 b/idl/ISyntaxStateMachine_DIfElseSsm.json5 index 23a4e35d..25feadde 100644 --- a/idl/ISyntaxStateMachine_DIfElseSsm.json5 +++ b/idl/ISyntaxStateMachine_DIfElseSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DLambdaSsm.json5 b/idl/ISyntaxStateMachine_DLambdaSsm.json5 index bd32a95b..413c64c8 100644 --- a/idl/ISyntaxStateMachine_DLambdaSsm.json5 +++ b/idl/ISyntaxStateMachine_DLambdaSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DParenSsm.json5 b/idl/ISyntaxStateMachine_DParenSsm.json5 index 9d24338d..7ea19fc0 100644 --- a/idl/ISyntaxStateMachine_DParenSsm.json5 +++ b/idl/ISyntaxStateMachine_DParenSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DProgressSsm.json5 b/idl/ISyntaxStateMachine_DProgressSsm.json5 index 9a141775..83c10717 100644 --- a/idl/ISyntaxStateMachine_DProgressSsm.json5 +++ b/idl/ISyntaxStateMachine_DProgressSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DSequenceSsm.json5 b/idl/ISyntaxStateMachine_DSequenceSsm.json5 index c9319948..e497ef7f 100644 --- a/idl/ISyntaxStateMachine_DSequenceSsm.json5 +++ b/idl/ISyntaxStateMachine_DSequenceSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 b/idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 index e94779f5..7a91622f 100644 --- a/idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 +++ b/idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 @@ -1,6 +1,8 @@ { mode: "implementation", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index d204a265..210a43a4 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -1,6 +1,8 @@ { mode: "facet", output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", // includes in ASyntaxStateMachine.hpp includes: [ "\"ParserStateMachine.hpp\"", From 5c53ae08a8c980fb718f2a54252464f9aff983d4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 22:48:27 -0500 Subject: [PATCH 235/342] xo-reader2: streamline facet codegen --- CMakeLists.txt | 54 -------------------------------------------------- 1 file changed, 54 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f098bd5e..9f05802f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,8 +29,6 @@ xo_add_genfacet( TARGET xo-reader2-facet-syntaxstatemachine FACET SyntaxStateMachine INPUT idl/SyntaxStateMachine.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -42,8 +40,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR ToplevelSeqSsm INPUT idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -53,8 +49,6 @@ xo_add_genfacetimpl( FACET Printable REPR ToplevelSeqSsm INPUT idl/IPrintable_DToplevelSeqSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -66,8 +60,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR DefineSsm INPUT idl/ISyntaxStateMachine_DDefineSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -77,8 +69,6 @@ xo_add_genfacetimpl( FACET Printable REPR DefineSsm INPUT idl/IPrintable_DDefineSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -90,8 +80,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR LambdaSsm INPUT idl/ISyntaxStateMachine_DLambdaSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -101,8 +89,6 @@ xo_add_genfacetimpl( FACET Printable REPR LambdaSsm INPUT idl/IPrintable_DLambdaSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -114,8 +100,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR ParenSsm INPUT idl/ISyntaxStateMachine_DParenSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -125,8 +109,6 @@ xo_add_genfacetimpl( FACET Printable REPR ParenSsm INPUT idl/IPrintable_DParenSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -138,8 +120,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR ExpectFormalArglistSsm INPUT idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -149,8 +129,6 @@ xo_add_genfacetimpl( FACET Printable REPR ExpectFormalArglistSsm INPUT idl/IPrintable_DExpectFormalArglistSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -162,8 +140,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR ExpectFormalArgSsm INPUT idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -173,8 +149,6 @@ xo_add_genfacetimpl( FACET Printable REPR ExpectFormalArgSsm INPUT idl/IPrintable_DExpectFormalArgSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -186,8 +160,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR IfElseSsm INPUT idl/ISyntaxStateMachine_DIfElseSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -197,8 +169,6 @@ xo_add_genfacetimpl( FACET Printable REPR IfElseSsm INPUT idl/IPrintable_DIfElseSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -210,8 +180,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR SequenceSsm INPUT idl/ISyntaxStateMachine_DSequenceSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -221,8 +189,6 @@ xo_add_genfacetimpl( FACET Printable REPR SequenceSsm INPUT idl/IPrintable_DSequenceSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -234,8 +200,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR ApplySsm INPUT idl/ISyntaxStateMachine_DApplySsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -245,8 +209,6 @@ xo_add_genfacetimpl( FACET Printable REPR ApplySsm INPUT idl/IPrintable_DApplySsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -258,8 +220,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR ExpectSymbolSsm INPUT idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -269,8 +229,6 @@ xo_add_genfacetimpl( FACET Printable REPR ExpectSymbolSsm INPUT idl/IPrintable_DExpectSymbolSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -282,8 +240,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR ExpectTypeSsm INPUT idl/ISyntaxStateMachine_DExpectTypeSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -293,8 +249,6 @@ xo_add_genfacetimpl( FACET Printable REPR ExpectTypeSsm INPUT idl/IPrintable_DExpectTypeSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -306,8 +260,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR ExpectExprSsm INPUT idl/ISyntaxStateMachine_DExpectExprSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -317,8 +269,6 @@ xo_add_genfacetimpl( FACET Printable REPR ExpectExprSsm INPUT idl/IPrintable_DExpectExprSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- @@ -330,8 +280,6 @@ xo_add_genfacetimpl( FACET SyntaxStateMachine REPR ProgressSsm INPUT idl/ISyntaxStateMachine_DProgressSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # note: manual target; generated code committed to git @@ -341,8 +289,6 @@ xo_add_genfacetimpl( FACET Printable REPR ProgressSsm INPUT idl/IPrintable_DProgressSsm.json5 - OUTPUT_HPP_DIR include/xo/reader2 - OUTPUT_IMPL_SUBDIR ssm ) # ---------------------------------------------------------------- From 10db8493f77a6a0e3f8bdc8345092fae3e600418 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 23:25:34 -0500 Subject: [PATCH 236/342] xo-reader2: utest with variable reference. Works ! --- src/reader2/DToplevelSeqSsm.cpp | 21 ++++----- src/reader2/ParserStateMachine.cpp | 70 ++++++++++++++++-------------- utest/SchematikaParser.test.cpp | 70 +++++++++++++++++++++++++++++- 3 files changed, 117 insertions(+), 44 deletions(-) diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index e294d078..42c870b6 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -11,6 +11,7 @@ #include "DIfElseSsm.hpp" #include "ParenSsm.hpp" #include "ExpectExprSsm.hpp" +#include "VarRef.hpp" #include #include @@ -204,23 +205,23 @@ namespace xo { void DToplevelSeqSsm::on_symbol_token(const Token & tk, - ParserStateMachine * p_psm) + ParserStateMachine * p_psm) { switch (seqtype_) { case exprseqtype::toplevel_interactive: { -#ifdef NOT_YET - obj var = p_psm->lookup_var(tk.text()); + auto varref = obj(p_psm->lookup_varref(tk.text())); - if (var) { - DProgressSsm::start(var, p_psm); + if (varref) { + DProgressSsm::start(p_psm->parser_alloc(), + varref, + p_psm); + return; } else { - p_psm->unknown_variable_error("DToplevelSeqSsm::on_symbol_token", - tk, - this->get_expect_str(), - p_psm); + p_psm->error_unbound_variable("DToplevelSeqSsm", + tk.text()); + return; } -#endif } break; case exprseqtype::toplevel_batch: diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 6df9133b..856a8215 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -156,6 +156,16 @@ namespace xo { { scope log(XO_DEBUG(debug_flag_)); + const DUniqueString * ustr = stringtable_.lookup(symbolname); + + if (!ustr) { + // if we don't already know the symbol, + // -> can't be a valid variable reference + // (whether global or local) + + return nullptr; + } + // TODO: // 1. check global symtab // 2. combine local+global symtab into indept struct @@ -163,52 +173,46 @@ namespace xo { // if (local_symtab_) { - const DUniqueString * ustr = stringtable_.lookup(symbolname); + DLocalSymtab * symtab = local_symtab_; - if (ustr) { - DLocalSymtab * symtab = local_symtab_; + // count #of nested scopes to cross, to reach symbol + // + int32_t link_count = 0; - // count #of nested scopes to cross, to reach symbol - // - int32_t link_count = 0; + while (symtab) { + Binding b = symtab->lookup_binding(ustr); - while (symtab) { - Binding b = symtab->lookup_binding(ustr); + if (b.is_local()) { + assert(b.i_link() == 0); - if (b.is_local()) { - assert(b.i_link() == 0); + DVariable * vardef = symtab->lookup_var(b); + assert(vardef); - DVariable * vardef = symtab->lookup_var(b); - assert(vardef); + /** ascii diagram here + **/ - - /** ascii diagram here - **/ - - return DVarRef::make(expr_alloc_, - vardef, - link_count); - } else { - assert(b.is_null()); - } - - ++link_count; - symtab = symtab->parent(); + return DVarRef::make(expr_alloc_, + vardef, + link_count); + } else { + assert(b.is_null()); } - } else { - // if we don't already know the symbol, - // -> can't be a valid variable reference - // (whether global or local) - return nullptr; + ++link_count; + symtab = symtab->parent(); } } - // TODO: check global symtab also + DVariable * vardef = global_symtab_->lookup_variable(ustr); - log.retroactively_enable(); - log("STUB: check global symtab"); + if (vardef) { + return DVarRef::make(expr_alloc_, + vardef, + 0 /*link_count -- n/a for globals*/); + } + + // symbol not found return nullptr; } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 665342dc..e4a0e1de 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ namespace xo { using xo::scm::AExpression; using xo::scm::DDefineExpr; using xo::scm::DApplyExpr; + using xo::scm::DVarRef; using xo::scm::DConstant; //using xo::scm::ParserResult; @@ -232,7 +234,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -267,6 +269,72 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-interactive-def2", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + { + /** Walkthrough parsing input equivalent to: + * + * def foo : f64 = 3.141593 ; + * + **/ + + std::vector tk_v{ + Token::def_token(), + Token::symbol_token("foo"), + Token::colon_token(), + Token::symbol_token("f64"), + Token::singleassign_token(), + Token::f64_token("3.141593"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + + parser.reset_result(); + } + + { + /** Walkthrough parsing input equivalent to: + * + * foo ; + * + **/ + + std::vector tk_v{ +// Token::f64_token("2.0"), +// Token::star_token(), + Token::symbol_token("foo"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + } + + log && fixture.log_memory_layout(&log); + } + TEST_CASE("SchematikaParser-interactive-integer", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); From 121fb2dfad94fcaaf1ca50142121370a13b88641 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 17 Feb 2026 14:42:17 -0500 Subject: [PATCH 237/342] xo-interpreter2 stack: define-expr's work at top-level --- include/xo/reader2/ParserStateMachine.hpp | 21 ++++++++++++--------- include/xo/reader2/SchematikaParser.hpp | 2 ++ include/xo/reader2/SchematikaReader.hpp | 3 +++ src/reader2/SchematikaParser.cpp | 6 ++++++ src/reader2/SchematikaReader.cpp | 6 ++++++ utest/SchematikaParser.test.cpp | 1 + 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 2dfba437..f2654e1c 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -71,6 +71,7 @@ namespace xo { bool debug_flag() const noexcept { return debug_flag_; } ParserStack * stack() const noexcept { return stack_; } obj expr_alloc() const noexcept { return expr_alloc_; } + DGlobalSymtab * global_symtab() const noexcept { return global_symtab_.data(); } DLocalSymtab * local_symtab() const noexcept { return local_symtab_; } const ParserResult & result() const noexcept { return result_; } @@ -315,6 +316,17 @@ namespace xo { **/ obj aux_alloc_; + /** global symbol table. + * Toplevel definitions go here. + * + * Uses mmap -> non-trivial destructor. + * + * TODO: may want to move ownership upstairs. + * if so, along with stringtable_. + * maybe new struct ParserState? + **/ + dp global_symtab_; + /** symbol table with local bindings. * non-null during parsing of lambda expressions. * Always allocated from @p expr_alloc_. @@ -323,15 +335,6 @@ namespace xo { **/ DLocalSymtab * local_symtab_ = nullptr; - /** global symbol table. - * Toplevel definitions go here. - * - * Uses mmap -> non-trivial destructor. - * - * TODO: may want to move ownership upstairs - **/ - dp global_symtab_; - /** current output from parser **/ ParserResult result_; diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 45b45c19..96de8628 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -183,6 +183,8 @@ namespace xo { /** scm-schematikaparser-access-methods **/ ///@{ + DGlobalSymtab * global_symtab() const noexcept; + bool debug_flag() const { return debug_flag_; } /** true if parser is at top-level, diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index 5a4243a1..efd031ca 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -54,6 +54,9 @@ namespace xo { /** non-trivial dtor because of @p parser **/ ~SchematikaReader() = default; + /** top-level symbol table **/ + DGlobalSymtab * global_symtab() const noexcept; + /** visit reader-owned memory pools; call visitor(info) for each. * Specifically exclude expr_alloc, since we don't consider * that reader-owned diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 1bb188cb..25b3bc7f 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -32,6 +32,12 @@ namespace xo { { } + DGlobalSymtab * + SchematikaParser::global_symtab() const noexcept + { + return psm_.global_symtab(); + } + bool SchematikaParser::is_at_toplevel() const { diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index 98d44112..c3e13254 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -24,6 +24,12 @@ namespace xo { { } + DGlobalSymtab * + SchematikaReader::global_symtab() const noexcept + { + return parser_.global_symtab(); + } + void SchematikaReader::visit_pools(const MemorySizeVisitor & visitor) const { diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index e4a0e1de..6153ecb7 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -117,6 +117,7 @@ namespace xo { aux_arena_.visit_pools(visitor); FacetRegistry::instance().visit_pools(visitor); + TypeRegistry::instance().visit_pools(visitor); expr_arena_->visit_pools(visitor); parser_->visit_pools(visitor); From 27c5f66e742a60b2185ada590cb672628674cedf Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 17 Feb 2026 16:48:20 -0500 Subject: [PATCH 238/342] xo-reader2: allow formals w/out explicit type --- idl/SyntaxStateMachine.json5 | 11 ++ include/xo/reader2/DExpectFormalArgSsm.hpp | 6 ++ .../xo/reader2/DExpectFormalArglistSsm.hpp | 24 +++++ include/xo/reader2/DSyntaxStateMachine.hpp | 17 +++ include/xo/reader2/ParserStateMachine.hpp | 19 +++- .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 2 + .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../ssm/ISyntaxStateMachine_DApplySsm.hpp | 2 + .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 + .../ISyntaxStateMachine_DExpectExprSsm.hpp | 2 + ...SyntaxStateMachine_DExpectFormalArgSsm.hpp | 2 + ...axStateMachine_DExpectFormalArglistSsm.hpp | 2 + .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 + .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 + .../ssm/ISyntaxStateMachine_DIfElseSsm.hpp | 2 + .../ssm/ISyntaxStateMachine_DLambdaSsm.hpp | 2 + .../ssm/ISyntaxStateMachine_DParenSsm.hpp | 2 + .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 2 + .../ssm/ISyntaxStateMachine_DSequenceSsm.hpp | 2 + .../ISyntaxStateMachine_DToplevelSeqSsm.hpp | 2 + .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 3 + .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 + src/reader2/DExpectFormalArgSsm.cpp | 23 +++- src/reader2/DExpectFormalArglistSsm.cpp | 102 ++++++++++++------ src/reader2/ISyntaxStateMachine_Any.cpp | 6 ++ src/reader2/ISyntaxStateMachine_DApplySsm.cpp | 5 + .../ISyntaxStateMachine_DDefineSsm.cpp | 5 + .../ISyntaxStateMachine_DExpectExprSsm.cpp | 5 + ...SyntaxStateMachine_DExpectFormalArgSsm.cpp | 5 + ...axStateMachine_DExpectFormalArglistSsm.cpp | 5 + .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 + .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 + .../ISyntaxStateMachine_DIfElseSsm.cpp | 5 + .../ISyntaxStateMachine_DLambdaSsm.cpp | 5 + src/reader2/ISyntaxStateMachine_DParenSsm.cpp | 5 + .../ISyntaxStateMachine_DProgressSsm.cpp | 5 + .../ISyntaxStateMachine_DSequenceSsm.cpp | 5 + .../ISyntaxStateMachine_DToplevelSeqSsm.cpp | 5 + src/reader2/ParserStateMachine.cpp | 39 +++++++ 39 files changed, 311 insertions(+), 36 deletions(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 210a43a4..4cafd9c3 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -85,6 +85,17 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_parsed_formal_with_token", + doc: ["operate state machine for formal emitted by nested ssm"], + return_type: "void", + args: [ + {type: "const DUniqueString *", name: "param_name"}, + {type: "TypeDescr", name: "param_type"}, + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_parsed_formal_arglist", doc: ["consume formal arglist emitted by nested ssm"], diff --git a/include/xo/reader2/DExpectFormalArgSsm.hpp b/include/xo/reader2/DExpectFormalArgSsm.hpp index 62f5ae34..f1bd7867 100644 --- a/include/xo/reader2/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/DExpectFormalArgSsm.hpp @@ -79,6 +79,12 @@ namespace xo { void on_colon_token(const Token & tk, ParserStateMachine * p_psm); + /** update state on incoming rightparen token @p tk; + * with overall parser state in @p p_psm + **/ + void on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expectformalargssm-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index 203c7293..3129f0dc 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -55,6 +55,7 @@ namespace xo { class DExpectFormalArglistSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; + using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; using ppindentinfo = xo::print::ppindentinfo; @@ -108,6 +109,14 @@ namespace xo { void on_parsed_formal(const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** update state to consume parsed formal (name,type) emitted + * by nested ssm, that's followed immediately by token @p tk. + * overall parser state in @p *p_psm + **/ + void on_parsed_formal_with_token(const DUniqueString * param_name, + TypeDescr param_type, + const Token & tk, + ParserStateMachine * p_psm); ///@} /** @defgroup scm-expectformalarglistssm-printable-facet printable facet methods **/ @@ -117,6 +126,21 @@ namespace xo { ///@} + private: + /** @defgroup scm-expectformalarglistssm-impl-methods **/ + ///@{ + + /** update local state to include parsed formal (param_name, param_type). + * If stack memory needed, get from @p parser_alloc. + * Lifetime until formal arglist completely parsed + **/ + void _accept_formal(obj expr_alloc, + DArena & parser_alloc, + const DUniqueString * param_name, + TypeDescr param_type); + + ///@} + private: /** parsing state-machine state **/ formalarglstatetype fastate_ = formalarglstatetype::argl_0; diff --git a/include/xo/reader2/DSyntaxStateMachine.hpp b/include/xo/reader2/DSyntaxStateMachine.hpp index 947d3b84..5851390b 100644 --- a/include/xo/reader2/DSyntaxStateMachine.hpp +++ b/include/xo/reader2/DSyntaxStateMachine.hpp @@ -83,6 +83,23 @@ namespace xo { self.get_expect_str()); } + /** Default implementation for required SyntaxStateMachine facet method + **/ + void on_parsed_formal_with_token(const DUniqueString * param_name, + TypeDescr param_type, + const Token & tk, + ParserStateMachine * p_psm) + { + // starting with c++23 can use "this auto&& self" instead + Derived & self = reinterpret_cast(*this); + + p_psm->illegal_parsed_formal_with_token(Derived::ssm_classname(), + param_name, + param_type, + tk, + self.get_expect_str()); + } + /** Default implementation for required SyntaxStateMachine facet method * * arglist is DArray of obj diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index f2654e1c..bec90ae8 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -149,12 +149,20 @@ namespace xo { **/ void on_parsed_typedescr(TypeDescr td); - /** update state to consume param (name, value) emitted by + /** update state to consume param (name, type) emitted by * nested (expired) parsing state **/ void on_parsed_formal(const DUniqueString * param_name, TypeDescr param_type); + /** update state to consume formal parameter (name, type) + * emitted by nested (now expired) parsing state, + * with trailing token @p tk + **/ + void on_parsed_formal_with_token(const DUniqueString * param_name, + TypeDescr param_type, + const Token & tk); + /** update state to consume formal arugment list * emitted by nested (expired) parsing state **/ @@ -231,6 +239,15 @@ namespace xo { TypeDescr param_type, std::string_view expect_str); + /** report illegal parsed formal (param_name, param_type) from nested ssm; + * presented with immediately-following input token @p tk. + **/ + void illegal_parsed_formal_with_token(std::string_view ssm_name, + const DUniqueString * param_name, + TypeDescr param_type, + const Token & tk, + std::string_view expect_str); + /** @p arglist stores obj pointers. **/ void illegal_parsed_formal_arglist(std::string_view ssm_name, diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index 93a0e402..6b2976e1 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -67,6 +67,8 @@ public: virtual void on_parsed_typedescr(Opaque data, TypeDescr td, ParserStateMachine * p_psm) = 0; /** operate state machine for formal emitted by nested ssm **/ virtual void on_parsed_formal(Opaque data, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) = 0; + /** operate state machine for formal emitted by nested ssm **/ + virtual void on_parsed_formal_with_token(Opaque data, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) = 0; /** consume formal arglist emitted by nested ssm **/ virtual void on_parsed_formal_arglist(Opaque data, DArray * arglist, ParserStateMachine * p_psm) = 0; /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 05d292cc..8eb513c9 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -67,6 +67,7 @@ namespace scm { [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; [[noreturn]] void on_parsed_formal(Opaque, const DUniqueString *, TypeDescr, ParserStateMachine *) override; + [[noreturn]] void on_parsed_formal_with_token(Opaque, const DUniqueString *, TypeDescr, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_formal_arglist(Opaque, DArray *, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression(Opaque, obj, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression_with_token(Opaque, obj, const Token &, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp index d6b1a53e..eb9b10fa 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DApplySsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DApplySsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DApplySsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DApplySsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index 0a8ff60d..8fee27fd 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DDefineSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index e425386e..b452860f 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DExpectExprSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectExprSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DExpectExprSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DExpectExprSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp index 4c8e8c44..466dce8b 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DExpectFormalArgSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectFormalArgSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DExpectFormalArgSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DExpectFormalArgSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp index 2540684c..571255f9 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DExpectFormalArglistSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectFormalArglistSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DExpectFormalArglistSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DExpectFormalArglistSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 4b4ea7dd..d8367631 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DExpectSymbolSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectSymbolSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DExpectSymbolSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DExpectSymbolSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index 49c0ffe4..87b5db71 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DExpectTypeSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DExpectTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DExpectTypeSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp index f1594b02..d1373a1a 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DIfElseSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DIfElseSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DIfElseSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DIfElseSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp index 062de20c..3c945b94 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DLambdaSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DLambdaSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DLambdaSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DLambdaSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp index 33be5e16..19e4a89b 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DParenSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DParenSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DParenSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DParenSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 0d776976..13a2d461 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DProgressSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DProgressSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DProgressSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DProgressSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp index 90c17b36..7e0cfb42 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DSequenceSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DSequenceSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DSequenceSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DSequenceSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp index 1d91c13d..69a3c71f 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp @@ -62,6 +62,8 @@ namespace xo { static void on_parsed_typedescr(DToplevelSeqSsm & self, TypeDescr td, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DToplevelSeqSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DToplevelSeqSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DToplevelSeqSsm & self, DArray * arglist, ParserStateMachine * p_psm); /** update state machine for incoming parsed expression @p expr **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 971f08b8..30c87269 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -67,6 +67,9 @@ namespace scm { void on_parsed_formal(Opaque data, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) override { return I::on_parsed_formal(_dcast(data), param_name, param_type, p_psm); } + void on_parsed_formal_with_token(Opaque data, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) override { + return I::on_parsed_formal_with_token(_dcast(data), param_name, param_type, tk, p_psm); + } void on_parsed_formal_arglist(Opaque data, DArray * arglist, ParserStateMachine * p_psm) override { return I::on_parsed_formal_arglist(_dcast(data), arglist, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 28be39be..8012b657 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -73,6 +73,9 @@ public: void on_parsed_formal(const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) { return O::iface()->on_parsed_formal(O::data(), param_name, param_type, p_psm); } + void on_parsed_formal_with_token(const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) { + return O::iface()->on_parsed_formal_with_token(O::data(), param_name, param_type, tk, p_psm); + } void on_parsed_formal_arglist(DArray * arglist, ParserStateMachine * p_psm) { return O::iface()->on_parsed_formal_arglist(O::data(), arglist, p_psm); } diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index 47d55f6a..bbb9048e 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -97,6 +97,10 @@ namespace xo { case tokentype::tk_colon: this->on_colon_token(tk, p_psm); return; + case tokentype::tk_rightparen: + this->on_rightparen_token(tk, p_psm); + return; + // all the not-yet-handled cases case tokentype::tk_leftparen: case tokentype::tk_lambda: @@ -110,7 +114,6 @@ namespace xo { case tokentype::tk_bool: case tokentype::tk_semicolon: case tokentype::tk_invalid: - case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: @@ -159,6 +162,24 @@ namespace xo { Super::on_token(tk, p_psm); } + void + DExpectFormalArgSsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (fstate_ == formalstatetype::formal_1) { + // formal with no type annotation + + assert(name_); + + p_psm->pop_ssm(); + p_psm->on_parsed_formal_with_token(name_, nullptr, tk); + + return; + } + + Super::on_token(tk, p_psm); + } + void DExpectFormalArgSsm::on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 3ce11ae8..53dcf30c 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -176,6 +176,49 @@ namespace xo { Super::on_token(tk, p_psm); } + + void + DExpectFormalArglistSsm::_accept_formal(obj expr_alloc, + DArena & parser_alloc, + const DUniqueString * param_name, + TypeDescr param_type) + { + /* note: param_type can be nullptr */ + TypeRef typeref + = TypeRef::dwim(TypeRef::prefix_type::from_chars("formal"), param_type); + + DVariable * var = DVariable::make(expr_alloc, + param_name, + typeref); + + // need AGCObject facet to use DArray here. + // May want to have gc feature that allows it to use + // FacetRegistry on memory that stores obj + // + // In this case doesn't matter since DExpectFormalArglistSsm not actually collected! + + obj var_o(var); + + if (argl_->size() == argl_->capacity()) { + // need to expand argl_ capacity. + // If DArena were to allow it (i.e. offer a realloc() feature, + // could do this in place since this SSM is at the top of the parser stack. + + obj mm(&parser_alloc); + DArray * argl_2x = DArray::empty(mm, 2 * argl_->capacity()); + + for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { + // TODO: prefer non-bounds-checked access here + argl_2x->push_back(argl_->at(i)); + } + + // update in place + this->argl_ = argl_2x; + } + + this->argl_->push_back(var_o); + } + void DExpectFormalArglistSsm::on_parsed_formal(const DUniqueString * param_name, TypeDescr param_type, @@ -184,46 +227,37 @@ namespace xo { if (fastate_ == formalarglstatetype::argl_1a) { this->fastate_ = formalarglstatetype::argl_1b; - TypeRef typeref - = TypeRef::dwim(TypeRef::prefix_type::from_chars("formal"), param_type); - - DVariable * var = DVariable::make(p_psm->expr_alloc(), - param_name, - typeref); - - // need AGCObject facet to use DArray here. - // May want to have gc feature that allows it to use - // FacetRegistry on memory that stores obj - // - // In this case doesn't matter since DExpectFormalArglistSsm not actually collected! - - obj var_o(var); - - if (argl_->size() == argl_->capacity()) { - // need to expand argl_ capacity. - // If DArena were to allow it (i.e. offer a realloc() feature, - // could do this in place since this SSM is at the top of the parser stack. - - obj mm(&(p_psm->parser_alloc())); - - DArray * argl_2x = DArray::empty(mm, 2 * argl_->capacity()); - - for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { - // TODO: prefer non-bounds-checked access here - argl_2x->push_back(argl_->at(i)); - } - - // update in place - this->argl_ = argl_2x; - } - - this->argl_->push_back(var_o); + this->_accept_formal(p_psm->expr_alloc(), + p_psm->parser_alloc(), + param_name, + param_type); return; } Super::on_parsed_formal(param_name, param_type, p_psm); } + void + DExpectFormalArglistSsm::on_parsed_formal_with_token(const DUniqueString * param_name, + TypeDescr param_type, + const Token & tk, + ParserStateMachine * p_psm) + { + if (fastate_ == formalarglstatetype::argl_1a) { + this->fastate_ = formalarglstatetype::argl_1b; + + this->_accept_formal(p_psm->expr_alloc(), + p_psm->parser_alloc(), + param_name, + param_type); + + this->on_token(tk, p_psm); + return; + } + + Super::on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + void DExpectFormalArglistSsm::on_leftparen_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 6a78fa5e..393fea04 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -58,6 +58,12 @@ ISyntaxStateMachine_Any::on_parsed_formal(Opaque, const DUniqueString *, TypeDes _fatal(); } +auto +ISyntaxStateMachine_Any::on_parsed_formal_with_token(Opaque, const DUniqueString *, TypeDescr, const Token &, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_parsed_formal_arglist(Opaque, DArray *, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DApplySsm.cpp b/src/reader2/ISyntaxStateMachine_DApplySsm.cpp index 2164ae04..bcc672a4 100644 --- a/src/reader2/ISyntaxStateMachine_DApplySsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DApplySsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DApplySsm::on_parsed_formal_with_token(DApplySsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DApplySsm::on_parsed_formal_arglist(DApplySsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index 8940c1b5..dad9d0e8 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DDefineSsm::on_parsed_formal_with_token(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DDefineSsm::on_parsed_formal_arglist(DDefineSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index 17f0ec3f..855135e6 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DExpectExprSsm::on_parsed_formal_with_token(DExpectExprSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DExpectExprSsm::on_parsed_formal_arglist(DExpectExprSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp index 77afbe60..948a4fe2 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_formal_with_token(DExpectFormalArgSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_formal_arglist(DExpectFormalArgSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp index 619f2ceb..f56a90d2 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_formal_with_token(DExpectFormalArglistSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_formal_arglist(DExpectFormalArglistSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index efd7b893..77f0fd10 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_formal_with_token(DExpectSymbolSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_formal_arglist(DExpectSymbolSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 32e07aaa..f5f650ae 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DExpectTypeSsm::on_parsed_formal_with_token(DExpectTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DExpectTypeSsm::on_parsed_formal_arglist(DExpectTypeSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp index 3dbd66a8..d5a78844 100644 --- a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DIfElseSsm::on_parsed_formal_with_token(DIfElseSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DIfElseSsm::on_parsed_formal_arglist(DIfElseSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp index 967e328a..f99ab05d 100644 --- a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DLambdaSsm::on_parsed_formal_with_token(DLambdaSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DLambdaSsm::on_parsed_formal_arglist(DLambdaSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp index 1bb2ea83..0773ff3f 100644 --- a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DParenSsm::on_parsed_formal_with_token(DParenSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DParenSsm::on_parsed_formal_arglist(DParenSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 4cb25bf4..0e1e4a4c 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DProgressSsm::on_parsed_formal_with_token(DProgressSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DProgressSsm::on_parsed_formal_arglist(DProgressSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp index b27f25ba..bc6ab823 100644 --- a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DSequenceSsm::on_parsed_formal_with_token(DSequenceSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DSequenceSsm::on_parsed_formal_arglist(DSequenceSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp index 4dfe35a8..6850aee1 100644 --- a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp @@ -48,6 +48,11 @@ namespace xo { self.on_parsed_formal(param_name, param_type, p_psm); } auto + ISyntaxStateMachine_DToplevelSeqSsm::on_parsed_formal_with_token(DToplevelSeqSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto ISyntaxStateMachine_DToplevelSeqSsm::on_parsed_formal_arglist(DToplevelSeqSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void { self.on_parsed_formal_arglist(arglist, p_psm); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 856a8215..dee9e4b2 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -286,6 +286,18 @@ namespace xo { this->stack_->top().on_parsed_formal(sym, td, this); } + void + ParserStateMachine::on_parsed_formal_with_token(const DUniqueString * sym, + TypeDescr td, + const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("sym", std::string_view(*sym)), xtag("td", td), xtag("tk", tk)); + + assert(stack_); + + this->stack_->top().on_parsed_formal_with_token(sym, td, tk, this); + } + void ParserStateMachine::on_parsed_formal_arglist(DArray * arglist) { @@ -446,6 +458,33 @@ namespace xo { this->capture_error(ssm_name, errmsg); } + void + ParserStateMachine::illegal_parsed_formal_with_token(std::string_view ssm_name, + const DUniqueString * param_name, + TypeDescr param_type, + const Token & tk, + std::string_view expect_str) + { + // TODO: + // - want to write error message using DArena + // - need something like log_streambuf and/or tostr() that's arena-aware + + auto errmsg_string = tostr("Unexpected formal", + xtag("param_name", std::string_view(*param_name)), + xtag("param_type", param_type), + xtag("tk", tk), + xtag("expecting", expect_str), + xtag("ssm", ssm_name), + xtag("via", "ParserStateMachine::illegal_parsed_formal")); + + assert(expr_alloc_); + + auto errmsg = DString::from_view(expr_alloc_, + std::string_view(errmsg_string)); + + this->capture_error(ssm_name, errmsg); + } + void ParserStateMachine::illegal_parsed_formal_arglist(std::string_view ssm_name, DArray * arglist, From 9cb3c4b5b65a97d8d9e05ea82bc47498b415d9d6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 17 Feb 2026 18:32:41 -0500 Subject: [PATCH 239/342] xo-reader2: recursive top-level function definition works --- include/xo/reader2/DExpectExprSsm.hpp | 16 +++++++ include/xo/reader2/DParenSsm.hpp | 8 ++++ src/reader2/DExpectExprSsm.cpp | 43 ++++++++++++++++-- src/reader2/DIfElseSsm.cpp | 65 +++++++++++++++++++++++++-- src/reader2/DParenSsm.cpp | 16 +++++++ src/reader2/DProgressSsm.cpp | 25 +++++++++-- utest/SchematikaParser.test.cpp | 62 ++++++++++++++++++++++++- 7 files changed, 222 insertions(+), 13 deletions(-) diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index c963c9c1..7600948c 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -51,6 +51,12 @@ namespace xo { /** @defgroup scm-expectexpr-methods general methods **/ ///@{ + /** update state for this syntax on incoming leftparen token @p tk, + * with overall parser state in @p p_psm + **/ + void on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming leftbrace token @p tk, * with overall parser state in @p p_psm **/ @@ -81,8 +87,18 @@ namespace xo { void on_string_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming if-token @p tk, + * overall parser state in @p p_psm. + * + * action: start nested if-else ssm + **/ + void on_if_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming lambda token @p tk, * overall parser state in @p p_psm + * + * action: start nested lambda ssm **/ void on_lambda_token(const Token & tk, ParserStateMachine * p_psm); diff --git a/include/xo/reader2/DParenSsm.hpp b/include/xo/reader2/DParenSsm.hpp index 818e0470..05c3926b 100644 --- a/include/xo/reader2/DParenSsm.hpp +++ b/include/xo/reader2/DParenSsm.hpp @@ -116,6 +116,14 @@ namespace xo { void on_parsed_expression(obj expr, ParserStateMachine * p_psm); + /** update ssm for expression @p expr (emitted by nested ssm) + * that's immediately followed by token @p tk + * with overall parser state in @p p_psm + **/ + void on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psmn); + ///@} /** @defgroup scm-parenssm-printable-facet printable facet methods **/ ///@{ diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index a2db5967..445ee76d 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -8,6 +8,7 @@ #include "SyntaxStateMachine.hpp" #include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" #include "DSequenceSsm.hpp" +#include "IfElseSsm.hpp" #include "LambdaSsm.hpp" #include "syntaxstatetype.hpp" #include @@ -103,9 +104,9 @@ namespace xo { DExpectExprSsm::get_expect_str() const noexcept { if (allow_defs_) { - return "def|lambda|lparen|lbrace|literal|var"; + return "def|if|lambda|lparen|lbrace|literal|var"; } else { - return "lambda|lparen|lbrace|literal|var"; + return "if|lambda|lparen|lbrace|literal|var"; } } @@ -116,6 +117,10 @@ namespace xo { scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); switch (tk.tk_type()) { + case tokentype::tk_leftparen: + this->on_leftparen_token(tk, p_psm); + return; + case tokentype::tk_leftbrace: this->on_leftbrace_token(tk, p_psm); return; @@ -144,17 +149,19 @@ namespace xo { this->on_bool_token(tk, p_psm); return; + case tokentype::tk_if: + this->on_if_token(tk, p_psm); + return; + case tokentype::tk_lambda: this->on_lambda_token(tk, p_psm); return; // all the not-yet handled cases case tokentype::tk_invalid: - case tokentype::tk_if: case tokentype::tk_singleassign: case tokentype::tk_colon: case tokentype::tk_semicolon: - case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: @@ -187,6 +194,22 @@ namespace xo { Super::on_token(tk, p_psm); } + void + DExpectExprSsm::on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + // need progress ssm here because this is allowed: + // + // if (foo) > 5 then ... + // + // Start progress ssm, delegate incoming token thereto + // + + DProgressSsm::start(p_psm->parser_alloc(), + p_psm); + p_psm->on_token(tk); + } + void DExpectExprSsm::on_leftbrace_token(const Token & tk, ParserStateMachine * p_psm) @@ -388,6 +411,18 @@ namespace xo { p_psm); } + void + DExpectExprSsm::on_if_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + DIfElseSsm::start(p_psm->parser_alloc(), + p_psm->expr_alloc(), + p_psm); + // TODO: should send if-token here + } + void DExpectExprSsm::on_lambda_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index e78d187b..b7d150af 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -423,14 +423,71 @@ namespace xo { // TODO: may consider allowing if-else to terminate on other particular tokens // e.g. ')' - if ((tk.tk_type() == tokentype::tk_then) - || (tk.tk_type() == tokentype::tk_else) - || (tk.tk_type() == tokentype::tk_semicolon)) - { + switch (ifstate_) { + case ifexprstatetype::invalid: + case ifexprstatetype::N: + // impossible + assert(false); + break; + case ifexprstatetype::if_0: + // also unreachable + break; + case ifexprstatetype::if_1: + // only ok if tk-type is tk_then. + if (tk.tk_type() == tokentype::tk_then) { + // advance to if_2 -then-> if_3 this->on_parsed_expression(expr, p_psm); this->on_token(tk, p_psm); return; } + break; + case ifexprstatetype::if_2: + // illegal, not expecting expression + break; + case ifexprstatetype::if_3: + // incoming expr argument is sufficient to complete this if-else + // but may continue on else-token + if (tk.tk_type() == tokentype::tk_else) { + // advance to if_4 -else-> if_5 + this->on_parsed_expression(expr, p_psm); + this->on_token(tk, p_psm); + return; + } else if ((tk.tk_type() == tokentype::tk_semicolon) + || (tk.tk_type() == tokentype::tk_rightparen) + || (tk.tk_type() == tokentype::tk_rightbrace)) { + + this->on_parsed_expression(expr, p_psm); + p_psm->pop_ssm(); + p_psm->on_parsed_expression_with_token(if_expr_, tk); + return; + } + + break; + case ifexprstatetype::if_4: + // illegal, not expecting expression + break; + + case ifexprstatetype::if_5: + // incoming expr argument completes this if-else + // advance to if_6 + if ((tk.tk_type() == tokentype::tk_semicolon) + || (tk.tk_type() == tokentype::tk_rightparen) + || (tk.tk_type() == tokentype::tk_rightbrace)) + { + // attaches expr as else- branch + this->on_parsed_expression(expr, p_psm); + + p_psm->pop_ssm(); + p_psm->on_parsed_expression_with_token(if_expr_, tk); + return; + } + break; + + case ifexprstatetype::if_6: + // illegal, not expecting expression + break; + + } Super::on_parsed_expression_with_token(expr, tk, p_psm); } diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index ad86ddd5..b89dec52 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -364,7 +364,23 @@ namespace xo { } Super::on_parsed_expression(expr, p_psm); + } + void + DParenSsm::on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm) + { + if (parenstate_ == parenexprstatetype::lparen_1) { + this->parenstate_ = parenexprstatetype::lparen_2; + this->expr_ = expr; + + this->on_token(tk, p_psm); + + return; + } + + Super::on_parsed_expression(expr, p_psm); } #ifdef NOT_YET diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 4af449c0..72ec3e93 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -41,6 +41,7 @@ namespace xo { using xo::scm::Variable; using xo::scm::Apply; #endif + using xo::mm::AGCObject; using xo::print::APrintable; using xo::facet::FacetRegistry; using xo::facet::with_facet; @@ -214,7 +215,7 @@ namespace xo { if (!lhs_) { return "expr1|leftparen"; } else if (op_type_ == optype::invalid) { - return "oper|semicolon|rightparen|righbrace"; + return "oper|semicolon|rightparen|rightbrace"; } else { return "expr2|leftparen"; } @@ -293,10 +294,10 @@ namespace xo { case tokentype::tk_assign: case tokentype::tk_yields: case tokentype::tk_plus: - case tokentype::tk_minus: break; case tokentype::tk_star: + case tokentype::tk_minus: case tokentype::tk_cmpeq: this->on_operator_token(tk, p_psm); return; @@ -1244,7 +1245,6 @@ namespace xo { case optype::op_great: case optype::op_great_equal: case optype::op_add: - case optype::op_subtract: assert(false); break; @@ -1286,6 +1286,24 @@ namespace xo { // TODO: implement binary operator expression assembly assert(false); break; + case optype::op_subtract: /* editor bait: op_minus */ + { + auto pm_obj = (with_facet::mkobj + (&Primitives::s_sub_gco_gco_pm)); + auto fn_expr = (DConstant::make + (p_psm->expr_alloc(), pm_obj)); + + // see comment on op_multiply re need for poly impl + + TypeRef tref = TypeRef::dwim + (TypeRef::prefix_type::from_chars("_sub_gco"), + nullptr); + + return DApplyExpr::make2(p_psm->expr_alloc(), + tref, fn_expr, lhs_, rhs_); + } + + break; #ifdef NOT_YET case optype::op_assign: @@ -1308,6 +1326,7 @@ case optype::op_equal: if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { return Apply::make_cmp_eq_i64(lhs_, rhs_); } else { + this->apply_type_error(c_self_name, op_type_, lhs_, rhs_, p_psm); return nullptr; diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 6153ecb7..2b92161a 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -274,7 +274,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -809,7 +809,7 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -861,6 +861,64 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-batch-def2", "[reader2][SchematikaParser]") + { + // top-level recursive function definition + + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * def fact = lambda (n) { if (n == 0) then 1 else n * fact(n - 1) }; + * ^ ^ ^ ^ ^^^ ^ ^ ^^ ^ ^^ ^ ^ ^ ^ ^ ^ ^^ ^ ^^ ^^ + * 0 1 2 3 4|6 7 8 9| b c| e f g h i j k| m n| p| + * 5 a d l o q + **/ + + std::vector tk_v{ + /* [ 0] */ Token::def_token(), + + /* [ 1] */ Token::symbol_token("fact"), + /* [ 2] */ Token::singleassign_token(), + /* [ 3] */ Token::lambda_token(), + /* [ 4] */ Token::leftparen_token(), + /* [ 5] */ Token::symbol_token("n"), + /* [ 6] */ Token::rightparen_token(), + /* [ 7] */ Token::leftbrace_token(), + /* [ 8] */ Token::if_token(), + /* [ 9] */ Token::leftparen_token(), + /* [ a] */ Token::symbol_token("n"), + /* [ b] */ Token::cmpeq_token(), + /* [ c] */ Token::i64_token("0"), + /* [ d] */ Token::rightparen_token(), + /* [ e] */ Token::then_token(), + /* [ f] */ Token::i64_token("1"), + /* [ g] */ Token::else_token(), + /* [ h] */ Token::symbol_token("n"), + /* [ i] */ Token::star_token(), + /* [ j] */ Token::symbol_token("fact"), + /* [ k] */ Token::leftparen_token(), + /* [ l] */ Token::symbol_token("n"), + /* [ m] */ Token::minus_token(), + /* [ n] */ Token::i64_token("1"), + /* [ o] */ Token::rightparen_token(), + /* [ p] */ Token::rightbrace_token(), + /* [ q] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); + } + } /*namespace ut*/ } /*namespace xo*/ From 911818e9572b8da4757e2fced63cd7636cd2c0d0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 18 Feb 2026 21:47:02 -0800 Subject: [PATCH 240/342] xo-reader2 stack: + xo-numeric + setup multi dispatch for *,/ --- cmake/xo_reader2Config.cmake.in | 1 + src/reader2/CMakeLists.txt | 1 + src/reader2/DProgressSsm.cpp | 49 +++++++++++++++++++++----- src/reader2/init_reader2.cpp | 2 ++ utest/SchematikaParser.test.cpp | 61 +++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 8 deletions(-) diff --git a/cmake/xo_reader2Config.cmake.in b/cmake/xo_reader2Config.cmake.in index ed161c20..06d291b4 100644 --- a/cmake/xo_reader2Config.cmake.in +++ b/cmake/xo_reader2Config.cmake.in @@ -6,6 +6,7 @@ include(CMakeFindDependencyMacro) # must coordinate with xo_dependency() calls # in CMakeLists.txt # +find_dependency(xo_numeric) find_dependency(xo_procedure2) find_dependency(xo_gc) find_dependency(xo_tokenizer2) diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 6ad71cdf..f9c6511c 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -73,6 +73,7 @@ set(SELF_SRCS xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) # note: deps here must also appear in cmake/xo_expression2Config.cmake.in +xo_dependency(${SELF_LIB} xo_numeric) xo_dependency(${SELF_LIB} xo_procedure2) xo_dependency(${SELF_LIB} xo_gc) xo_dependency(${SELF_LIB} xo_tokenizer2) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 72ec3e93..eafe88b8 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -12,6 +12,8 @@ #include "ApplySsm.hpp" #include "ParenSsm.hpp" +#include + #include #include @@ -118,15 +120,15 @@ namespace xo { switch (tktype) { case tokentype::tk_assign: return optype::op_assign; - case tokentype::tk_plus: + case tokentype::tk_plus: // [+] return optype::op_add; - case tokentype::tk_minus: + case tokentype::tk_minus: // [-] return optype::op_subtract; - case tokentype::tk_star: + case tokentype::tk_star: // [*] return optype::op_multiply; - case tokentype::tk_slash: + case tokentype::tk_slash: // [/] return optype::op_divide; - case tokentype::tk_cmpeq: + case tokentype::tk_cmpeq: // [==] return optype::op_equal; case tokentype::tk_cmpne: return optype::op_not_equal; @@ -297,12 +299,12 @@ namespace xo { break; case tokentype::tk_star: + case tokentype::tk_slash: case tokentype::tk_minus: case tokentype::tk_cmpeq: this->on_operator_token(tk, p_psm); return; - case tokentype::tk_slash: case tokentype::tk_cmpne: case tokentype::tk_type: case tokentype::tk_lambda: @@ -1283,9 +1285,40 @@ namespace xo { break; case optype::op_divide: - // TODO: implement binary operator expression assembly - assert(false); + { + auto pm_obj = (with_facet::mkobj + (&NumericPrimitives::s_div_gco_gco_pm)); + auto fn_expr = (DConstant::make + (p_psm->expr_alloc(), pm_obj)); + + /* note: + * 1. don't assume we know lhs_ / rhs_ value types yet. + * perhaps have expression like + * f(..) * g(..) + * where f is the function that contains current ssm. + * + * 2. consequence: we need representation for + * polymorphic multiply on unknown numeric arguments. + * + * 3. TypeRef::dwim(..) is a placeholder. + * Plan to later provide abstract interpreter + * (ie compiler pass :) to drive type inference/unification + * + * 4. Alternatively could supply type-annotation syntax + * so human can assist inference; context here is we want + * to automate the boring stuff + */ + + TypeRef tref = TypeRef::dwim + (TypeRef::prefix_type::from_chars("_div_gco"), + nullptr); + + return DApplyExpr::make2(p_psm->expr_alloc(), + tref, fn_expr, lhs_, rhs_); + } + break; + case optype::op_subtract: /* editor bait: op_minus */ { auto pm_obj = (with_facet::mkobj diff --git a/src/reader2/init_reader2.cpp b/src/reader2/init_reader2.cpp index aa7e291c..a6e1a7b0 100644 --- a/src/reader2/init_reader2.cpp +++ b/src/reader2/init_reader2.cpp @@ -8,6 +8,7 @@ #include "reader2_register_types.hpp" #include +#include #include namespace xo { @@ -30,6 +31,7 @@ namespace xo { /* direct subsystem deps for xo-reader2/ */ retval ^= InitSubsys::require(); + retval ^= InitSubsys::require(); /* xo-reader2/'s own initialization code */ retval ^= Subsystem::provide("reader2", &init); diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 2b92161a..b6934f18 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -578,6 +578,67 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-interactive-arith2", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * 3.14159265 / 10.0 ; + * + **/ + + std::vector tk_v{ + Token::f64_token("3.14159265"), + Token::slash_token(), + Token::f64_token("10.0"), + Token::semicolon_token(), + }; + + INFO(testname); + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + + REQUIRE(expr->n_args() == 2); + + auto fn = obj::from(expr->fn()); + REQUIRE(fn); + + auto pm = obj::from(fn->value()); + REQUIRE(pm); + REQUIRE(pm->name() == "_div"); + + auto lhs = obj::from(expr->arg(0)); + REQUIRE(lhs); + + auto lhs_f64 = obj::from(lhs->value()); + REQUIRE(lhs_f64); + REQUIRE(lhs_f64->value() == 3.14159265); + + auto rhs = obj::from(expr->arg(1)); + REQUIRE(rhs); + + auto rhs_f64 = obj::from(rhs->value()); + REQUIRE(rhs_f64); + REQUIRE(rhs_f64->value() == 10.0); + } + + log && fixture.log_memory_layout(&log); + } + TEST_CASE("SchematikaParser-interactive-cmp", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); From dd0857160be3531c594645b9ffbbf730ca5e46c4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 18 Feb 2026 22:00:30 -0800 Subject: [PATCH 241/342] xo-interpreter2 stack: use xo-numeric/ to support op* --- src/reader2/DProgressSsm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index eafe88b8..dd201b65 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -1253,7 +1253,7 @@ namespace xo { case optype::op_multiply: { auto pm_obj = (with_facet::mkobj - (&Primitives::s_mul_gco_gco_pm)); + (&NumericPrimitives::s_mul_gco_gco_pm)); auto fn_expr = (DConstant::make (p_psm->expr_alloc(), pm_obj)); From 6575ab1c11bd58c124ac1383d50041db937b22ad Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 18 Feb 2026 22:40:37 -0800 Subject: [PATCH 242/342] xo-reader2 stack: use NumericDispatch for *,/,+,- ops --- src/reader2/DProgressSsm.cpp | 40 +++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index dd201b65..ad3a0297 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -295,11 +295,11 @@ namespace xo { case tokentype::tk_doublecolon: case tokentype::tk_assign: case tokentype::tk_yields: - case tokentype::tk_plus: break; case tokentype::tk_star: case tokentype::tk_slash: + case tokentype::tk_plus: case tokentype::tk_minus: case tokentype::tk_cmpeq: this->on_operator_token(tk, p_psm); @@ -1246,7 +1246,6 @@ namespace xo { case optype::op_less_equal: case optype::op_great: case optype::op_great_equal: - case optype::op_add: assert(false); break; @@ -1319,10 +1318,45 @@ namespace xo { break; + case optype::op_add: + { + auto pm_obj = (with_facet::mkobj + (&NumericPrimitives::s_add_gco_gco_pm)); + auto fn_expr = (DConstant::make + (p_psm->expr_alloc(), pm_obj)); + + /* note: + * 1. don't assume we know lhs_ / rhs_ value types yet. + * perhaps have expression like + * f(..) * g(..) + * where f is the function that contains current ssm. + * + * 2. consequence: we need representation for + * polymorphic multiply on unknown numeric arguments. + * + * 3. TypeRef::dwim(..) is a placeholder. + * Plan to later provide abstract interpreter + * (ie compiler pass :) to drive type inference/unification + * + * 4. Alternatively could supply type-annotation syntax + * so human can assist inference; context here is we want + * to automate the boring stuff + */ + + TypeRef tref = TypeRef::dwim + (TypeRef::prefix_type::from_chars("_add_gco"), + nullptr); + + return DApplyExpr::make2(p_psm->expr_alloc(), + tref, fn_expr, lhs_, rhs_); + } + + break; + case optype::op_subtract: /* editor bait: op_minus */ { auto pm_obj = (with_facet::mkobj - (&Primitives::s_sub_gco_gco_pm)); + (&NumericPrimitives::s_sub_gco_gco_pm)); auto fn_expr = (DConstant::make (p_psm->expr_alloc(), pm_obj)); From 8743aa44ef2f646fc7fea7cb9c2df2ef4fb381ff Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 19 Feb 2026 09:03:02 -0800 Subject: [PATCH 243/342] xo-interpreter2 stack: streamline op== impl + utests --- src/reader2/DProgressSsm.cpp | 58 ++++++++++++++++++++++- utest/SchematikaParser.test.cpp | 84 ++++++++++++++++++++++++++++++++- 2 files changed, 139 insertions(+), 3 deletions(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index ad3a0297..46321b0a 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -43,6 +43,7 @@ namespace xo { using xo::scm::Variable; using xo::scm::Apply; #endif + using xo::mm::AAllocator; using xo::mm::AGCObject; using xo::print::APrintable; using xo::facet::FacetRegistry; @@ -1185,6 +1186,45 @@ namespace xo { namespace { // make_builtin_apply_pm2 + + // helper function for making apply expression that invokes + // a binary primitive. Use for numeric operators: + // {*, /, +, -, ==} + // + obj + assemble_numeric_expr_aux(obj expr_alloc, + const TypeRef::prefix_type & prefix, + DPrimitive_gco_2_gco_gco * p_gco_pm, + obj lhs, + obj rhs) + { + auto pm_obj = with_facet::mkobj(p_gco_pm); + auto fn_expr = DConstant::make(expr_alloc, pm_obj); + + /* note: + * 1. don't assume we know lhs_ / rhs_ value types yet. + * perhaps have expression like + * f(..) * g(..) + * where f is the function that contains current ssm. + * + * 2. consequence: we need representation for + * polymorphic multiply on unknown numeric arguments. + * + * 3. TypeRef::dwim(..) is a placeholder. + * Plan to later provide abstract interpreter + * (ie compiler pass :) to drive type inference/unification + * + * 4. Alternatively could supply type-annotation syntax + * so human can assist inference; context here is we want + * to automate the boring stuff + */ + + TypeRef tref = TypeRef::dwim(prefix, nullptr); + + return DApplyExpr::make2(expr_alloc, + tref, fn_expr, lhs, rhs); + + } } obj @@ -1223,9 +1263,16 @@ namespace xo { break; case optype::op_equal: + return assemble_numeric_expr_aux + (p_psm->expr_alloc(), + TypeRef::prefix_type::from_chars("_cmpeq_gco"), + &NumericPrimitives::s_cmpeq_gco_gco_pm, + lhs_, rhs_); + +#ifdef OBSOLETE { auto pm_obj = (with_facet::mkobj - (&Primitives::s_equal_gco_gco_pm)); + (&NumericPrimitives::s_cmpeq_gco_gco_pm)); auto fn_expr = (DConstant::make (p_psm->expr_alloc(), pm_obj)); @@ -1240,6 +1287,7 @@ namespace xo { fn_expr, lhs_, rhs_); } break; +#endif case optype::op_not_equal: case optype::op_less: @@ -1250,6 +1298,13 @@ namespace xo { break; case optype::op_multiply: + return assemble_numeric_expr_aux + (p_psm->expr_alloc(), + TypeRef::prefix_type::from_chars("_mul_gco"), + &NumericPrimitives::s_mul_gco_gco_pm, + lhs_, rhs_); + +#ifdef OBSOLETE { auto pm_obj = (with_facet::mkobj (&NumericPrimitives::s_mul_gco_gco_pm)); @@ -1281,6 +1336,7 @@ namespace xo { return DApplyExpr::make2(p_psm->expr_alloc(), tref, fn_expr, lhs_, rhs_); } +#endif break; case optype::op_divide: diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index b6934f18..fa108af3 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ namespace xo { using xo::scm::AExpression; using xo::scm::DDefineExpr; + using xo::scm::DIfElseExpr; using xo::scm::DApplyExpr; using xo::scm::DVarRef; using xo::scm::DConstant; @@ -680,7 +682,7 @@ namespace xo { auto pm = obj::from(fn->value()); REQUIRE(pm); - REQUIRE(pm->name() == "_equal"); + REQUIRE(pm->name() == "_cmpeq"); auto lhs = obj::from(expr->arg(0)); REQUIRE(lhs); @@ -700,6 +702,84 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-interactive-if1", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), + xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + { + /** Walkthrough parsing input equivalent to: + * + * def n = 4 ; + * ^ ^ ^ ^ ^ + * 0 1 2 3 4 + **/ + + std::vector tk_v{ + /* [0] */ Token::def_token(), + /* [1] */ Token::symbol_token("n"), + /* [2] */ Token::singleassign_token(), + /* [3] */ Token::i64_token("4"), + /* [4] */ Token::semicolon_token() + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + } + + { + const auto & result = parser.result(); + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + + { + parser.reset_result(); + + /** Walkthrough parsing input equivalent to: + * + * if (n == 4) then 1 else n * 5 ; + * ^ ^^ ^ ^^ ^ ^ ^ ^ ^ ^ ^ + * 0 1| 3 4| 6 7 8 9 a b c + * 2 5 + **/ + + std::vector tk_v{ + /* [0] */ Token::if_token(), + /* [1] */ Token::leftparen_token(), + /* [2] */ Token::symbol_token("n"), + /* [3] */ Token::cmpeq_token(), + /* [4] */ Token::i64_token("4"), + /* [5] */ Token::rightparen_token(), + /* [6] */ Token::then_token(), + /* [7] */ Token::i64_token("1"), + /* [8] */ Token::else_token(), + /* [9] */ Token::symbol_token("n"), + /* [a] */ Token::star_token(), + /* [b] */ Token::i64_token("5"), + /* [c] */ Token::semicolon_token() + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + } + + const auto & result = parser.result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + + log && fixture.log_memory_layout(&log); + } + TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); @@ -743,7 +823,7 @@ namespace xo { log && fixture.log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-if2", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); From 4fc5f7d8ba193afe87dab5f41f0be5d3f927cab4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 19 Feb 2026 11:56:06 -0800 Subject: [PATCH 244/342] xo-interpreter2 stack: support op!= + trial numeric refactor --- src/reader2/DProgressSsm.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 46321b0a..9907869d 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -303,10 +303,10 @@ namespace xo { case tokentype::tk_plus: case tokentype::tk_minus: case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: this->on_operator_token(tk, p_psm); return; - case tokentype::tk_cmpne: case tokentype::tk_type: case tokentype::tk_lambda: break; @@ -1290,6 +1290,12 @@ namespace xo { #endif case optype::op_not_equal: + return assemble_numeric_expr_aux + (p_psm->expr_alloc(), + TypeRef::prefix_type::from_chars("_cmpne_gco"), + &NumericPrimitives::s_cmpne_gco_gco_pm, + lhs_, rhs_); + case optype::op_less: case optype::op_less_equal: case optype::op_great: From d6456ce921b05ba17f39879f60ec6c4adb1396e0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 23 Feb 2026 07:04:54 +1100 Subject: [PATCH 245/342] xo-reader2: bugfix: need pattern match to fix operator precedence --- src/reader2/DExpectExprSsm.cpp | 32 ++++++-- src/reader2/DProgressSsm.cpp | 29 +++++-- utest/SchematikaParser.test.cpp | 141 ++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 10 deletions(-) diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 445ee76d..459e3176 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -5,6 +5,7 @@ #include "ExpectExprSsm.hpp" #include "ParserStateMachine.hpp" +#include "ParserStack.hpp" #include "SyntaxStateMachine.hpp" #include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" #include "DSequenceSsm.hpp" @@ -28,15 +29,10 @@ #include "paren_xs.hpp" #include "sequence_xs.hpp" #include "progress_xs.hpp" -#include "xo/expression/Lambda.hpp" -#include "xo/expression/Constant.hpp" #include "xo/expression/pretty_expression.hpp" #endif namespace xo { -#ifdef NOT_YET - using xo::scm::Constant; -#endif using xo::scm::DFloat; using xo::mm::AGCObject; @@ -372,6 +368,32 @@ namespace xo { auto expr = DConstant::make(p_psm->expr_alloc(), i64o); + // Consider parser stack, with control here at b + // + // a * b - c + // ^ + // + // [1] ExpectExpr <-- this + // [0] ProgressSsm :lhs k(b) :op * :rhs _ + // + // if parent is ProgressSsm [0], need to deliver k(b) to it; + // Then let that ProgressSsm [0] establish whether next token + // is operator. + // + assert((void*)p_psm->stack()->top().data() == (void*)this); + + if (p_psm->stack()->parent()) { + auto parent_ssm = (obj::from + (p_psm->stack()->parent()->top())); + + if (parent_ssm) { + // parent is-a DProgressSsm instance + p_psm->pop_ssm(); + p_psm->on_parsed_expression(expr); + return; + } + } + // DProgressSsm responsible for resolving cases like // 1, // 1; diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 9907869d..371c7e88 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -125,13 +125,13 @@ namespace xo { return optype::op_add; case tokentype::tk_minus: // [-] return optype::op_subtract; - case tokentype::tk_star: // [*] + case tokentype::tk_star: // [*] return optype::op_multiply; - case tokentype::tk_slash: // [/] + case tokentype::tk_slash: // [/] return optype::op_divide; - case tokentype::tk_cmpeq: // [==] + case tokentype::tk_cmpeq: // [==] return optype::op_equal; - case tokentype::tk_cmpne: + case tokentype::tk_cmpne: // [!=] return optype::op_not_equal; case tokentype::tk_leftangle: return optype::op_less; @@ -362,7 +362,12 @@ namespace xo { ParserStateMachine * p_psm) { if (op_type_ == optype::invalid) { - // tk is the operator this instance was waiting for + // tk is the operator this instance was waiting for. + // But need to consider precedence. + // possibly need to take lhs_ expression and rotate it into new lhs of + // surrounding ProgressSsm + + this->op_type_ = tk2op(tk.tk_type()); DExpectExprSsm::start(p_psm); @@ -393,6 +398,7 @@ namespace xo { lhs2, op_type2, p_psm); + DExpectExprSsm::start(p_psm); return; } else { /* associate to the right @@ -512,6 +518,19 @@ namespace xo { log && log("accepting expr1"); this->lhs_ = expr; + + return; + } + + assert (op_type_ != optype::invalid); + + if (!rhs_) { + this->rhs_ = expr; + + // need next token before we know whether this DProgressSsm + // is complete. Consider input like 7 + 2 * 3 vs 7 * 2 + 3 + // + return; } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index fa108af3..18d1c0ee 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -641,6 +641,147 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-interactive-arith3", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * 7 * 2 - 3; + * + **/ + + std::vector tk_v{ + Token::i64_token("7"), + Token::star_token(), + Token::i64_token("2"), + Token::minus_token(), + Token::i64_token("3"), + Token::semicolon_token(), + }; + + INFO(testname); + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + REQUIRE(expr->n_args() == 2); + + auto fn = obj::from(expr->fn()); + REQUIRE(fn); + + auto pm = obj::from(fn->value()); + REQUIRE(pm); + REQUIRE(pm->name() == "_sub"); + + auto lhs = obj::from(expr->arg(0)); + REQUIRE(lhs); + + auto lhs_lhs = obj::from(lhs->arg(0)); + REQUIRE(lhs_lhs); + auto lhs_lhs_i64 = obj::from(lhs_lhs->value()); + REQUIRE(lhs_lhs_i64); + REQUIRE(lhs_lhs_i64->value() == 7); + + auto lhs_rhs = obj::from(lhs->arg(1)); + REQUIRE(lhs_rhs); + auto lhs_rhs_i64 = obj::from(lhs_rhs->value()); + REQUIRE(lhs_rhs_i64); + REQUIRE(lhs_rhs_i64->value() == 2); + + auto rhs = obj::from(expr->arg(1)); + REQUIRE(rhs); + + auto rhs_i64 = obj::from(rhs->value()); + REQUIRE(rhs_i64); + REQUIRE(rhs_i64->value() == 3); + } + + log && fixture.log_memory_layout(&log); + } + + TEST_CASE("SchematikaParser-interactive-arith3-bad", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * 7 * 2 - 3 4; + * + **/ + + std::vector tk_v{ + Token::i64_token("7"), + Token::star_token(), + Token::i64_token("2"), + Token::minus_token(), + Token::i64_token("3"), + Token::i64_token("4"), + Token::semicolon_token(), + }; + + INFO(testname); + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + REQUIRE(expr->n_args() == 2); + + auto fn = obj::from(expr->fn()); + REQUIRE(fn); + + auto pm = obj::from(fn->value()); + REQUIRE(pm); + REQUIRE(pm->name() == "_sub"); + + auto lhs = obj::from(expr->arg(0)); + REQUIRE(lhs); + + auto lhs_lhs = obj::from(lhs->arg(0)); + REQUIRE(lhs_lhs); + auto lhs_lhs_i64 = obj::from(lhs_lhs->value()); + REQUIRE(lhs_lhs_i64); + REQUIRE(lhs_lhs_i64->value() == 7); + + auto lhs_rhs = obj::from(lhs->arg(1)); + REQUIRE(lhs_rhs); + auto lhs_rhs_i64 = obj::from(lhs_rhs->value()); + REQUIRE(lhs_rhs_i64); + REQUIRE(lhs_rhs_i64->value() == 2); + + auto rhs = obj::from(expr->arg(1)); + REQUIRE(rhs); + + auto rhs_i64 = obj::from(rhs->value()); + REQUIRE(rhs_i64); + REQUIRE(rhs_i64->value() == 3); + } + + log && fixture.log_memory_layout(&log); + } + TEST_CASE("SchematikaParser-interactive-cmp", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); From caa03566da2858b368de16dc1c0dd4d2eb5bca25 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 26 Feb 2026 12:20:34 +1100 Subject: [PATCH 246/342] xo-alloc: nix-build + compiler nits --- src/alloc/ArenaAlloc.cpp | 2 ++ src/alloc/GC.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index d7f794f3..dc80eb4e 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -390,8 +390,10 @@ namespace xo { /* word size for alignment */ constexpr uint32_t c_bpw = sizeof(std::uintptr_t); + (void)c_bpw; std::uintptr_t free_u64 = reinterpret_cast(free_ptr_); + (void)free_u64; assert(free_u64 % c_bpw == 0ul); diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index dd17fd3b..f1c52d1b 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -551,7 +551,7 @@ namespace xo { case generation_result::nursery: if (is_before_checkpoint(parent)) { log && log(xtag("act", "N1->N0 must mlog")); - + // N1->N0, so must log this->mutation_log_[role2int(role::to_space)]->push_back(MutationLogEntry(parent, lhs)); ++(this->gc_statistics_.n_logged_mutation_); @@ -974,12 +974,14 @@ namespace xo { from_entry.fixup_parent_child_moved(child_to); +#ifndef NDEBUG { // verify fixup was effective IObject * child_from2 = from_entry.child(); assert(child_from2 == child_to); } - +#endif + // P->C', loc(C') in {N1', T'} From a1e5449d5a0910ba71c43dc18bcc3efe451c81c9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 27 Feb 2026 11:33:40 +1100 Subject: [PATCH 247/342] xo-alloc: nix requires specific include path --- include/xo/alloc/Blob.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/alloc/Blob.hpp b/include/xo/alloc/Blob.hpp index 9e3ae44a..205e984b 100644 --- a/include/xo/alloc/Blob.hpp +++ b/include/xo/alloc/Blob.hpp @@ -6,7 +6,7 @@ #pragma once #include "Object.hpp" -#include "IAlloc.hpp" +#include namespace xo { /** Use to allocate opaque binary data, From fe9ae6389240138d57db72a1adc807f07f2d3715 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 27 Feb 2026 11:34:18 +1100 Subject: [PATCH 248/342] xo-alloc: fix broken cmake export deps --- cmake/xo_allocConfig.cmake.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmake/xo_allocConfig.cmake.in b/cmake/xo_allocConfig.cmake.in index f5afd837..97574de5 100644 --- a/cmake/xo_allocConfig.cmake.in +++ b/cmake/xo_allocConfig.cmake.in @@ -1,7 +1,10 @@ @PACKAGE_INIT@ include(CMakeFindDependencyMacro) +find_dependency(xo_allocutil) +find_dependency(xo_unit) find_dependency(indentlog) -#find_dependency(xo_flatstring) +find_dependency(reflect) +find_dependency(callback) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") check_required_components("@PROJECT_NAME@") From f83af2fd3e8636acb71321d9b4d9a51ce7742734 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 27 Feb 2026 19:38:53 +1100 Subject: [PATCH 249/342] xo-cmake: setup to make share target available via cmake install --- cmake/xo_reader2Config.cmake.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/xo_reader2Config.cmake.in b/cmake/xo_reader2Config.cmake.in index ed161c20..26ab1dae 100644 --- a/cmake/xo_reader2Config.cmake.in +++ b/cmake/xo_reader2Config.cmake.in @@ -13,4 +13,5 @@ find_dependency(xo_expression2) find_dependency(subsys) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Share.cmake") check_required_components("@PROJECT_NAME@") From 6d039c03e6420168003aa48b19f459ef78b9578a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 27 Feb 2026 19:38:53 +1100 Subject: [PATCH 250/342] xo-cmake: setup to make share target available via cmake install --- cmake/xo_tokenizer2Config.cmake.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/xo_tokenizer2Config.cmake.in b/cmake/xo_tokenizer2Config.cmake.in index 13f1dac1..eccd2745 100644 --- a/cmake/xo_tokenizer2Config.cmake.in +++ b/cmake/xo_tokenizer2Config.cmake.in @@ -10,4 +10,5 @@ find_dependency(xo_arena) find_dependency(indentlog) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Share.cmake") check_required_components("@PROJECT_NAME@") From dffaf7fa163d4781ffa116f42fa4bf9705fd049b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 27 Feb 2026 19:38:53 +1100 Subject: [PATCH 251/342] xo-cmake: setup to make share target available via cmake install --- cmake/xo_reflectutilConfig.cmake.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/xo_reflectutilConfig.cmake.in b/cmake/xo_reflectutilConfig.cmake.in index 26df0fc7..b57e2bb5 100644 --- a/cmake/xo_reflectutilConfig.cmake.in +++ b/cmake/xo_reflectutilConfig.cmake.in @@ -9,4 +9,5 @@ include(CMakeFindDependencyMacro) #find_dependency(xo_flatstring) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Share.cmake") check_required_components("@PROJECT_NAME@") From 1d6f1c22eaaee04a263117dd89be9d3ef5457d22 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 27 Feb 2026 19:38:53 +1100 Subject: [PATCH 252/342] xo-cmake: setup to make share target available via cmake install --- cmake/xo_allocConfig.cmake.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/xo_allocConfig.cmake.in b/cmake/xo_allocConfig.cmake.in index 97574de5..e627df64 100644 --- a/cmake/xo_allocConfig.cmake.in +++ b/cmake/xo_allocConfig.cmake.in @@ -7,4 +7,5 @@ find_dependency(indentlog) find_dependency(reflect) find_dependency(callback) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Share.cmake") check_required_components("@PROJECT_NAME@") From 04076ea9835b368d727b4446af824f21bebd6c32 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 27 Feb 2026 19:41:03 +1100 Subject: [PATCH 253/342] osx build: #include in _Any.cpp --- src/reader2/ISyntaxStateMachine_Any.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 393fea04..4fa59332 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -4,6 +4,7 @@ #include "ssm/ISyntaxStateMachine_Any.hpp" #include +#include namespace xo { namespace scm { From c221a31efe014aaeec9af7b584912354eb53395d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 27 Feb 2026 22:55:14 +1100 Subject: [PATCH 254/342] xo-numeric: + less than dispatch (also in schematika parser) --- src/reader2/DProgressSsm.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 371c7e88..4954dc49 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -121,9 +121,9 @@ namespace xo { switch (tktype) { case tokentype::tk_assign: return optype::op_assign; - case tokentype::tk_plus: // [+] + case tokentype::tk_plus: // [+] return optype::op_add; - case tokentype::tk_minus: // [-] + case tokentype::tk_minus: // [-] return optype::op_subtract; case tokentype::tk_star: // [*] return optype::op_multiply; @@ -133,7 +133,7 @@ namespace xo { return optype::op_equal; case tokentype::tk_cmpne: // [!=] return optype::op_not_equal; - case tokentype::tk_leftangle: + case tokentype::tk_leftangle: // [<] return optype::op_less; case tokentype::tk_lessequal: return optype::op_less_equal; @@ -288,7 +288,6 @@ namespace xo { case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: - case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_lessequal: case tokentype::tk_greatequal: @@ -304,6 +303,7 @@ namespace xo { case tokentype::tk_minus: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_leftangle: this->on_operator_token(tk, p_psm); return; @@ -1316,6 +1316,12 @@ namespace xo { lhs_, rhs_); case optype::op_less: + return assemble_numeric_expr_aux + (p_psm->expr_alloc(), + TypeRef::prefix_type::from_chars("_cmplt_gco"), + &NumericPrimitives::s_cmplt_gco_gco_pm, + lhs_, rhs_); + case optype::op_less_equal: case optype::op_great: case optype::op_great_equal: From 6795c1bc15285b5ceedba58fa764e68d0e4e9d59 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 28 Feb 2026 13:21:54 +1100 Subject: [PATCH 255/342] xo-reader2: support 0-argument apply-expressions --- include/xo/reader2/DApplySsm.hpp | 21 ++++++-- include/xo/reader2/DExpectExprSsm.hpp | 32 ++++++++--- src/reader2/DApplySsm.cpp | 78 ++++++++++++++++++--------- src/reader2/DExpectExprSsm.cpp | 73 +++++++++++++------------ src/reader2/DParenSsm.cpp | 5 +- src/reader2/DProgressSsm.cpp | 2 +- src/reader2/DSequenceSsm.cpp | 4 +- 7 files changed, 138 insertions(+), 77 deletions(-) diff --git a/include/xo/reader2/DApplySsm.hpp b/include/xo/reader2/DApplySsm.hpp index d53b3c5c..9357fc39 100644 --- a/include/xo/reader2/DApplySsm.hpp +++ b/include/xo/reader2/DApplySsm.hpp @@ -30,12 +30,13 @@ namespace xo { * apply_0 --on_expr()--> apply_1 * apply_1 --on_leftparen()--> apply_2 * apply_2 --on_expr()--> apply_3 + * --on_rightparen()--> (done) * apply_3 --on_comma()--> apply_2 - * --on_rightparen()-> (done) + * --on_rightparen()--> (done) * * apply_0: start * apply_1: leftparen following expr allows parser to recognize apply - * apply_2: expect next argument + * apply_2: expect next argument, or rightparent to continue * apply_3: got argument, expect comma or rightparen to continue * (done): apply complete, pop exprstate from stack * @@ -129,6 +130,15 @@ namespace xo { void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); + /** handle rightparen token @p tk for this ssm, + * with overall parser state in @p p_psm. + * + * Rightparen will complete apply-expression, + * terminating this syntax. + **/ + void on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup ssm-applyssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -177,9 +187,14 @@ namespace xo { ///@} private: - /** @defgroup ssm-applyssm-mpl-methods **/ + /** @defgroup ssm-applyssm-impl-methods **/ ///@{ + /** create final apply-expression for this syntax, + * using @p mm for memory + **/ + obj assemble_expr(obj mm); + ///@} private: diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 7600948c..16739006 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -22,21 +22,24 @@ namespace xo { using ppindentinfo = xo::print::ppindentinfo; public: - explicit DExpectExprSsm(bool allow_defs, - bool cxl_on_rightparen); + DExpectExprSsm(bool allow_defs, + bool cxl_on_rightbrace, + bool cxl_on_rightparen); static DExpectExprSsm * _make(DArena & parser_mm, bool allow_defs, - bool cxl_on_rightbrace); + bool cxl_on_rightbrace, + bool cxl_on_rightparen); /** create fop referring to new DExpectExprSsm **/ static obj make(DArena & parser_mm, bool allow_defs, - bool cxl_on_rightbrace); + bool cxl_on_rightbrace, + bool cxl_on_rightparen); - static void start(DArena & parser_mm, - bool allow_defs, + static void start(bool allow_defs, bool cxl_on_rightbrace, + bool cxl_on_rightparen, ParserStateMachine * p_psm); static void start(ParserStateMachine * p_psm); @@ -46,6 +49,7 @@ namespace xo { static const char * ssm_classname() { return "DExpectExprSsm"; } bool allow_defs() const noexcept { return allow_defs_; } bool cxl_on_rightbrace() const noexcept { return cxl_on_rightbrace_; } + bool cxl_on_rightparen() const noexcept { return cxl_on_rightparen_; } ///@} /** @defgroup scm-expectexpr-methods general methods **/ @@ -57,6 +61,15 @@ namespace xo { void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming rightparen token @p tk, + * with overall parser state in @p p_psm. + * + * Generally treats as illegal, but cancels gracefully when + * @ref cxl_on_rightparen_ set. + **/ + void on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming leftbrace token @p tk, * with overall parser state in @p p_psm **/ @@ -165,8 +178,11 @@ namespace xo { * 2a. expression **/ bool cxl_on_rightbrace_ = false; - - + /** if true: expecting either: + * 1a. expression + * 1b. right paren ')', in which case no expression + **/ + bool cxl_on_rightparen_ = false; }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index d6f5e151..867bf33b 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -116,7 +116,7 @@ namespace xo { case applyexprstatetype::invalid: return "invalid"; case applyexprstatetype::apply_0: return "expr"; case applyexprstatetype::apply_1: return "lparen"; - case applyexprstatetype::apply_2: return "expr"; + case applyexprstatetype::apply_2: return "expr|rparen"; case applyexprstatetype::apply_3: return "comma|rparen"; case applyexprstatetype::N: break; } @@ -134,6 +134,9 @@ namespace xo { case tokentype::tk_leftparen: this->on_leftparen_token(tk, p_psm); return; + case tokentype::tk_rightparen: + this->on_rightparen_token(tk, p_psm); + return; case tokentype::tk_symbol: case tokentype::tk_def: case tokentype::tk_if: @@ -147,7 +150,6 @@ namespace xo { case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_invalid: - case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: @@ -186,7 +188,25 @@ namespace xo { if (applystate_ == applyexprstatetype::apply_1) { this->applystate_ = applyexprstatetype::apply_2; - DExpectExprSsm::start(p_psm); + DExpectExprSsm::start(false /*!allow_defs*/, + false /*!cxl_on_rightbrace*/, + true /*cxl_on_rightparen*/, + p_psm); + return; + } + + Super::on_token(tk, p_psm); + } + + void + DApplySsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (applystate_ == applyexprstatetype::apply_2) { + obj apply = this->assemble_expr(p_psm->expr_alloc()); + + p_psm->pop_ssm(); + p_psm->on_parsed_expression(apply); return; } @@ -226,28 +246,7 @@ namespace xo { args_expr_v_->push_back(expr_gco); if (tk.tk_type() == tokentype::tk_rightparen) { - // begin assemble_expr().. - - std::uint32_t n_args = args_expr_v_->size(); - - DApplyExpr * apply - = (DApplyExpr::scaffold - (mm, - TypeRef::dwim(TypeRef::prefix_type::from_chars("apply"), - nullptr), - fn_expr_, - n_args)); - - for (std::uint32_t i_arg = 0; i_arg < n_args; ++i_arg) { - auto arg_expr - = args_expr_v_->at(i_arg).to_facet(); - - apply->assign_arg(i_arg, arg_expr); - } - - // ..end assemble_expr() - - obj apply_ex(apply); + obj apply_ex = this->assemble_expr(p_psm->expr_alloc()); p_psm->pop_ssm(); p_psm->on_parsed_expression(apply_ex); @@ -266,6 +265,35 @@ namespace xo { Super::on_parsed_expression_with_token(expr, tk, p_psm); } + obj + DApplySsm::assemble_expr(obj mm) + { + // begin assemble_expr().. + + std::uint32_t n_args = args_expr_v_->size(); + + DApplyExpr * apply + = (DApplyExpr::scaffold + (mm, + TypeRef::dwim(TypeRef::prefix_type::from_chars("apply"), + nullptr), + fn_expr_, + n_args)); + + for (std::uint32_t i_arg = 0; i_arg < n_args; ++i_arg) { + auto arg_expr + = args_expr_v_->at(i_arg).to_facet(); + + apply->assign_arg(i_arg, arg_expr); + } + + // ..end assemble_expr() + + obj apply_ex(apply); + + return apply_ex; + } + #ifdef NOT_YET void apply_xs::on_expr(bp expr, diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 459e3176..ba1fa33f 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -42,41 +42,48 @@ namespace xo { namespace scm { DExpectExprSsm::DExpectExprSsm(bool allow_defs, - bool cxl_on_rightbrace) + bool cxl_on_rightbrace, + bool cxl_on_rightparen) : allow_defs_{allow_defs}, - cxl_on_rightbrace_{cxl_on_rightbrace} + cxl_on_rightbrace_{cxl_on_rightbrace}, + cxl_on_rightparen_{cxl_on_rightparen} { } DExpectExprSsm * DExpectExprSsm::_make(DArena & mm, bool allow_defs, - bool cxl_on_rightbrace) + bool cxl_on_rightbrace, + bool cxl_on_rightparen) { void * mem = mm.alloc(typeseq::id(), sizeof(DExpectExprSsm)); return new (mem) DExpectExprSsm(allow_defs, - cxl_on_rightbrace); + cxl_on_rightbrace, + cxl_on_rightparen); } obj DExpectExprSsm::make(DArena & mm, bool allow_defs, - bool cxl_on_rightbrace) + bool cxl_on_rightbrace, + bool cxl_on_rightparen) { - return obj(_make(mm, allow_defs, cxl_on_rightbrace)); + return obj(_make(mm, allow_defs, cxl_on_rightbrace, cxl_on_rightparen)); } void - DExpectExprSsm::start(DArena & mm, - bool allow_defs, + DExpectExprSsm::start(bool allow_defs, bool cxl_on_rightbrace, + bool cxl_on_rightparen, ParserStateMachine * p_psm) { + auto & mm = p_psm->parser_alloc(); + DArena::Checkpoint ckp = mm.checkpoint(); - auto ssm = DExpectExprSsm::make(mm, allow_defs, cxl_on_rightbrace); + auto ssm = DExpectExprSsm::make(mm, allow_defs, cxl_on_rightbrace, cxl_on_rightparen); p_psm->push_ssm(ckp, ssm); } @@ -84,9 +91,9 @@ namespace xo { void DExpectExprSsm::start(ParserStateMachine * p_psm) { - start(p_psm->parser_alloc(), - false /*!allow_defs*/, + start(false /*!allow_defs*/, false /*!cxl_on_rightbrace*/, + false /*cxl_on_rightparen*/, p_psm); } @@ -117,6 +124,10 @@ namespace xo { this->on_leftparen_token(tk, p_psm); return; + case tokentype::tk_rightparen: + this->on_rightparen_token(tk, p_psm); + return; + case tokentype::tk_leftbrace: this->on_leftbrace_token(tk, p_psm); return; @@ -158,7 +169,6 @@ namespace xo { case tokentype::tk_singleassign: case tokentype::tk_colon: case tokentype::tk_semicolon: - case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_rightbrace: @@ -206,6 +216,21 @@ namespace xo { p_psm->on_token(tk); } + void + DExpectExprSsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (cxl_on_rightparen_) { + /* abandon expression, delegate rightparen to parent */ + + p_psm->pop_ssm(); + p_psm->on_token(tk); + return; + } + + Super::on_token(tk, p_psm); + } + void DExpectExprSsm::on_leftbrace_token(const Token & tk, ParserStateMachine * p_psm) @@ -482,8 +507,8 @@ namespace xo { "DExpectExprSsm", refrtag("allow_defs", allow_defs_), refrtag("cxl_on_rightbrace", cxl_on_rightbrace_), - refrtag("expect", this->get_expect_str()) - ); + refrtag("cxl_on_rightparen", cxl_on_rightparen_), + refrtag("expect", this->get_expect_str())); } #ifdef NOT_YET @@ -494,18 +519,6 @@ namespace xo { if_else_xs::start(p_psm); } - void - expect_expr_xs::on_leftparen_token(const token_type & /*tk*/, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - //constexpr const char * self_name = "exprstate::on_leftparen"; - - /* push lparen_0 to remember to look for subsequent rightparen. */ - paren_xs::start(p_psm); - } - void expect_expr_xs::on_rightbrace_token(const token_type & tk, parserstatemachine * p_psm) @@ -561,14 +574,6 @@ namespace xo { << xtag("cxl_on_rightbrace", cxl_on_rightbrace_) << ">"; } - - bool - expect_expr_xs::pretty_print(const xo::print::ppindentinfo & ppii) const - { - return ppii.pps()->pretty_struct(ppii, "expect_expr_xs", - refrtag("allow_defs", allow_defs_), - refrtag("cxl_on_rightbrace", cxl_on_rightbrace_)); - } #endif } /*namespace scm*/ diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index b89dec52..acfeb65c 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -159,10 +159,7 @@ namespace xo { * by rightparen. empty parentheses '()' * do not denote anything, in expression context **/ - DExpectExprSsm::start(p_psm->parser_alloc(), - false /*!allow_defs*/, - false /*cx_on_rightbrace*/, - p_psm); + DExpectExprSsm::start(p_psm); return; } diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 4954dc49..65c39d74 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -218,7 +218,7 @@ namespace xo { if (!lhs_) { return "expr1|leftparen"; } else if (op_type_ == optype::invalid) { - return "oper|semicolon|rightparen|rightbrace"; + return "oper|semicolon|leftparen|rightparen|rightbrace"; } else { return "expr2|leftparen"; } diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index 87460804..f9884b78 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -29,9 +29,9 @@ namespace xo { /* want to accept anything that starts an expression, * except that rightbrace '}' ends it */ - DExpectExprSsm::start(p_psm->parser_alloc(), - true /*allow_defs*/, + DExpectExprSsm::start(true /*allow_defs*/, true /*cxl_on_rightbrace*/, + false /*!cxl_on_rightparen*/, p_psm); } From df2c13f395a4dc5b18750663af118db46149efec Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 28 Feb 2026 13:24:06 +1100 Subject: [PATCH 256/342] xo-reader2: + intern_string() forwarding methods in parser/reader --- include/xo/reader2/SchematikaParser.hpp | 4 ++++ include/xo/reader2/SchematikaReader.hpp | 4 ++++ src/reader2/SchematikaParser.cpp | 6 ++++++ src/reader2/SchematikaReader.cpp | 6 ++++++ 4 files changed, 20 insertions(+) diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index 96de8628..ce7b3335 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -220,6 +220,10 @@ namespace xo { **/ void begin_batch_session(); + /** intern string @p str in global string table + **/ + const DUniqueString * intern_string(std::string_view str); + /** include next token @p tk and increment parser state. * * @param tk next input token diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index efd031ca..5d20226e 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -78,6 +78,10 @@ namespace xo { **/ void begin_batch_session(); + /** intern string @p str in global string table + **/ + const DUniqueString * intern_string(std::string_view str); + /** consume input @p input_cstr **/ const ReaderResult & read_expr(span_type input_span, bool eof); diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 25b3bc7f..12f15bd6 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -81,6 +81,12 @@ namespace xo { DToplevelSeqSsm::establish_batch(psm_.parser_alloc(), &psm_); } + const DUniqueString * + SchematikaParser::intern_string(std::string_view str) + { + return psm_.intern_string(str); + } + const ParserResult & SchematikaParser::on_token(const token_type & tk) { diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index c3e13254..f9cad55a 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -58,6 +58,12 @@ namespace xo { // TODO: // Schematika::end_interactive_session() + const DUniqueString * + SchematikaReader::intern_string(std::string_view str) + { + return parser_.intern_string(str); + } + const ReaderResult & SchematikaReader::read_expr(span_type input_ext, bool eof) { From 34e863d4eae19bc1c26e358d048aa3caa4ece6e0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 28 Feb 2026 13:36:27 +1100 Subject: [PATCH 257/342] xo-interpreter2: report_memory_use() unit test --- src/reader2/SchematikaParser.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 12f15bd6..74e17576 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -103,6 +103,9 @@ namespace xo { psm_.on_token(tk); + log && log(xtag("parser", this)); + log && log(xtag("result", psm_.result())); + return psm_.result(); } /*include_token*/ From 7b70296eb114ba729ea2bf34c5b518ebeb36c2ba Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 1 Mar 2026 13:06:57 +1100 Subject: [PATCH 258/342] xo-reader2 stack: + #q token + QuoteSsm [WIP - not functional] --- CMakeLists.txt | 20 ++ idl/IPrintable_DQuoteSsm.json5 | 16 ++ idl/ISyntaxStateMachine_DQuoteSsm.json5 | 16 ++ include/xo/reader2/DQuoteSsm.hpp | 166 +++++++++++++ include/xo/reader2/QuoteSsm.hpp | 12 + .../xo/reader2/ssm/IPrintable_DQuoteSsm.hpp | 62 +++++ .../ssm/ISyntaxStateMachine_DQuoteSsm.hpp | 79 +++++++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 3 + src/reader2/DApplySsm.cpp | 1 + src/reader2/DDefineSsm.cpp | 1 + src/reader2/DExpectExprSsm.cpp | 1 + src/reader2/DExpectFormalArgSsm.cpp | 1 + src/reader2/DExpectFormalArglistSsm.cpp | 1 + src/reader2/DExpectSymbolSsm.cpp | 1 + src/reader2/DExpectTypeSsm.cpp | 1 + src/reader2/DIfElseSsm.cpp | 1 + src/reader2/DLambdaSsm.cpp | 1 + src/reader2/DParenSsm.cpp | 1 + src/reader2/DProgressSsm.cpp | 1 + src/reader2/DQuoteSsm.cpp | 218 ++++++++++++++++++ src/reader2/DSequenceSsm.cpp | 1 + src/reader2/DToplevelSeqSsm.cpp | 1 + src/reader2/IPrintable_DQuoteSsm.cpp | 28 +++ src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp | 74 ++++++ src/reader2/syntaxstatetype.cpp | 2 + 26 files changed, 712 insertions(+) create mode 100644 idl/IPrintable_DQuoteSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DQuoteSsm.json5 create mode 100644 include/xo/reader2/DQuoteSsm.hpp create mode 100644 include/xo/reader2/QuoteSsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DQuoteSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp create mode 100644 src/reader2/DQuoteSsm.cpp create mode 100644 src/reader2/IPrintable_DQuoteSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f05802f..c70ad114 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -293,6 +293,26 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-quotessm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR QuoteSsm + INPUT idl/ISyntaxStateMachine_DQuoteSsm.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-quotessm + FACET_PKG xo_printable2 + FACET Printable + REPR QuoteSsm + INPUT idl/IPrintable_DQuoteSsm.json5 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-reader2-genfacet-all) # ---------------------------------------------------------------- diff --git a/idl/IPrintable_DQuoteSsm.json5 b/idl/IPrintable_DQuoteSsm.json5 new file mode 100644 index 00000000..d1c28a15 --- /dev/null +++ b/idl/IPrintable_DQuoteSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DQuoteSsm", + using_doxygen: true, + repr: "DQuoteSsm", + doc: [ "implement APrintable for DQuoteSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DQuoteSsm.json5 b/idl/ISyntaxStateMachine_DQuoteSsm.json5 new file mode 100644 index 00000000..a70a4aa4 --- /dev/null +++ b/idl/ISyntaxStateMachine_DQuoteSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DQuoteSsm", + using_doxygen: true, + repr: "DQuoteSsm", + doc: [ "implement ASyntaxStateMachine for DQuoteSsm" ], +} diff --git a/include/xo/reader2/DQuoteSsm.hpp b/include/xo/reader2/DQuoteSsm.hpp new file mode 100644 index 00000000..5252e941 --- /dev/null +++ b/include/xo/reader2/DQuoteSsm.hpp @@ -0,0 +1,166 @@ +/** @file DQuoteSsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include +#include + +namespace xo { + namespace scm { + + /** + * @pre + * + * #q{ quote-expr } + * ^ ^ ^ ^ ^ + * | | | | (done) + * | | | | + * | | | quote_3:expect_rightbrace + * | | quote_2:expect_parsed_expression + * | quote_1:expect_leftbrace + * quote_0 + * + * quote_0 --on_quote_token()--> quote_1 + * quote_1 --on_leftbrace_token()--> quote_2 + * quote_2 --on_parsed_expression()--> quote_3 [will be constant expression] + * quote_3 --on_rightparen_token()--> (done) + * + * @endpre + **/ + + class QuoteXst { + public: + enum class code { + invalid = -1, + + quote_0, + quote_1, + quote_2, + quote_3, + + N, + }; + + explicit QuoteXst(code x) : code_{x} {} + + /** @return string representation for enum @p x **/ + static const char * _descr(code x); + + code code() const noexcept { return code_; } + + enum code code_; + }; + + inline std::ostream & + operator<<(std::ostream & os, QuoteXst x) { + os << QuoteXst::_descr(x.code_); + return os; + } + + class DQuoteSsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using TypeDescr = xo::reflect::TypeDescr; + using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; + + public: + /** @defgroup scm-parenssm-ctors **/ + ///@{ + + DQuoteSsm(); + + /** create instance using memory from @p parser_mm + **/ + static DQuoteSsm * _make(DArena & parser_mm); + + /** create fop pointing with new DQuoteSsm using memory from @p parser_mm **/ + static obj make(DArena & parser_mm); + + /** push DQuoteSsm instance onto @p p_psm stack **/ + static void start(ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-parenssm-access-methods **/ + ///@{ + + /** identify this nested state machine **/ + static const char * ssm_classname() { return "DQuoteSsm"; } + + /** internal state **/ + QuoteXst quotestate() const noexcept { return quote_xst_; } + + ///@} + /** @defgroup scm-parenssm-admin-methods admin methods **/ + ///@{ + + /** update ssm state for incoming leftparen token @p tk, + * with overall parser state in @p p_psm + **/ + void on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update ssm state for incoming rightparen token @p tk + * with overall parser state in @p p_psm + **/ + void on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-parenssm-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies this ssm **/ + syntaxstatetype ssm_type() const noexcept; + + /** text describing expected/allowed input to this ssm in current state. **/ + std::string_view get_expect_str() const noexcept; + + /** update ssm for token @p tk, with overall state in @p p_psm **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update ssm for expression @p expr (emitted by nested ssm), + * with overall parser state in @p p_psm + **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + + /** update ssm for expression @p expr (emitted by nested ssm) + * that's immediately followed by token @p tk + * with overall parser state in @p p_psm + **/ + void on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psmn); + + ///@} + /** @defgroup scm-parenssm-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + /** @defgroup scm-parenssm-member-vars **/ + ///@{ + + /** identify quote-expression state **/ + QuoteXst quote_xst_; + /** scaffold expression (representing parenthesized value) here **/ + obj expr_; + + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DQuoteSsm.hpp */ diff --git a/include/xo/reader2/QuoteSsm.hpp b/include/xo/reader2/QuoteSsm.hpp new file mode 100644 index 00000000..c0fb5429 --- /dev/null +++ b/include/xo/reader2/QuoteSsm.hpp @@ -0,0 +1,12 @@ +/** @file QuoteSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DQuoteSsm.hpp" +#include "ssm/ISyntaxStateMachine_DQuoteSsm.hpp" +#include "ssm/IPrintable_DQuoteSsm.hpp" + +/* end QuoteSsm.hpp */ diff --git a/include/xo/reader2/ssm/IPrintable_DQuoteSsm.hpp b/include/xo/reader2/ssm/IPrintable_DQuoteSsm.hpp new file mode 100644 index 00000000..2b969c50 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DQuoteSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DQuoteSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DQuoteSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DQuoteSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DQuoteSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DQuoteSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DQuoteSsm + **/ + class IPrintable_DQuoteSsm { + public: + /** @defgroup scm-printable-dquotessm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dquotessm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DQuoteSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp new file mode 100644 index 00000000..a692f79f --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp @@ -0,0 +1,79 @@ +/** @file ISyntaxStateMachine_DQuoteSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DQuoteSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DQuoteSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DQuoteSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DQuoteSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DQuoteSsm + **/ + class ISyntaxStateMachine_DQuoteSsm { + public: + /** @defgroup scm-syntaxstatemachine-dquotessm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dquotessm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DQuoteSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DQuoteSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DQuoteSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DQuoteSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DQuoteSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DQuoteSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DQuoteSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DQuoteSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for incoming parsed expression @p expr **/ + static void on_parsed_expression(DQuoteSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DQuoteSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 957272e8..6c6849dc 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -39,6 +39,9 @@ namespace xo { /** expression enclosed in parentheses. See @ref DParenSsm **/ paren, + /** quoted literal using #q{..} syntax. See @ref DQuoteSsm **/ + quote, + /** toplevel of some translation unit. See @ref DToplevelSeqSsm **/ expect_toplevel_expression_sequence, diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index f9c6511c..862ca0e6 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -69,6 +69,9 @@ set(SELF_SRCS ISyntaxStateMachine_DProgressSsm.cpp IPrintable_DProgressSsm.cpp + DQuoteSsm.cpp + ISyntaxStateMachine_DQuoteSsm.cpp + IPrintable_DQuoteSsm.cpp ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index 867bf33b..b0653a52 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -150,6 +150,7 @@ namespace xo { case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_invalid: + case tokentype::tk_quote: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index aae07b90..8266046f 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -531,6 +531,7 @@ namespace xo { case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_if: + case tokentype::tk_quote: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index ba1fa33f..1248947c 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -169,6 +169,7 @@ namespace xo { case tokentype::tk_singleassign: case tokentype::tk_colon: case tokentype::tk_semicolon: + case tokentype::tk_quote: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_rightbrace: diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index bbb9048e..7986a6de 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -114,6 +114,7 @@ namespace xo { case tokentype::tk_bool: case tokentype::tk_semicolon: case tokentype::tk_invalid: + case tokentype::tk_quote: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 53dcf30c..1de4533b 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -145,6 +145,7 @@ namespace xo { case tokentype::tk_bool: case tokentype::tk_semicolon: case tokentype::tk_invalid: + case tokentype::tk_quote: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 8a750751..0a5d7abb 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -78,6 +78,7 @@ namespace xo { case tokentype::tk_singleassign: case tokentype::tk_colon: case tokentype::tk_semicolon: + case tokentype::tk_quote: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index b4fa8819..e4078936 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -78,6 +78,7 @@ namespace xo { case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_string: + case tokentype::tk_quote: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index b7d150af..5a17054d 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -167,6 +167,7 @@ namespace xo { case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_invalid: + case tokentype::tk_quote: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 6308ae08..c0eb92cf 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -154,6 +154,7 @@ namespace xo { case tokentype::tk_bool: case tokentype::tk_semicolon: case tokentype::tk_invalid: + case tokentype::tk_quote: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index acfeb65c..53dc3063 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -111,6 +111,7 @@ namespace xo { case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_if: + case tokentype::tk_quote: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 65c39d74..d2032f39 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -285,6 +285,7 @@ namespace xo { case tokentype::tk_invalid: case tokentype::tk_def: case tokentype::tk_if: + case tokentype::tk_quote: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: diff --git a/src/reader2/DQuoteSsm.cpp b/src/reader2/DQuoteSsm.cpp new file mode 100644 index 00000000..b7f33456 --- /dev/null +++ b/src/reader2/DQuoteSsm.cpp @@ -0,0 +1,218 @@ +/** @file DQuoterSsm.cpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#include "QuoteSsm.hpp" +#include "ExpectExprSsm.hpp" +#include "syntaxstatetype.hpp" +//#include + +namespace xo { + using xo::facet::with_facet; + using xo::facet::typeseq; + + namespace scm { + + extern const char * + QuoteXst::_descr(enum QuoteXst::code x) + { + switch(x) { + case code::invalid: return "invalid"; + case code::quote_0: return "quote_0"; + case code::quote_1: return "quote_1"; + case code::quote_2: return "quote_2"; + case code::quote_3: return "quote_3"; + case code::N: break; + } + + return "?QuoteXst"; + } + + DQuoteSsm::DQuoteSsm() + : quote_xst_(QuoteXst::code::quote_0), + expr_{} + {} + + DQuoteSsm * + DQuoteSsm::_make(DArena & mm) + { + void * mem = mm.alloc_for(); + + return new (mem) DQuoteSsm(); + } + + obj + DQuoteSsm::make(DArena & mm) + { + return obj(_make(mm)); + } + + void + DQuoteSsm::start(ParserStateMachine * p_psm) + { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + auto paren_ssm = DQuoteSsm::make(p_psm->parser_alloc()); + + p_psm->push_ssm(ckp, paren_ssm); + } + + syntaxstatetype + DQuoteSsm::ssm_type() const noexcept + { + return syntaxstatetype::paren; + } + + std::string_view + DQuoteSsm::get_expect_str() const noexcept + { + switch (this->quote_xst_.code()) { + case QuoteXst::code::invalid: + case QuoteXst::code::N: + break; + case QuoteXst::code::quote_0: return "#q"; + case QuoteXst::code::quote_1: return "leftbrace"; + case QuoteXst::code::quote_2: return "qliteral"; + case QuoteXst::code::quote_3: return "rightbrace"; + } + + assert(false); + + return "?quotexst"; + } + + void + DQuoteSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (tk.tk_type()) { + + case tokentype::tk_leftbrace: + this->on_leftbrace_token(tk, p_psm); + return; + + case tokentype::tk_rightbrace: + this->on_rightbrace_token(tk, p_psm); + return; + + // all the not-yet handled cases + case tokentype::tk_symbol: + case tokentype::tk_def: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_if: + case tokentype::tk_quote: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + Super::on_token(tk, p_psm); + } + + void + DQuoteSsm::on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (quote_xst_.code() == QuoteXst::code::quote_0) { + this->quote_xst_ = QuoteXst(QuoteXst::code::quote_1); + + assert(false); + //DExpectQLiteralSsm::start(p_psm); + //return; + } + + Super::on_token(tk, p_psm); + } + + void + DQuoteSsm::on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (quote_xst_.code() == QuoteXst::code::quote_3) { + // quoted literal (reported as constant expr) successfully parsed + + p_psm->pop_ssm(); + p_psm->on_parsed_expression(this->expr_); + return; + } + + Super::on_token(tk, p_psm); + } + + void + DQuoteSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) + { + if (quote_xst_.code() == QuoteXst::code::quote_2) { + this->quote_xst_ = QuoteXst(QuoteXst::code::quote_3); + this->expr_ = expr; + + return; + } + + Super::on_parsed_expression(expr, p_psm); + } + + void + DQuoteSsm::on_parsed_expression_with_token(obj expr, + const Token & tk, + ParserStateMachine * p_psm) + { + if (quote_xst_.code() == QuoteXst::code::quote_2) { + this->quote_xst_ = QuoteXst(QuoteXst::code::quote_3); + this->expr_ = expr; + + this->on_token(tk, p_psm); + + return; + } + + Super::on_parsed_expression(expr, p_psm); + } + + bool + DQuoteSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, + "DParenSsm", + refrtag("quote_xst", quote_xst_), + refrtag("expect", this->get_expect_str())); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DQuoteSsm.cpp */ diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index f9884b78..12d47a9d 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -92,6 +92,7 @@ namespace xo { case tokentype::tk_bool: case tokentype::tk_semicolon: case tokentype::tk_invalid: + case tokentype::tk_quote: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index 42c870b6..d7520e87 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -162,6 +162,7 @@ namespace xo { // all the not-yet handled cases case tokentype::tk_invalid: + case tokentype::tk_quote: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: diff --git a/src/reader2/IPrintable_DQuoteSsm.cpp b/src/reader2/IPrintable_DQuoteSsm.cpp new file mode 100644 index 00000000..303acefb --- /dev/null +++ b/src/reader2/IPrintable_DQuoteSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DQuoteSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DQuoteSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DQuoteSsm.json5] +**/ + +#include "ssm/IPrintable_DQuoteSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DQuoteSsm::pretty(const DQuoteSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DQuoteSsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp b/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp new file mode 100644 index 00000000..c3264db0 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp @@ -0,0 +1,74 @@ +/** @file ISyntaxStateMachine_DQuoteSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DQuoteSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DQuoteSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DQuoteSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DQuoteSsm::ssm_type(const DQuoteSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DQuoteSsm::get_expect_str(const DQuoteSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DQuoteSsm::on_token(DQuoteSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DQuoteSsm::on_parsed_symbol(DQuoteSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DQuoteSsm::on_parsed_typedescr(DQuoteSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DQuoteSsm::on_parsed_formal(DQuoteSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DQuoteSsm::on_parsed_formal_with_token(DQuoteSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto + ISyntaxStateMachine_DQuoteSsm::on_parsed_formal_arglist(DQuoteSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DQuoteSsm::on_parsed_expression(DQuoteSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DQuoteSsm::on_parsed_expression_with_token(DQuoteSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DQuoteSsm.cpp */ diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index 01ab1005..0d7dd7e2 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -27,6 +27,8 @@ namespace xo { return "progress"; case syntaxstatetype::paren: return "paren"; + case syntaxstatetype::quote: + return "quote"; case syntaxstatetype::expect_toplevel_expression_sequence: return "expect-toplevel-expression-sequence"; case syntaxstatetype::expect_formal_arglist: From 9920812d4297b0f63abe160264ad1a5c707ca4d8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 1 Mar 2026 13:06:57 +1100 Subject: [PATCH 259/342] xo-reader2 stack: + #q token + QuoteSsm [WIP - not functional] --- include/xo/tokenizer2/Token.hpp | 2 ++ include/xo/tokenizer2/tokentype.hpp | 3 +++ src/tokenizer2/Tokenizer.cpp | 13 +++++++++++++ src/tokenizer2/tokentype.cpp | 5 +++-- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index b211f967..9ddd0181 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -87,6 +87,8 @@ namespace xo { static Token symbol_token(const std::string & txt) { return Token(tokentype::tk_symbol, txt); } + /** token representing quote @c "'" **/ + static Token quote() { return Token(tokentype::tk_quote); } /** token representing left angle bracket @c "<" **/ static Token leftangle() { return Token(tokentype::tk_leftangle); } /** token representing right angle bracket @c ">" **/ diff --git a/include/xo/tokenizer2/tokentype.hpp b/include/xo/tokenizer2/tokentype.hpp index 91cb3622..3f259f8d 100644 --- a/include/xo/tokenizer2/tokentype.hpp +++ b/include/xo/tokenizer2/tokentype.hpp @@ -64,6 +64,9 @@ namespace xo { /** a symbol **/ tk_symbol, + /** quote @c ' **/ + tk_quote, + /** left-hand parenthesis @c '(' **/ tk_leftparen, diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index f176a88f..8821cd65 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -32,6 +32,8 @@ namespace xo { Tokenizer::is_1char_punctuation(CharT ch) { switch(ch) { + case '\'': + return true; case '(': return true; case ')': @@ -418,6 +420,15 @@ namespace xo { break; } + case '\'': + { + log && log("quote token"); + + tk_type = tokentype::tk_quote; + ++ix; + + break; + } case 'a': case 'A': case 'b': case 'B': case 'c': case 'C': @@ -593,6 +604,8 @@ namespace xo { tk_type = tokentype::tk_in; } else if (tk_text == "end") { tk_type = tokentype::tk_end; + } else if (tk_text == "#q") { + tk_type = tokentype::tk_quote; } else { /* keep as symbol */ keep_text = true; diff --git a/src/tokenizer2/tokentype.cpp b/src/tokenizer2/tokentype.cpp index 40c2dbfb..0831940f 100644 --- a/src/tokenizer2/tokentype.cpp +++ b/src/tokenizer2/tokentype.cpp @@ -18,16 +18,17 @@ namespace xo { CASE(tk_f64); CASE(tk_string); CASE(tk_symbol); - CASE(tk_leftparen); + CASE(tk_quote); + CASE(tk_leftparen); CASE(tk_rightparen); CASE(tk_leftbracket); CASE(tk_rightbracket); CASE(tk_leftbrace); CASE(tk_rightbrace); - CASE(tk_leftangle); CASE(tk_rightangle); + CASE(tk_lessequal); CASE(tk_greatequal); CASE(tk_dot); From 3f8be97290d02b5ef1a6bdd11a59900f8d2bf3ce Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 1 Mar 2026 13:35:52 +1100 Subject: [PATCH 260/342] xo-reader2: scasffold for on_quoted_literal() --- idl/SyntaxStateMachine.json5 | 12 ++++++++- include/xo/reader2/DSyntaxStateMachine.hpp | 20 ++++++++++++++ include/xo/reader2/ParserStateMachine.hpp | 8 ++++++ .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 6 ++++- .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DApplySsm.hpp | 5 +++- .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 5 +++- .../ISyntaxStateMachine_DExpectExprSsm.hpp | 5 +++- ...SyntaxStateMachine_DExpectFormalArgSsm.hpp | 5 +++- ...axStateMachine_DExpectFormalArglistSsm.hpp | 5 +++- .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 5 +++- .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 5 +++- .../ssm/ISyntaxStateMachine_DIfElseSsm.hpp | 5 +++- .../ssm/ISyntaxStateMachine_DLambdaSsm.hpp | 5 +++- .../ssm/ISyntaxStateMachine_DParenSsm.hpp | 5 +++- .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 5 +++- .../ssm/ISyntaxStateMachine_DQuoteSsm.hpp | 5 +++- .../ssm/ISyntaxStateMachine_DSequenceSsm.hpp | 5 +++- .../ISyntaxStateMachine_DToplevelSeqSsm.hpp | 5 +++- .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 4 +++ .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 4 +++ src/reader2/ISyntaxStateMachine_Any.cpp | 6 +++++ src/reader2/ISyntaxStateMachine_DApplySsm.cpp | 5 ++++ .../ISyntaxStateMachine_DDefineSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectExprSsm.cpp | 5 ++++ ...SyntaxStateMachine_DExpectFormalArgSsm.cpp | 5 ++++ ...axStateMachine_DExpectFormalArglistSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DIfElseSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DLambdaSsm.cpp | 5 ++++ src/reader2/ISyntaxStateMachine_DParenSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DProgressSsm.cpp | 5 ++++ src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DSequenceSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DToplevelSeqSsm.cpp | 5 ++++ src/reader2/ParserStateMachine.cpp | 26 +++++++++++++++++++ 37 files changed, 212 insertions(+), 16 deletions(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 4cafd9c3..815fd18e 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -25,6 +25,7 @@ ], types: [ { name: "TypeDescr", doc: [ "reflected c++ type" ], definition: "xo::reflect::TypeDescr" }, + { name: "AGCObject", doc: [ "gc-aware object" ], definition: "xo::mm::AGCObject" }, // { name: string, doc: [ string ], definition: string }, ], const_methods: [ @@ -107,7 +108,7 @@ }, { name: "on_parsed_expression", - doc: ["update state machine for incoming parsed expression @p expr"], + doc: ["update state machine for nested parsed expression @p expr"], return_type: "void", args: [ {type: "obj", name: "expr"}, @@ -124,6 +125,15 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_quoted_literal", + doc: ["update state machine for nested quoted literal @p lit"], + return_type: "void", + args: [ + {type: "obj", name: "lit"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + } ], router_facet_explicit_content: [ ], } diff --git a/include/xo/reader2/DSyntaxStateMachine.hpp b/include/xo/reader2/DSyntaxStateMachine.hpp index 5851390b..b72a3e92 100644 --- a/include/xo/reader2/DSyntaxStateMachine.hpp +++ b/include/xo/reader2/DSyntaxStateMachine.hpp @@ -30,6 +30,19 @@ namespace xo { class DSyntaxStateMachine { public: using TypeDescr = xo::reflect::TypeDescr; + using AGCObject = xo::mm::AGCObject; + + /** Explicit error path **/ + void illegal_quoted_literal(obj lit, + ParserStateMachine * p_psm) + { + // starting with c++23 can use "this auto&& self" instead + Derived & self = static_cast(*this); + + p_psm->illegal_quoted_literal(Derived::ssm_classname(), + lit, + self.get_expect_str()); + } /** Default implementation for required SyntaxStateMachine facet method **/ @@ -148,6 +161,13 @@ namespace xo { self.get_expect_str()); } + + /** Default impplementation for required SyntaxStateMachine facet method **/ + void on_quoted_literal(obj lit, + ParserStateMachine * p_psm) + { + this->illegal_quoted_literal(lit, p_psm); + } }; } /*namespace scm*/ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index bec90ae8..f8214a39 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -37,6 +37,7 @@ namespace xo { using TypeDescr = xo::reflect::TypeDescr; using AAllocator = xo::mm::AAllocator; using ArenaConfig = xo::mm::ArenaConfig; + using AGCObject = xo::mm::AGCObject; using DArena = xo::mm::DArena; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using ArenaHashMapConfig = xo::map::ArenaHashMapConfig; @@ -272,6 +273,13 @@ namespace xo { const Token & tk, std::string_view expect_str); + /** report illegal quoted literal @p lit from nested ssm @p ssm_name. + * Possibly unreachable. + **/ + void illegal_quoted_literal(std::string_view ssm_name, + obj lit, + std::string_view expect_str); + /** report error - no binding for variable @p sym **/ void error_unbound_variable(std::string_view ssm_name, diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index 6b2976e1..b7fa0a92 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -44,6 +44,8 @@ public: using Opaque = void *; /** reflected c++ type **/ using TypeDescr = xo::reflect::TypeDescr; + /** gc-aware object **/ + using AGCObject = xo::mm::AGCObject; ///@} /** @defgroup scm-syntaxstatemachine-methods **/ @@ -71,10 +73,12 @@ public: virtual void on_parsed_formal_with_token(Opaque data, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) = 0; /** consume formal arglist emitted by nested ssm **/ virtual void on_parsed_formal_arglist(Opaque data, DArray * arglist, ParserStateMachine * p_psm) = 0; - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ virtual void on_parsed_expression(Opaque data, obj expr, ParserStateMachine * p_psm) = 0; /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ virtual void on_parsed_expression_with_token(Opaque data, obj expr, const Token & tk, ParserStateMachine * p_psm) = 0; + /** update state machine for nested quoted literal @p lit **/ + virtual void on_quoted_literal(Opaque data, obj lit, ParserStateMachine * p_psm) = 0; ///@} }; /*ASyntaxStateMachine*/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 8eb513c9..81d00656 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -45,6 +45,7 @@ namespace scm { /** integer identifying a type **/ using typeseq = xo::facet::typeseq; using TypeDescr = ASyntaxStateMachine::TypeDescr; + using AGCObject = ASyntaxStateMachine::AGCObject; ///@} /** @defgroup scm-syntaxstatemachine-any-methods **/ @@ -71,6 +72,7 @@ namespace scm { [[noreturn]] void on_parsed_formal_arglist(Opaque, DArray *, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression(Opaque, obj, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression_with_token(Opaque, obj, const Token &, ParserStateMachine *) override; + [[noreturn]] void on_quoted_literal(Opaque, obj, ParserStateMachine *) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp index eb9b10fa..75863bfc 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dapplyssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DApplySsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DApplySsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DApplySsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DApplySsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DApplySsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index 8fee27fd..0191de54 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-ddefinessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DDefineSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DDefineSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DDefineSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index b452860f..a84ed1b1 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectexprssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DExpectExprSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DExpectExprSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DExpectExprSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DExpectExprSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectExprSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp index 466dce8b..4e924170 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectformalargssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DExpectFormalArgSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DExpectFormalArgSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DExpectFormalArgSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DExpectFormalArgSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectFormalArgSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp index 571255f9..d1e388b2 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectformalarglistssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DExpectFormalArglistSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DExpectFormalArglistSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DExpectFormalArglistSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DExpectFormalArglistSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectFormalArglistSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index d8367631..f39e2af3 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectsymbolssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DExpectSymbolSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DExpectSymbolSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DExpectSymbolSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DExpectSymbolSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectSymbolSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index 87b5db71..ba997e28 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpecttypessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DExpectTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DExpectTypeSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DExpectTypeSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DExpectTypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectTypeSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp index d1373a1a..b189bf87 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-difelsessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DIfElseSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DIfElseSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DIfElseSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DIfElseSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DIfElseSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp index 3c945b94..9c97287f 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dlambdassm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DLambdaSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DLambdaSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DLambdaSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DLambdaSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DLambdaSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp index 19e4a89b..65cd1727 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dparenssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DParenSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DParenSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DParenSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DParenSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DParenSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 13a2d461..431892b9 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dprogressssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DProgressSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DProgressSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DProgressSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DProgressSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DProgressSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp index a692f79f..e5548af5 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dquotessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DQuoteSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DQuoteSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DQuoteSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DQuoteSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DQuoteSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp index 7e0cfb42..448b296b 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dsequencessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DSequenceSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DSequenceSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DSequenceSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DSequenceSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DSequenceSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp index 69a3c71f..9aa70c43 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dtoplevelseqssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -66,10 +67,12 @@ namespace xo { static void on_parsed_formal_with_token(DToplevelSeqSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); /** consume formal arglist emitted by nested ssm **/ static void on_parsed_formal_arglist(DToplevelSeqSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for incoming parsed expression @p expr **/ + /** update state machine for nested parsed expression @p expr **/ static void on_parsed_expression(DToplevelSeqSsm & self, obj expr, ParserStateMachine * p_psm); /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ static void on_parsed_expression_with_token(DToplevelSeqSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DToplevelSeqSsm & self, obj lit, ParserStateMachine * p_psm); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 30c87269..4a77f0c4 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -32,6 +32,7 @@ namespace scm { /** integer identifying a type **/ using typeseq = ASyntaxStateMachine::typeseq; using TypeDescr = ASyntaxStateMachine::TypeDescr; + using AGCObject = ASyntaxStateMachine::AGCObject; ///@} /** @defgroup scm-syntaxstatemachine-xfer-methods **/ @@ -79,6 +80,9 @@ namespace scm { void on_parsed_expression_with_token(Opaque data, obj expr, const Token & tk, ParserStateMachine * p_psm) override { return I::on_parsed_expression_with_token(_dcast(data), expr, tk, p_psm); } + void on_quoted_literal(Opaque data, obj lit, ParserStateMachine * p_psm) override { + return I::on_quoted_literal(_dcast(data), lit, p_psm); + } ///@} diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 8012b657..33321d14 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -32,6 +32,7 @@ public: using DataPtr = Object::DataPtr; using typeseq = xo::reflect::typeseq; using TypeDescr = ASyntaxStateMachine::TypeDescr; + using AGCObject = ASyntaxStateMachine::AGCObject; ///@} /** @defgroup scm-syntaxstatemachine-router-ctors **/ @@ -85,6 +86,9 @@ public: void on_parsed_expression_with_token(obj expr, const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_parsed_expression_with_token(O::data(), expr, tk, p_psm); } + void on_quoted_literal(obj lit, ParserStateMachine * p_psm) { + return O::iface()->on_quoted_literal(O::data(), lit, p_psm); + } ///@} /** @defgroup scm-syntaxstatemachine-member-vars **/ diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 4fa59332..ccf69ca8 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -83,6 +83,12 @@ ISyntaxStateMachine_Any::on_parsed_expression_with_token(Opaque, obj, ParserStateMachine *) -> void +{ + _fatal(); +} + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DApplySsm.cpp b/src/reader2/ISyntaxStateMachine_DApplySsm.cpp index bcc672a4..f5cbb4e2 100644 --- a/src/reader2/ISyntaxStateMachine_DApplySsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DApplySsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DApplySsm::on_quoted_literal(DApplySsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index dad9d0e8..be766921 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DDefineSsm::on_quoted_literal(DDefineSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index 855135e6..d505b427 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DExpectExprSsm::on_quoted_literal(DExpectExprSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp index 948a4fe2..50131470 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DExpectFormalArgSsm::on_quoted_literal(DExpectFormalArgSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp index f56a90d2..982ce47a 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DExpectFormalArglistSsm::on_quoted_literal(DExpectFormalArglistSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 77f0fd10..3701069f 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DExpectSymbolSsm::on_quoted_literal(DExpectSymbolSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index f5f650ae..e83c591a 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DExpectTypeSsm::on_quoted_literal(DExpectTypeSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp index d5a78844..fc28d9c9 100644 --- a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DIfElseSsm::on_quoted_literal(DIfElseSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp index f99ab05d..2ce18e6b 100644 --- a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DLambdaSsm::on_quoted_literal(DLambdaSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp index 0773ff3f..dcd49028 100644 --- a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DParenSsm::on_quoted_literal(DParenSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 0e1e4a4c..c9d1931c 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DProgressSsm::on_quoted_literal(DProgressSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp b/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp index c3264db0..9281d6f5 100644 --- a/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DQuoteSsm::on_quoted_literal(DQuoteSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp index bc6ab823..5aa181bb 100644 --- a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DSequenceSsm::on_quoted_literal(DSequenceSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp index 6850aee1..698ccefc 100644 --- a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp @@ -67,6 +67,11 @@ namespace xo { { self.on_parsed_expression_with_token(expr, tk, p_psm); } + auto + ISyntaxStateMachine_DToplevelSeqSsm::on_quoted_literal(DToplevelSeqSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index dee9e4b2..bade16dc 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -569,6 +569,32 @@ namespace xo { this->capture_error(ssm_name, errmsg); } + void + ParserStateMachine::illegal_quoted_literal(std::string_view ssm_name, + obj lit, + std::string_view expect_str) + { + obj lit_pr + = FacetRegistry::instance().variant(lit); + + /** TODO + * problem here: we have pretty() support for obj, + * but not "ordinary printing" support. So expression doesn't get printed + **/ + auto errmsg_string = tostr("Unexpected quoted literal", + xtag("lit", lit_pr), + xtag("expecting", expect_str), + xtag("ssm", ssm_name), + xtag("via", "ParserStateMachine::illegal_quoted_literal")); + + assert(expr_alloc_); + + auto errmsg = DString::from_view(expr_alloc_, + std::string_view(errmsg_string)); + + this->capture_error(ssm_name, errmsg); + } + void ParserStateMachine::error_unbound_variable(std::string_view ssm_name, std::string_view sym) From 906bb2a913e0b1bfac006df642c8bcc92e3cef06 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 2 Mar 2026 11:05:12 +1100 Subject: [PATCH 261/342] xo-interpreter2 stack: handle operator expressions w/ qliterals --- CMakeLists.txt | 20 ++ idl/IPrintable_DExpectQLiteralSsm.json5 | 16 ++ ...yntaxStateMachine_DExpectQLiteralSsm.json5 | 16 ++ include/xo/reader2/DExpectExprSsm.hpp | 17 ++ include/xo/reader2/DExpectQLiteralSsm.hpp | 143 ++++++++++ include/xo/reader2/DQuoteSsm.hpp | 17 +- include/xo/reader2/DToplevelSeqSsm.hpp | 5 + include/xo/reader2/ExpectQLiteralSsm.hpp | 12 + include/xo/reader2/ParserStateMachine.hpp | 3 + .../ssm/IPrintable_DExpectQLiteralSsm.hpp | 62 +++++ ...ISyntaxStateMachine_DExpectQLiteralSsm.hpp | 82 ++++++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 5 + src/reader2/DExpectExprSsm.cpp | 38 ++- src/reader2/DExpectQLiteralSsm.cpp | 256 ++++++++++++++++++ src/reader2/DProgressSsm.cpp | 4 +- src/reader2/DQuoteSsm.cpp | 55 ++-- src/reader2/DToplevelSeqSsm.cpp | 33 ++- src/reader2/IPrintable_DExpectQLiteralSsm.cpp | 28 ++ ...ISyntaxStateMachine_DExpectQLiteralSsm.cpp | 79 ++++++ src/reader2/ParserStateMachine.cpp | 6 + src/reader2/reader2_register_facets.cpp | 9 + src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 82 +++++- 24 files changed, 942 insertions(+), 51 deletions(-) create mode 100644 idl/IPrintable_DExpectQLiteralSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5 create mode 100644 include/xo/reader2/DExpectQLiteralSsm.hpp create mode 100644 include/xo/reader2/ExpectQLiteralSsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DExpectQLiteralSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp create mode 100644 src/reader2/DExpectQLiteralSsm.cpp create mode 100644 src/reader2/IPrintable_DExpectQLiteralSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c70ad114..eef3fddb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,6 +313,26 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqliteralssm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ExpectQLiteralSsm + INPUT idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expectqliteralssm + FACET_PKG xo_printable2 + FACET Printable + REPR ExpectQLiteralSsm + INPUT idl/IPrintable_DExpectQLiteralSsm.json5 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-reader2-genfacet-all) # ---------------------------------------------------------------- diff --git a/idl/IPrintable_DExpectQLiteralSsm.json5 b/idl/IPrintable_DExpectQLiteralSsm.json5 new file mode 100644 index 00000000..ae3f9dd6 --- /dev/null +++ b/idl/IPrintable_DExpectQLiteralSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectQLiteralSsm", + using_doxygen: true, + repr: "DExpectQLiteralSsm", + doc: [ "implement APrintable for DExpectQLiteralSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5 b/idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5 new file mode 100644 index 00000000..58310939 --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectQLiteralSsm", + using_doxygen: true, + repr: "DExpectQLiteralSsm", + doc: [ "implement ASyntaxStateMachine for DExpectQLiteralSsm" ], +} diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 16739006..539fbb39 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -76,6 +76,14 @@ namespace xo { void on_leftbrace_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on quote token @p tk, + * with overall parser state in @p p_psm. + * + * Starts nested {progress-ssm, quote-ssm} combination. + **/ + void on_quote_token(const Token & tk, + ParserStateMachine * p_psm); + /** step state machine for this syntax on incoming boolean literal token @p tkk * with overall parser state in @p p_psm **/ @@ -160,6 +168,15 @@ namespace xo { const Token & tk, ParserStateMachine * p_psm); +#ifdef NOT_YET + /** update state for literal @p lit with overall state in @p p_psm. + * wraps literal as constant-expr + starts progress-ssm for possible + * operator expression. + **/ + void on_quoted_literal(obj lit, + ParserStateMachine * p_psm); +#endif + ///@} /** @defgroup scm-define-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DExpectQLiteralSsm.hpp b/include/xo/reader2/DExpectQLiteralSsm.hpp new file mode 100644 index 00000000..407146a5 --- /dev/null +++ b/include/xo/reader2/DExpectQLiteralSsm.hpp @@ -0,0 +1,143 @@ +/** @file DExpectQLiteralSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +//#include +//#include + +namespace xo { + namespace scm { +#ifdef NOT_USING + /** + * Already in quoted-literal context + * + * #q{ } + * ^ + * qliteral_0 + * + * qliteral_0 --on_leftparen_token()--> push QuotedListSsm + **/ + enum class formalarglstatetype { + invalid = -1, + + argl_0, + argl_1a, + argl_1b, + + n_formalarglstatetype, + }; + + extern const char * + formalarglstatetype_descr(formalarglstatetype x); + + inline std::ostream & + operator<< (std::ostream & os, formalarglstatetype x) { + os << formalarglstatetype_descr(x); + return os; + } +#endif + + /** @class expect_formal_arglist + * @brief parser state-machine for a formal parameter list + **/ + class DExpectQLiteralSsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; + using TypeDescr = xo::reflect::TypeDescr; + using ppindentinfo = xo::print::ppindentinfo; + using size_type = std::uint32_t; + + public: + DExpectQLiteralSsm(); + + /** create instance, using memory from @parser_mm **/ + static obj make(DArena & parser_mm); + static DExpectQLiteralSsm * _make(DArena & parser_mm); + + /** start nested syntax for a quoted literal **/ + static void start(ParserStateMachine * p_psm); + + /** @defgroup scm-expectformalarglistssm-methods general methods **/ + ///@{ + + static const char * ssm_classname() { return "DExpectQLiteralSsm"; } + + /** update state for f64 token @p tk, with overall parser state in @p p_psm. + * delegates to parent ssm via @ref on_quoted_literal + **/ + void on_f64_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ + void on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ + void on_comma_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on incoming rightparen token @p tk, with overall parser state in @p p_psm **/ + void on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectformalarglistssm-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** mnemonic for expected input (for this ssm) in current state **/ + std::string_view get_expect_str() const; + + /** update state on incoming token @p tk, + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectformalarglistssm-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + /** @defgroup scm-expectformalarglistssm-impl-methods **/ + ///@{ + + /** update local state to include parsed formal (param_name, param_type). + * If stack memory needed, get from @p parser_alloc. + * Lifetime until formal arglist completely parsed + **/ + void _accept_formal(obj expr_alloc, + DArena & parser_alloc, + const DUniqueString * param_name, + TypeDescr param_type); + + ///@} + + private: +#ifdef NOT_USING + /** parsing state-machine state **/ + formalarglstatetype fastate_ = formalarglstatetype::argl_0; + /** populate with (parameter-name, parameter-type) list + * as they're encountered. + * + * Not using flexible array here since we don't know size at construction time + **/ + DArray * argl_ = nullptr; +#endif + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectQLiteralSsm.hpp */ diff --git a/include/xo/reader2/DQuoteSsm.hpp b/include/xo/reader2/DQuoteSsm.hpp index 5252e941..6cbfac79 100644 --- a/include/xo/reader2/DQuoteSsm.hpp +++ b/include/xo/reader2/DQuoteSsm.hpp @@ -100,6 +100,13 @@ namespace xo { /** @defgroup scm-parenssm-admin-methods admin methods **/ ///@{ + /** update ssm for incoming quote token @p tk. + * with overall parser state in @p p_psm. + * advances from quote_0 -> quote_1. Otherwise error + **/ + void on_quote_token(const Token & tk, + ParserStateMachine * p_psm); + /** update ssm state for incoming leftparen token @p tk, * with overall parser state in @p p_psm **/ @@ -129,17 +136,9 @@ namespace xo { /** update ssm for expression @p expr (emitted by nested ssm), * with overall parser state in @p p_psm **/ - void on_parsed_expression(obj expr, + void on_quoted_literal(obj literal, ParserStateMachine * p_psm); - /** update ssm for expression @p expr (emitted by nested ssm) - * that's immediately followed by token @p tk - * with overall parser state in @p p_psm - **/ - void on_parsed_expression_with_token(obj expr, - const Token & tk, - ParserStateMachine * p_psmn); - ///@} /** @defgroup scm-parenssm-printable-facet printable facet methods **/ ///@{ diff --git a/include/xo/reader2/DToplevelSeqSsm.hpp b/include/xo/reader2/DToplevelSeqSsm.hpp index 743d2133..d20e751a 100644 --- a/include/xo/reader2/DToplevelSeqSsm.hpp +++ b/include/xo/reader2/DToplevelSeqSsm.hpp @@ -119,6 +119,11 @@ namespace xo { **/ void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); + /** update ssm for incoming quote token @p tk, overall parser state in @p p_psm + * starts nested syntax for quoted literal + **/ + void on_quote_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on parsed expression @p expr * from nested ssm. * overall parser state in @p p_psm diff --git a/include/xo/reader2/ExpectQLiteralSsm.hpp b/include/xo/reader2/ExpectQLiteralSsm.hpp new file mode 100644 index 00000000..562387dc --- /dev/null +++ b/include/xo/reader2/ExpectQLiteralSsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectQLiteralSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DExpectQLiteralSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp" +#include "ssm/IPrintable_DExpectQLiteralSsm.hpp" + +/* end ExpectQLiteralSsm.hpp */ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index f8214a39..0c01e452 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -186,6 +186,9 @@ namespace xo { void on_parsed_expression_with_token(obj expr, const Token & tk); + /** update state to consume quoted literal @p lit **/ + void on_quoted_literal(obj lit); + /** update state to respond to input token @p tk. * record output (if any) in @ref result_ **/ diff --git a/include/xo/reader2/ssm/IPrintable_DExpectQLiteralSsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectQLiteralSsm.hpp new file mode 100644 index 00000000..ec20bbc4 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DExpectQLiteralSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectQLiteralSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQLiteralSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQLiteralSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectQLiteralSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectQLiteralSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectQLiteralSsm + **/ + class IPrintable_DExpectQLiteralSsm { + public: + /** @defgroup scm-printable-dexpectqliteralssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpectqliteralssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectQLiteralSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp new file mode 100644 index 00000000..303d137e --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp @@ -0,0 +1,82 @@ +/** @file ISyntaxStateMachine_DExpectQLiteralSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectQLiteralSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectQLiteralSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectQLiteralSsm + **/ + class ISyntaxStateMachine_DExpectQLiteralSsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpectqliteralssm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexpectqliteralssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectQLiteralSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectQLiteralSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectQLiteralSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectQLiteralSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectQLiteralSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectQLiteralSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DExpectQLiteralSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExpectQLiteralSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for nested parsed expression @p expr **/ + static void on_parsed_expression(DExpectQLiteralSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExpectQLiteralSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectQLiteralSsm & self, obj lit, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 6c6849dc..68656581 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -60,6 +60,9 @@ namespace xo { /** expecting a rhs expression. See @ref DExpectExprSsm **/ expect_rhs_expression, + /** expecting a quoted literal. See @ref DExpectQLiteralSsm **/ + expect_qliteral, + /** comes lasts, counts number of valid enums **/ N }; diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 862ca0e6..b00c4d04 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -65,6 +65,10 @@ set(SELF_SRCS ISyntaxStateMachine_DExpectExprSsm.cpp IPrintable_DExpectExprSsm.cpp + DExpectQLiteralSsm.cpp + ISyntaxStateMachine_DExpectQLiteralSsm.cpp + IPrintable_DExpectQLiteralSsm.cpp + DProgressSsm.cpp ISyntaxStateMachine_DProgressSsm.cpp IPrintable_DProgressSsm.cpp @@ -72,6 +76,7 @@ set(SELF_SRCS DQuoteSsm.cpp ISyntaxStateMachine_DQuoteSsm.cpp IPrintable_DQuoteSsm.cpp + ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 1248947c..57cf3836 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -7,10 +7,11 @@ #include "ParserStateMachine.hpp" #include "ParserStack.hpp" #include "SyntaxStateMachine.hpp" -#include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" +#include "ProgressSsm.hpp" #include "DSequenceSsm.hpp" #include "IfElseSsm.hpp" #include "LambdaSsm.hpp" +#include "QuoteSsm.hpp" #include "syntaxstatetype.hpp" #include #include @@ -22,14 +23,10 @@ #include #ifdef NOT_YET -#include "exprstatestack.hpp" #include "define_xs.hpp" -#include "lambda_xs.hpp" -#include "if_else_xs.hpp" #include "paren_xs.hpp" #include "sequence_xs.hpp" #include "progress_xs.hpp" -#include "xo/expression/pretty_expression.hpp" #endif namespace xo { @@ -140,6 +137,10 @@ namespace xo { this->on_def_token(tk, p_psm); return; + case tokentype::tk_quote: + this->on_quote_token(tk, p_psm); + return; + case tokentype::tk_string: this->on_string_token(tk, p_psm); return; @@ -169,7 +170,6 @@ namespace xo { case tokentype::tk_singleassign: case tokentype::tk_colon: case tokentype::tk_semicolon: - case tokentype::tk_quote: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_rightbrace: @@ -344,6 +344,17 @@ namespace xo { Super::on_token(tk, p_psm); } + void + DExpectExprSsm::on_quote_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + DProgressSsm::start(p_psm->parser_alloc(), p_psm); + DQuoteSsm::start(p_psm); + p_psm->on_token(Token::quote_token()); + } + void DExpectExprSsm::on_bool_token(const Token & tk, ParserStateMachine * p_psm) @@ -500,6 +511,21 @@ namespace xo { p_psm->on_parsed_expression_with_token(expr, tk); } +#ifdef NOT_YET + void + DExpectExprSsm::on_quoted_literal(obj lit, + ParserStateMachine * p_psm) + { + // note: impl here parallels .on_f64_token() .on_i64_token() etc. + + auto expr = DConstant::make(p_psm->expr_alloc(), lit); + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); + } +#endif + bool DExpectExprSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp new file mode 100644 index 00000000..78c62430 --- /dev/null +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -0,0 +1,256 @@ +/* @file DExpectQLiteralSsm.cpp + * + * @author Roland Conybeare, Mar 2026 + */ + +#include "ExpectQLiteralSsm.hpp" +#include +//#include "DExpectFormalArgSsm.hpp" +//#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" +//#include +//#include +//#include +//#include +//#include +#include + +namespace xo { +// using xo::print::APrintable; +// using xo::print::ppstate; +// using xo::print::ppindentinfo; + using xo::mm::AGCObject; +// using xo::mm::AAllocator; +// using xo::facet::FacetRegistry; +// using xo::reflect::typeseq; + + namespace scm { +#ifdef NOT_USING + const char * + formalarglstatetype_descr(formalarglstatetype x) { + switch (x) { + case formalarglstatetype::invalid: + return "invalid"; + case formalarglstatetype::argl_0: + return "argl_0"; + case formalarglstatetype::argl_1a: + return "argl_1a"; + case formalarglstatetype::argl_1b: + return "argl_1b"; + case formalarglstatetype::n_formalarglstatetype: + break; + } + + return "?formalarglstatetype"; + } +#endif + + DExpectQLiteralSsm::DExpectQLiteralSsm() + {} + + DExpectQLiteralSsm * + DExpectQLiteralSsm::_make(DArena & arena) + { + /* out-of-order so argl follows ssm in arena, + * consistent with any subsequent arglist realloc. + * Not a load-bearing choice however + */ + + void * mem = arena.alloc_for(); + + return new (mem) DExpectQLiteralSsm(); + } + + obj + DExpectQLiteralSsm::make(DArena & arena) + { + obj retval(_make(arena)); + + return retval; + } + + void + DExpectQLiteralSsm::start(ParserStateMachine * p_psm) + { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DExpectQLiteralSsm::make(p_psm->parser_alloc())); + } + + syntaxstatetype + DExpectQLiteralSsm::ssm_type() const noexcept { + return syntaxstatetype::expect_qliteral; + } + + std::string_view + DExpectQLiteralSsm::get_expect_str() const + { + return "leftparen|leftbracket|leftbrace|string|f64|i64|bool"; + } + + void + DExpectQLiteralSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (tk.tk_type()) { + case tokentype::tk_f64: + this->on_f64_token(tk, p_psm); + return; + + case tokentype::tk_leftparen: + case tokentype::tk_comma: + case tokentype::tk_rightparen: + case tokentype::tk_lambda: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_symbol: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_quote: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + Super::on_token(tk, p_psm); + } + + void + DExpectQLiteralSsm::on_f64_token(const Token & tk, + ParserStateMachine * p_psm) + { + auto literal = DFloat::box(p_psm->expr_alloc(), + tk.f64_value()); + + p_psm->pop_ssm(); + p_psm->on_quoted_literal(literal); + } + +#ifdef NOT_YET + void + DExpectQLiteralSsm::_accept_formal(obj expr_alloc, + DArena & parser_alloc, + const DUniqueString * param_name, + TypeDescr param_type) + { + /* note: param_type can be nullptr */ + TypeRef typeref + = TypeRef::dwim(TypeRef::prefix_type::from_chars("formal"), param_type); + + DVariable * var = DVariable::make(expr_alloc, + param_name, + typeref); + + // need AGCObject facet to use DArray here. + // May want to have gc feature that allows it to use + // FacetRegistry on memory that stores obj + // + // In this case doesn't matter since DExpectQLiteralSsm not actually collected! + + obj var_o(var); + + if (argl_->size() == argl_->capacity()) { + // need to expand argl_ capacity. + // If DArena were to allow it (i.e. offer a realloc() feature, + // could do this in place since this SSM is at the top of the parser stack. + + obj mm(&parser_alloc); + DArray * argl_2x = DArray::empty(mm, 2 * argl_->capacity()); + + for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { + // TODO: prefer non-bounds-checked access here + argl_2x->push_back(argl_->at(i)); + } + + // update in place + this->argl_ = argl_2x; + } + + this->argl_->push_back(var_o); + } +#endif + +#ifdef NOT_YET + void + DExpectQLiteralSsm::on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (fastate_ == formalarglstatetype::argl_0) { + this->fastate_ = formalarglstatetype::argl_1a; + + DExpectFormalArgSsm::start(p_psm); + return; + } + + Super::on_token(tk, p_psm); + } + + void + DExpectQLiteralSsm::on_comma_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (fastate_ == formalarglstatetype::argl_1b) { + this->fastate_ = formalarglstatetype::argl_1a; + + DExpectFormalArgSsm::start(p_psm); + return; + } + + Super::on_token(tk, p_psm); + } + + void + DExpectQLiteralSsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (fastate_ == formalarglstatetype::argl_1b) { + DArray * args = argl_; + + p_psm->pop_ssm(); + p_psm->on_parsed_formal_arglist(args); + return; + } + + Super::on_token(tk, p_psm); + } +#endif + + bool + DExpectQLiteralSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, + "DExpectQLiteralSsm", + refrtag("expect", this->get_expect_str())); + } + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end DExpectQLiteralSsm.cpp */ diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index d2032f39..02d09e8a 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -3,8 +3,7 @@ * @author Roland Conybeare, Jan 2026 **/ -#include "DProgressSsm.hpp" -#include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" +#include "ProgressSsm.hpp" #include "DExpectExprSsm.hpp" #include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" @@ -189,6 +188,7 @@ namespace xo { start(parser_mm, lhs, optype::invalid, p_psm); } + void DProgressSsm::start(DArena & parser_mm, ParserStateMachine * p_psm) diff --git a/src/reader2/DQuoteSsm.cpp b/src/reader2/DQuoteSsm.cpp index b7f33456..1ca8a8a2 100644 --- a/src/reader2/DQuoteSsm.cpp +++ b/src/reader2/DQuoteSsm.cpp @@ -4,8 +4,9 @@ **/ #include "QuoteSsm.hpp" -#include "ExpectExprSsm.hpp" +#include "ExpectQLiteralSsm.hpp" #include "syntaxstatetype.hpp" +#include //#include namespace xo { @@ -88,6 +89,10 @@ namespace xo { { switch (tk.tk_type()) { + case tokentype::tk_quote: + this->on_quote_token(tk, p_psm); + return; + case tokentype::tk_leftbrace: this->on_leftbrace_token(tk, p_psm); return; @@ -108,7 +113,6 @@ namespace xo { case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_if: - case tokentype::tk_quote: case tokentype::tk_leftparen: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: @@ -143,15 +147,25 @@ namespace xo { } void - DQuoteSsm::on_leftbrace_token(const Token & tk, - ParserStateMachine * p_psm) + DQuoteSsm::on_quote_token(const Token & tk, + ParserStateMachine * p_psm) { if (quote_xst_.code() == QuoteXst::code::quote_0) { this->quote_xst_ = QuoteXst(QuoteXst::code::quote_1); + return; + } - assert(false); - //DExpectQLiteralSsm::start(p_psm); - //return; + Super::on_token(tk, p_psm); + } + + void + DQuoteSsm::on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (quote_xst_.code() == QuoteXst::code::quote_1) { + this->quote_xst_ = QuoteXst(QuoteXst::code::quote_2); + DExpectQLiteralSsm::start(p_psm); + return; } Super::on_token(tk, p_psm); @@ -173,41 +187,24 @@ namespace xo { } void - DQuoteSsm::on_parsed_expression(obj expr, - ParserStateMachine * p_psm) + DQuoteSsm::on_quoted_literal(obj literal, + ParserStateMachine * p_psm) { if (quote_xst_.code() == QuoteXst::code::quote_2) { this->quote_xst_ = QuoteXst(QuoteXst::code::quote_3); - this->expr_ = expr; + this->expr_ = DConstant::make(p_psm->expr_alloc(), literal); return; } - Super::on_parsed_expression(expr, p_psm); - } - - void - DQuoteSsm::on_parsed_expression_with_token(obj expr, - const Token & tk, - ParserStateMachine * p_psm) - { - if (quote_xst_.code() == QuoteXst::code::quote_2) { - this->quote_xst_ = QuoteXst(QuoteXst::code::quote_3); - this->expr_ = expr; - - this->on_token(tk, p_psm); - - return; - } - - Super::on_parsed_expression(expr, p_psm); + Super::illegal_quoted_literal(literal, p_psm); } bool DQuoteSsm::pretty(const ppindentinfo & ppii) const { return ppii.pps()->pretty_struct(ppii, - "DParenSsm", + "DQuoteSsm", refrtag("quote_xst", quote_xst_), refrtag("expect", this->get_expect_str())); } diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index d7520e87..0473660f 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -9,12 +9,13 @@ #include "DLambdaSsm.hpp" #include "ProgressSsm.hpp" #include "DIfElseSsm.hpp" +#include "QuoteSsm.hpp" #include "ParenSsm.hpp" #include "ExpectExprSsm.hpp" #include "VarRef.hpp" -#include -#include +#include +//#include #include #include @@ -160,9 +161,12 @@ namespace xo { this->on_leftparen_token(tk, p_psm); return; + case tokentype::tk_quote: + this->on_quote_token(tk, p_psm); + return; + // all the not-yet handled cases case tokentype::tk_invalid: - case tokentype::tk_quote: case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: @@ -424,6 +428,29 @@ namespace xo { Super::on_token(tk, p_psm); } + void + DToplevelSeqSsm::on_quote_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (seqtype_) { + case exprseqtype::toplevel_interactive: { + DProgressSsm::start(p_psm->parser_alloc(), + p_psm); + DQuoteSsm::start(p_psm); + p_psm->on_token(Token::quote_token()); + + return; + } + case exprseqtype::toplevel_batch: + break; + case exprseqtype::N: + assert(false); // unreachable + break; + } + + Super::on_token(tk, p_psm); + } + void DToplevelSeqSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) diff --git a/src/reader2/IPrintable_DExpectQLiteralSsm.cpp b/src/reader2/IPrintable_DExpectQLiteralSsm.cpp new file mode 100644 index 00000000..24c33902 --- /dev/null +++ b/src/reader2/IPrintable_DExpectQLiteralSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectQLiteralSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQLiteralSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQLiteralSsm.json5] +**/ + +#include "ssm/IPrintable_DExpectQLiteralSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectQLiteralSsm::pretty(const DExpectQLiteralSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectQLiteralSsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp new file mode 100644 index 00000000..977b1194 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp @@ -0,0 +1,79 @@ +/** @file ISyntaxStateMachine_DExpectQLiteralSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectQLiteralSsm::ssm_type(const DExpectQLiteralSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectQLiteralSsm::get_expect_str(const DExpectQLiteralSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectQLiteralSsm::on_token(DExpectQLiteralSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQLiteralSsm::on_parsed_symbol(DExpectQLiteralSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExpectQLiteralSsm::on_parsed_typedescr(DExpectQLiteralSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DExpectQLiteralSsm::on_parsed_formal(DExpectQLiteralSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DExpectQLiteralSsm::on_parsed_formal_with_token(DExpectQLiteralSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQLiteralSsm::on_parsed_formal_arglist(DExpectQLiteralSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DExpectQLiteralSsm::on_parsed_expression(DExpectQLiteralSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DExpectQLiteralSsm::on_parsed_expression_with_token(DExpectQLiteralSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQLiteralSsm::on_quoted_literal(DExpectQLiteralSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectQLiteralSsm.cpp */ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index bade16dc..125ca1dd 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -330,6 +330,12 @@ namespace xo { this->top_ssm().on_parsed_expression_with_token(expr, tk, this); } + void + ParserStateMachine::on_quoted_literal(obj lit) + { + this->top_ssm().on_quoted_literal(lit, this); + } + void ParserStateMachine::on_token(const Token & tk) { diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 59d91907..b3fe47be 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -13,11 +13,13 @@ #include "ApplySsm.hpp" #include "SequenceSsm.hpp" #include "ParenSsm.hpp" +#include "QuoteSsm.hpp" #include "ExpectFormalArglistSsm.hpp" #include "ExpectFormalArgSsm.hpp" #include "ExpectSymbolSsm.hpp" #include "ExpectTypeSsm.hpp" #include "ExpectExprSsm.hpp" +#include "ExpectQLiteralSsm.hpp" #include "ProgressSsm.hpp" #include "SyntaxStateMachine.hpp" @@ -75,6 +77,12 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + // misc types showing up in aux arena TypeRegistry::register_type(); // misc types showing up in parser stack arena @@ -91,6 +99,7 @@ namespace xo { log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); log && log(xtag("DProgressSsm.tseq", typeseq::id())); log && log(xtag("DParenSsm.tseq", typeseq::id())); + log && log(xtag("DQuoteSsm.tseq", typeseq::id())); log && log(xtag("ASyntaxStateMachine.tseq", typeseq::id())); return true; diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index 0d7dd7e2..c4eb3667 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -41,6 +41,8 @@ namespace xo { return "expect-type"; case syntaxstatetype::expect_rhs_expression: return "expect-rhs-expression"; + case syntaxstatetype::expect_qliteral: + return "expect-qliteral"; case syntaxstatetype::N: break; } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 274cca2f..6637ad9a 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -849,7 +849,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); @@ -1151,7 +1151,7 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -1203,6 +1203,84 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-batch-qliteral1", "[reader2][SchematikaParser]") + { + // top-level recursive function definition + + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * #q{ 4.5 } ; + * ^ ^ ^ ^ ^ + * 0 1 2 3 4 + **/ + + std::vector tk_v{ + /* [ 0] */ Token::quote_token(), + + /* [ 1] */ Token::leftbrace_token(), + /* [ 2] */ Token::f64_token("4.5"), + /* [ 3] */ Token::rightbrace_token(), + /* [ 4] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); + } + + TEST_CASE("SchematikaParser-batch-qliteral2", "[reader2][SchematikaParser]") + { + // top-level recursive function definition + + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * #q{ 4.5 } + #q { 7.2 }; + * ^ ^ ^ ^ ^ ^ ^ ^ ^^ + * 0 1 2 3 4 5 6 7 8| + * 9 + **/ + + std::vector tk_v{ + /* [ 0] */ Token::quote_token(), + /* [ 1] */ Token::leftbrace_token(), + /* [ 2] */ Token::f64_token("4.5"), + /* [ 3] */ Token::rightbrace_token(), + + /* [ 4] */ Token::plus_token(), + + /* [ 5] */ Token::quote_token(), + /* [ 6] */ Token::leftbrace_token(), + /* [ 7] */ Token::f64_token("7.2"), + /* [ 8] */ Token::rightbrace_token(), + + /* [ 9] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); + } + } /*namespace ut*/ } /*namespace xo*/ From 650a9fa95f1851dc92720a289470ab37ec44ac8f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 2 Mar 2026 11:05:12 +1100 Subject: [PATCH 262/342] xo-interpreter2 stack: handle operator expressions w/ qliterals --- include/xo/tokenizer2/Token.hpp | 2 +- src/tokenizer2/Tokenizer.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index 9ddd0181..9c748933 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -88,7 +88,7 @@ namespace xo { return Token(tokentype::tk_symbol, txt); } /** token representing quote @c "'" **/ - static Token quote() { return Token(tokentype::tk_quote); } + static Token quote_token() { return Token(tokentype::tk_quote); } /** token representing left angle bracket @c "<" **/ static Token leftangle() { return Token(tokentype::tk_leftangle); } /** token representing right angle bracket @c ">" **/ diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index 8821cd65..323c2d8d 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -429,6 +429,7 @@ namespace xo { break; } + case '#': case 'a': case 'A': case 'b': case 'B': case 'c': case 'C': From f2a9aa3f524d355e76261759e9a5cad68d73bd1e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 2 Mar 2026 23:21:10 +1100 Subject: [PATCH 263/342] xo-interpreter2 stack: parse literal lists (w/ implicit types) --- CMakeLists.txt | 20 ++ idl/IPrintable_DExpectQListSsm.json5 | 16 ++ idl/ISyntaxStateMachine_DExpectQListSsm.json5 | 16 ++ include/xo/reader2/DExpectQListSsm.hpp | 155 +++++++++++ include/xo/reader2/DExpectQLiteralSsm.hpp | 55 +--- include/xo/reader2/DSyntaxStateMachine.hpp | 19 +- include/xo/reader2/ExpectQListSsm.hpp | 12 + .../ssm/IPrintable_DExpectQListSsm.hpp | 62 +++++ .../ISyntaxStateMachine_DExpectQListSsm.hpp | 82 ++++++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 4 + src/reader2/DExepctQListSsm.cpp | 255 ++++++++++++++++++ src/reader2/DExpectQListSsm.cpp | 215 +++++++++++++++ src/reader2/DExpectQLiteralSsm.cpp | 75 +++--- src/reader2/IPrintable_DExpectQListSsm.cpp | 28 ++ .../ISyntaxStateMachine_DExpectQListSsm.cpp | 79 ++++++ src/reader2/reader2_register_facets.cpp | 11 +- src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 42 ++- 19 files changed, 1052 insertions(+), 99 deletions(-) create mode 100644 idl/IPrintable_DExpectQListSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DExpectQListSsm.json5 create mode 100644 include/xo/reader2/DExpectQListSsm.hpp create mode 100644 include/xo/reader2/ExpectQListSsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DExpectQListSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp create mode 100644 src/reader2/DExepctQListSsm.cpp create mode 100644 src/reader2/DExpectQListSsm.cpp create mode 100644 src/reader2/IPrintable_DExpectQListSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index eef3fddb..b7b5a5f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -333,6 +333,26 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqlistssm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ExpectQListSsm + INPUT idl/ISyntaxStateMachine_DExpectQListSsm.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expectqlistssm + FACET_PKG xo_printable2 + FACET Printable + REPR ExpectQListSsm + INPUT idl/IPrintable_DExpectQListSsm.json5 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-reader2-genfacet-all) # ---------------------------------------------------------------- diff --git a/idl/IPrintable_DExpectQListSsm.json5 b/idl/IPrintable_DExpectQListSsm.json5 new file mode 100644 index 00000000..91f98f8f --- /dev/null +++ b/idl/IPrintable_DExpectQListSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectQListSsm", + using_doxygen: true, + repr: "DExpectQListSsm", + doc: [ "implement APrintable for DExpectQListSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DExpectQListSsm.json5 b/idl/ISyntaxStateMachine_DExpectQListSsm.json5 new file mode 100644 index 00000000..94d59ba0 --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectQListSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectQListSsm", + using_doxygen: true, + repr: "DExpectQListSsm", + doc: [ "implement ASyntaxStateMachine for DExpectQListSsm" ], +} diff --git a/include/xo/reader2/DExpectQListSsm.hpp b/include/xo/reader2/DExpectQListSsm.hpp new file mode 100644 index 00000000..2b4b70b2 --- /dev/null +++ b/include/xo/reader2/DExpectQListSsm.hpp @@ -0,0 +1,155 @@ +/** @file DExpectQListSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +#include +//#include +#include + +namespace xo { + namespace scm { + /** + * Already in quoted-literal context + * + * ( quote-expr ... ) + * ^ ^ ^ + * | qlist_1a qlist_2(done) + * qlist_0 + * + * qlist_0 --on_leftparen_token()--> qlist_1a [push ExpectQLiteralSsm] + * qlist_1a --on_quoted_literal()--> qlist_1a [append literal] + * qlist_1a --on_rightparen_token()--> qlist_2(done) [report quoted list] + **/ + class QListXst { + public: + enum class code { + invalid = -1, + + qlist_0, + qlist_1a, + qlist_2, + + N + }; + + explicit QListXst(code x) : code_{x} {} + + /** @return string representation for enum @p x **/ + static const char * _descr(code x); + + code code() const noexcept { return code_; } + + enum code code_; + }; + + inline std::ostream & + operator<< (std::ostream & os, QListXst x) { + os << QListXst::_descr(x.code_); + return os; + } + + /** @class DExpectQListSsm + * @brief parser state-machine for a formal parameter list + **/ + class DExpectQListSsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; + using TypeDescr = xo::reflect::TypeDescr; + using ppindentinfo = xo::print::ppindentinfo; + using size_type = std::uint32_t; + + public: + /** @defgroup scm-expectqlistssm-ctors constructors **/ + ///@{ + + DExpectQListSsm(); + + /** create instance, using memory from @parser_mm **/ + static obj make(DArena & parser_mm); + static DExpectQListSsm * _make(DArena & parser_mm); + + /** start nested syntax for a quoted literal **/ + static void start(ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectformalarglistssm-methods general methods **/ + ///@{ + + static const char * ssm_classname() { return "DExpectQListSsm"; } + + /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ + void on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm); + + void on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqlistssm-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** mnemonic for expected input (for this ssm) in current state **/ + std::string_view get_expect_str() const; + + /** update state on incoming token @p tk, + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for nested qliteral @p lit, with overall parser state in @p p_psm. + * Appends @p lit to target list + **/ + void on_quoted_literal(obj lit, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqlistssm-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + /** @defgroup scm-expectqlistssm-impl-methods **/ + ///@{ + + /** update local state to include parsed formal (param_name, param_type). + * If stack memory needed, get from @p parser_alloc. + * Lifetime until formal arglist completely parsed + **/ + void _accept_formal(obj expr_alloc, + DArena & parser_alloc, + const DUniqueString * param_name, + TypeDescr param_type); + + ///@} + + private: + /** @defgroup scm-expectqlistssm-member-vars **/ + ///@{ + + /** identifies qlist parsing state **/ + QListXst state_; + + /** first node in literal list **/ + DList * start_ = nullptr; + /** last node in literal list **/ + DList * end_ = nullptr; + + ///@} + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectQListSsm.hpp */ diff --git a/include/xo/reader2/DExpectQLiteralSsm.hpp b/include/xo/reader2/DExpectQLiteralSsm.hpp index 407146a5..efb93f6d 100644 --- a/include/xo/reader2/DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/DExpectQLiteralSsm.hpp @@ -11,37 +11,7 @@ namespace xo { namespace scm { -#ifdef NOT_USING - /** - * Already in quoted-literal context - * - * #q{ } - * ^ - * qliteral_0 - * - * qliteral_0 --on_leftparen_token()--> push QuotedListSsm - **/ - enum class formalarglstatetype { - invalid = -1, - - argl_0, - argl_1a, - argl_1b, - - n_formalarglstatetype, - }; - - extern const char * - formalarglstatetype_descr(formalarglstatetype x); - - inline std::ostream & - operator<< (std::ostream & os, formalarglstatetype x) { - os << formalarglstatetype_descr(x); - return os; - } -#endif - - /** @class expect_formal_arglist + /** @class DExpectQLiteralSsm * @brief parser state-machine for a formal parameter list **/ class DExpectQLiteralSsm : public DSyntaxStateMachine { @@ -54,14 +24,17 @@ namespace xo { using size_type = std::uint32_t; public: - DExpectQLiteralSsm(); + explicit DExpectQLiteralSsm(bool cxl_on_rightparen); /** create instance, using memory from @parser_mm **/ - static obj make(DArena & parser_mm); - static DExpectQLiteralSsm * _make(DArena & parser_mm); + static obj make(DArena & parser_mm, + bool cxl_on_rightparen); + static DExpectQLiteralSsm * _make(DArena & parser_mm, + bool cxl_on_rightparen); /** start nested syntax for a quoted literal **/ - static void start(ParserStateMachine * p_psm); + static void start(ParserStateMachine * p_psm, + bool cxl_on_rightparen = false); /** @defgroup scm-expectformalarglistssm-methods general methods **/ ///@{ @@ -126,16 +99,8 @@ namespace xo { ///@} private: -#ifdef NOT_USING - /** parsing state-machine state **/ - formalarglstatetype fastate_ = formalarglstatetype::argl_0; - /** populate with (parameter-name, parameter-type) list - * as they're encountered. - * - * Not using flexible array here since we don't know size at construction time - **/ - DArray * argl_ = nullptr; -#endif + /** if true rightparen pops + delegates to parent ssm **/ + bool cxl_on_rightparen_ = false; }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/DSyntaxStateMachine.hpp b/include/xo/reader2/DSyntaxStateMachine.hpp index b72a3e92..adce34e1 100644 --- a/include/xo/reader2/DSyntaxStateMachine.hpp +++ b/include/xo/reader2/DSyntaxStateMachine.hpp @@ -32,6 +32,18 @@ namespace xo { using TypeDescr = xo::reflect::TypeDescr; using AGCObject = xo::mm::AGCObject; + /** Explicit error path **/ + void illegal_token(const Token & tk, + ParserStateMachine * p_psm) + { + // starting with c++23 can use "this auto&& self" instead + Derived & self = reinterpret_cast(*this); + + p_psm->illegal_input_on_token(Derived::ssm_classname(), + tk, + self.get_expect_str()); + } + /** Explicit error path **/ void illegal_quoted_literal(obj lit, ParserStateMachine * p_psm) @@ -49,12 +61,7 @@ namespace xo { void on_token(const Token & tk, ParserStateMachine * p_psm) { - // starting with c++23 can use "this auto&& self" instead - Derived & self = reinterpret_cast(*this); - - p_psm->illegal_input_on_token(Derived::ssm_classname(), - tk, - self.get_expect_str()); + this->illegal_token(tk, p_psm); } void on_parsed_symbol(std::string_view sym, diff --git a/include/xo/reader2/ExpectQListSsm.hpp b/include/xo/reader2/ExpectQListSsm.hpp new file mode 100644 index 00000000..82a3c0ab --- /dev/null +++ b/include/xo/reader2/ExpectQListSsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectQListSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DExpectQListSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectQListSsm.hpp" +#include "ssm/IPrintable_DExpectQListSsm.hpp" + +/* end ExpectQListSsm.hpp */ diff --git a/include/xo/reader2/ssm/IPrintable_DExpectQListSsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectQListSsm.hpp new file mode 100644 index 00000000..45d72c07 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DExpectQListSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectQListSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQListSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQListSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectQListSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectQListSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectQListSsm + **/ + class IPrintable_DExpectQListSsm { + public: + /** @defgroup scm-printable-dexpectqlistssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpectqlistssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectQListSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp new file mode 100644 index 00000000..6cd1a38b --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp @@ -0,0 +1,82 @@ +/** @file ISyntaxStateMachine_DExpectQListSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQListSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQListSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectQListSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectQListSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectQListSsm + **/ + class ISyntaxStateMachine_DExpectQListSsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpectqlistssm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexpectqlistssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectQListSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectQListSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectQListSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectQListSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectQListSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectQListSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DExpectQListSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExpectQListSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for nested parsed expression @p expr **/ + static void on_parsed_expression(DExpectQListSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExpectQListSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectQListSsm & self, obj lit, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 68656581..0a0c857c 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -63,6 +63,9 @@ namespace xo { /** expecting a quoted literal. See @ref DExpectQLiteralSsm **/ expect_qliteral, + /** expecint a quoted list. See @ref DExpectQListSsm **/ + expect_qlist, + /** comes lasts, counts number of valid enums **/ N }; diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index b00c4d04..fa88a4dd 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -69,6 +69,10 @@ set(SELF_SRCS ISyntaxStateMachine_DExpectQLiteralSsm.cpp IPrintable_DExpectQLiteralSsm.cpp + DExpectQListSsm.cpp + ISyntaxStateMachine_DExpectQListSsm.cpp + IPrintable_DExpectQListSsm.cpp + DProgressSsm.cpp ISyntaxStateMachine_DProgressSsm.cpp IPrintable_DProgressSsm.cpp diff --git a/src/reader2/DExepctQListSsm.cpp b/src/reader2/DExepctQListSsm.cpp new file mode 100644 index 00000000..44393451 --- /dev/null +++ b/src/reader2/DExepctQListSsm.cpp @@ -0,0 +1,255 @@ +/* @file DExpectQListSsm.cpp + * + * @author Roland Conybeare, Mar 2026 + */ + +#include "ExpectQLiteralSsm.hpp" +#include +//#include "DExpectFormalArgSsm.hpp" +//#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" +//#include +//#include +//#include +//#include +//#include +#include + +namespace xo { +// using xo::print::APrintable; +// using xo::print::ppstate; +// using xo::print::ppindentinfo; + using xo::mm::AGCObject; +// using xo::mm::AAllocator; +// using xo::facet::FacetRegistry; +// using xo::reflect::typeseq; + + namespace scm { +#ifdef NOT_USING + const char * + formalarglstatetype_descr(formalarglstatetype x) { + switch (x) { + case formalarglstatetype::invalid: + return "invalid"; + case formalarglstatetype::argl_0: + return "argl_0"; + case formalarglstatetype::argl_1a: + return "argl_1a"; + case formalarglstatetype::argl_1b: + return "argl_1b"; + case formalarglstatetype::n_formalarglstatetype: + break; + } + + return "?formalarglstatetype"; + } +#endif + + DExpectQListSsm::DExpectQListSsm() + {} + + DExpectQListSsm * + DExpectQListSsm::_make(DArena & arena) + { + /* out-of-order so argl follows ssm in arena, + * consistent with any subsequent arglist realloc. + * Not a load-bearing choice however + */ + + void * mem = arena.alloc_for(); + + return new (mem) DExpectQListSsm(); + } + + obj + DExpectQListSsm::make(DArena & arena) + { + obj retval(_make(arena)); + + return retval; + } + + void + DExpectQListSsm::start(ParserStateMachine * p_psm) + { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DExpectQListSsm::make(p_psm->parser_alloc())); + } + + syntaxstatetype + DExpectQListSsm::ssm_type() const noexcept { + return syntaxstatetype::expect_qliteral; + } + + std::string_view + DExpectQListSsm::get_expect_str() const + { + return "leftparen|leftbracket|leftbrace|string|f64|i64|bool"; + } + + void + DExpectQListSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (tk.tk_type()) { + case tokentype::tk_f64: + this->on_f64_token(tk, p_psm); + return; + + case tokentype::tk_leftparen: + case tokentype::tk_comma: + case tokentype::tk_rightparen: + case tokentype::tk_lambda: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_symbol: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_quote: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + Super::on_token(tk, p_psm); + } + + void + DExpectQListSsm::on_f64_token(const Token & tk, + ParserStateMachine * p_psm) + { + auto literal = DFloat::box(p_psm->expr_alloc(), + tk.f64_value()); + + p_psm->pop_ssm(); + p_psm->on_quoted_literal(literal); + } + +#ifdef NOT_YET + void + DExpectQListSsm::_accept_formal(obj expr_alloc, + DArena & parser_alloc, + const DUniqueString * param_name, + TypeDescr param_type) + { + /* note: param_type can be nullptr */ + TypeRef typeref + = TypeRef::dwim(TypeRef::prefix_type::from_chars("formal"), param_type); + + DVariable * var = DVariable::make(expr_alloc, + param_name, + typeref); + + // need AGCObject facet to use DArray here. + // May want to have gc feature that allows it to use + // FacetRegistry on memory that stores obj + // + // In this case doesn't matter since DExpectQListSsm not actually collected! + + obj var_o(var); + + if (argl_->size() == argl_->capacity()) { + // need to expand argl_ capacity. + // If DArena were to allow it (i.e. offer a realloc() feature, + // could do this in place since this SSM is at the top of the parser stack. + + obj mm(&parser_alloc); + DArray * argl_2x = DArray::empty(mm, 2 * argl_->capacity()); + + for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { + // TODO: prefer non-bounds-checked access here + argl_2x->push_back(argl_->at(i)); + } + + // update in place + this->argl_ = argl_2x; + } + + this->argl_->push_back(var_o); + } +#endif + +#ifdef NOT_YET + void + DExpectQListSsm::on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (fastate_ == formalarglstatetype::argl_0) { + this->fastate_ = formalarglstatetype::argl_1a; + + DExpectFormalArgSsm::start(p_psm); + return; + } + + Super::on_token(tk, p_psm); + } + + void + DExpectQListSsm::on_comma_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (fastate_ == formalarglstatetype::argl_1b) { + this->fastate_ = formalarglstatetype::argl_1a; + + DExpectFormalArgSsm::start(p_psm); + return; + } + + Super::on_token(tk, p_psm); + } + + void + DExpectQListSsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (fastate_ == formalarglstatetype::argl_1b) { + DArray * args = argl_; + + p_psm->pop_ssm(); + p_psm->on_parsed_formal_arglist(args); + return; + } + + Super::on_token(tk, p_psm); + } +#endif + + bool + DExpectQListSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, + "DExpectQListSsm", + refrtag("expect", this->get_expect_str())); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectQListSsm.cpp */ diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp new file mode 100644 index 00000000..2227a398 --- /dev/null +++ b/src/reader2/DExpectQListSsm.cpp @@ -0,0 +1,215 @@ +/** @file DExpectQListSsm.cpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#include "ExpectQListSsm.hpp" +#include "ExpectQLiteralSsm.hpp" +#include +#include +#include + +namespace xo { + using xo::print::APrintable; + using xo::facet::FacetRegistry; + using xo::mm::AGCObject; + + namespace scm { + const char * + QListXst::_descr(enum code x) + { + switch (x) { + case code::invalid: break; + case code::qlist_0: return "qlist_0"; + case code::qlist_1a: return "qlist_1a"; + case code::qlist_2: return "qlist_2"; + case code::N: break; + } + + return "?QListXst"; + } + + DExpectQListSsm::DExpectQListSsm() : state_{QListXst::code::qlist_0} {} + + obj + DExpectQListSsm::make(DArena & parser_mm) + { + return obj(_make(parser_mm)); + } + + DExpectQListSsm * + DExpectQListSsm::_make(DArena & parser_mm) + { + void * mem = parser_mm.alloc_for(); + + return new (mem) DExpectQListSsm(); + } + + void + DExpectQListSsm::start(ParserStateMachine * p_psm) + { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DExpectQListSsm::make(p_psm->parser_alloc())); + } + + syntaxstatetype + DExpectQListSsm::ssm_type() const noexcept { + return syntaxstatetype::expect_qlist; + } + + std::string_view + DExpectQListSsm::get_expect_str() const { + switch (state_.code()) { + case QListXst::code::qlist_0: + return "leftparen"; + case QListXst::code::qlist_1a: + return "qliteral|rightparen"; + case QListXst::code::qlist_2: + return "(done)"; + case QListXst::code::invalid: + case QListXst::code::N: + break; + } + + return "?DExpectQListSsm"; + } + + void + DExpectQListSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch(tk.tk_type()) + { + case tokentype::tk_leftparen: + this->on_leftparen_token(tk, p_psm); + return; + + case tokentype::tk_rightparen: + this->on_rightparen_token(tk, p_psm); + return; + + case tokentype::tk_comma: + case tokentype::tk_lambda: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_symbol: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_quote: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + } + + void + DExpectQListSsm::on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QListXst::code::qlist_0) { + this->state_ = QListXst(QListXst::code::qlist_1a); + this->start_ = DList::_nil(); + this->end_ = nullptr; + + DExpectQLiteralSsm::start(p_psm, + true /*cxl_on_rightparen*/); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQListSsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QListXst::code::qlist_1a) { + this->state_ = QListXst(QListXst::code::qlist_2); + + obj lit = obj(start_); + + p_psm->pop_ssm(); + p_psm->on_quoted_literal(lit); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQListSsm::on_quoted_literal(obj lit, + ParserStateMachine * p_psm) + { + if(state_.code() == QListXst::code::qlist_1a) { + // append lit at the end of list start_ .. end_ + { + DList * new_last + = DList::_cons(p_psm->expr_alloc(), lit, DList::_nil()); + + if (this->end_) { + end_->assign_rest(new_last); + + this->end_ = new_last; + } else { + this->start_ = DList::_cons(p_psm->expr_alloc(), + lit, + DList::_nil()); + this->end_ = this->start_; + } + } + + // start syntax to receive next literal + DExpectQLiteralSsm::start(p_psm, + true /*cxl_on_rightparen*/); + return; + } + + Super::illegal_quoted_literal(lit, p_psm); + } + + bool + DExpectQListSsm::pretty(const ppindentinfo & ppii) const + { + obj list(start_); + auto list_pr = FacetRegistry::instance().variant(list); + + return ppii.pps()->pretty_struct(ppii, + "DExpectQListSsm", + refrtag("state", state_), + refrtag("expect", this->get_expect_str()), + refrtag("list", list_pr)); + } + } +} + +/* end DExpectQListSsm.cpp */ diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index 78c62430..efc92a48 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -4,6 +4,7 @@ */ #include "ExpectQLiteralSsm.hpp" +#include "ExpectQListSsm.hpp" #include //#include "DExpectFormalArgSsm.hpp" //#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" @@ -24,31 +25,13 @@ namespace xo { // using xo::reflect::typeseq; namespace scm { -#ifdef NOT_USING - const char * - formalarglstatetype_descr(formalarglstatetype x) { - switch (x) { - case formalarglstatetype::invalid: - return "invalid"; - case formalarglstatetype::argl_0: - return "argl_0"; - case formalarglstatetype::argl_1a: - return "argl_1a"; - case formalarglstatetype::argl_1b: - return "argl_1b"; - case formalarglstatetype::n_formalarglstatetype: - break; - } - - return "?formalarglstatetype"; - } -#endif - - DExpectQLiteralSsm::DExpectQLiteralSsm() + DExpectQLiteralSsm::DExpectQLiteralSsm(bool cxl_on_rightparen) + : cxl_on_rightparen_{cxl_on_rightparen} {} DExpectQLiteralSsm * - DExpectQLiteralSsm::_make(DArena & arena) + DExpectQLiteralSsm::_make(DArena & arena, + bool cxl_on_rightparen) { /* out-of-order so argl follows ssm in arena, * consistent with any subsequent arglist realloc. @@ -57,23 +40,26 @@ namespace xo { void * mem = arena.alloc_for(); - return new (mem) DExpectQLiteralSsm(); + return new (mem) DExpectQLiteralSsm(cxl_on_rightparen); } obj - DExpectQLiteralSsm::make(DArena & arena) + DExpectQLiteralSsm::make(DArena & arena, + bool cxl_on_rightparen) { - obj retval(_make(arena)); - + obj retval(_make(arena, + cxl_on_rightparen)); return retval; } void - DExpectQLiteralSsm::start(ParserStateMachine * p_psm) + DExpectQLiteralSsm::start(ParserStateMachine * p_psm, + bool cxl_on_rightparen) { DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); - p_psm->push_ssm(ckp, DExpectQLiteralSsm::make(p_psm->parser_alloc())); + p_psm->push_ssm(ckp, DExpectQLiteralSsm::make(p_psm->parser_alloc(), + cxl_on_rightparen)); } syntaxstatetype @@ -97,8 +83,14 @@ namespace xo { return; case tokentype::tk_leftparen: - case tokentype::tk_comma: + this->on_leftparen_token(tk, p_psm); + return; + case tokentype::tk_rightparen: + this->on_rightparen_token(tk, p_psm); + return; + + case tokentype::tk_comma: case tokentype::tk_lambda: case tokentype::tk_def: case tokentype::tk_if: @@ -197,21 +189,18 @@ namespace xo { } #endif -#ifdef NOT_YET void DExpectQLiteralSsm::on_leftparen_token(const Token & tk, - ParserStateMachine * p_psm) + ParserStateMachine * p_psm) { - if (fastate_ == formalarglstatetype::argl_0) { - this->fastate_ = formalarglstatetype::argl_1a; + // replace self with specialized version for parsing a literal list - DExpectFormalArgSsm::start(p_psm); - return; - } - - Super::on_token(tk, p_psm); + p_psm->pop_ssm(); + DExpectQListSsm::start(p_psm); + p_psm->on_token(tk); } +#ifdef NOT_YET void DExpectQLiteralSsm::on_comma_token(const Token & tk, ParserStateMachine * p_psm) @@ -225,22 +214,20 @@ namespace xo { Super::on_token(tk, p_psm); } +#endif void DExpectQLiteralSsm::on_rightparen_token(const Token & tk, - ParserStateMachine * p_psm) + ParserStateMachine * p_psm) { - if (fastate_ == formalarglstatetype::argl_1b) { - DArray * args = argl_; - + if (cxl_on_rightparen_) { p_psm->pop_ssm(); - p_psm->on_parsed_formal_arglist(args); + p_psm->on_token(tk); return; } Super::on_token(tk, p_psm); } -#endif bool DExpectQLiteralSsm::pretty(const ppindentinfo & ppii) const diff --git a/src/reader2/IPrintable_DExpectQListSsm.cpp b/src/reader2/IPrintable_DExpectQListSsm.cpp new file mode 100644 index 00000000..c8342703 --- /dev/null +++ b/src/reader2/IPrintable_DExpectQListSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectQListSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQListSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQListSsm.json5] +**/ + +#include "ssm/IPrintable_DExpectQListSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectQListSsm::pretty(const DExpectQListSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectQListSsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp new file mode 100644 index 00000000..2d24b697 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp @@ -0,0 +1,79 @@ +/** @file ISyntaxStateMachine_DExpectQListSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQListSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQListSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DExpectQListSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectQListSsm::ssm_type(const DExpectQListSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectQListSsm::get_expect_str(const DExpectQListSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectQListSsm::on_token(DExpectQListSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_symbol(DExpectQListSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_typedescr(DExpectQListSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_formal(DExpectQListSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_formal_with_token(DExpectQListSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_formal_arglist(DExpectQListSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_expression(DExpectQListSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_expression_with_token(DExpectQListSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_quoted_literal(DExpectQListSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectQListSsm.cpp */ diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index b3fe47be..1df5cb82 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -14,14 +14,15 @@ #include "SequenceSsm.hpp" #include "ParenSsm.hpp" #include "QuoteSsm.hpp" +#include "ProgressSsm.hpp" +#include "SyntaxStateMachine.hpp" #include "ExpectFormalArglistSsm.hpp" #include "ExpectFormalArgSsm.hpp" #include "ExpectSymbolSsm.hpp" #include "ExpectTypeSsm.hpp" #include "ExpectExprSsm.hpp" #include "ExpectQLiteralSsm.hpp" -#include "ProgressSsm.hpp" -#include "SyntaxStateMachine.hpp" +#include "ExpectQListSsm.hpp" #include #include @@ -83,6 +84,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + // misc types showing up in aux arena TypeRegistry::register_type(); // misc types showing up in parser stack arena @@ -97,6 +101,9 @@ namespace xo { log && log(xtag("DExpectSymbolSsm.tseq", typeseq::id())); log && log(xtag("DExpectTypeSsm.tseq", typeseq::id())); log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); + log && log(xtag("DExpectQLiteralSsm.tseq", typeseq::id())); + log && log(xtag("DExpectQListSsm.tseq", typeseq::id())); + log && log(xtag("DProgressSsm.tseq", typeseq::id())); log && log(xtag("DParenSsm.tseq", typeseq::id())); log && log(xtag("DQuoteSsm.tseq", typeseq::id())); diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index c4eb3667..f1d93239 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -43,6 +43,8 @@ namespace xo { return "expect-rhs-expression"; case syntaxstatetype::expect_qliteral: return "expect-qliteral"; + case syntaxstatetype::expect_qlist: + return "expect-qlist"; case syntaxstatetype::N: break; } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 6637ad9a..17022d42 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1209,7 +1209,7 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -1244,7 +1244,7 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -1281,6 +1281,44 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-batch-qlist", "[reader2][SchematikaParser]") + { + // top-level recursive function definition + + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * #q{ (4.5 7.2) }; + * ^ ^ ^^ ^ ^ ^^ + * 0 1 2| 4 5 6| + * 3 7 + **/ + + std::vector tk_v{ + /* [ 0] */ Token::quote_token(), + /* [ 1] */ Token::leftbrace_token(), + /* [ 2] */ Token::leftparen_token(), + /* [ 3] */ Token::f64_token("4.5"), + /* [ 4] */ Token::f64_token("7.2"), + /* [ 5] */ Token::rightparen_token(), + /* [ 6] */ Token::rightbrace_token(), + /* [ 7] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); + } + } /*namespace ut*/ } /*namespace xo*/ From 680416d077b541a7dda903d3778bc19cd65b6e1d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Mar 2026 12:12:09 +1100 Subject: [PATCH 264/342] xo-interpreter2 stack: + literal array parsing --- CMakeLists.txt | 20 ++ idl/IPrintable_DExpectQArraySsm.json5 | 16 ++ ...ISyntaxStateMachine_DExpectQArraySsm.json5 | 16 ++ include/xo/reader2/DExpectQArraySsm.hpp | 138 +++++++++++ include/xo/reader2/DExpectQListSsm.hpp | 17 +- include/xo/reader2/DExpectQLiteralSsm.hpp | 46 +++- include/xo/reader2/ExpectQArraySsm.hpp | 12 + .../ssm/IPrintable_DExpectQArraySsm.hpp | 62 +++++ .../ISyntaxStateMachine_DExpectQArraySsm.hpp | 82 +++++++ include/xo/reader2/syntaxstatetype.hpp | 7 +- src/reader2/CMakeLists.txt | 4 + src/reader2/DExpectQArraySsm.cpp | 222 ++++++++++++++++++ src/reader2/DExpectQLiteralSsm.cpp | 77 +++--- src/reader2/IPrintable_DExpectQArraySsm.cpp | 28 +++ .../ISyntaxStateMachine_DExpectQArraySsm.cpp | 79 +++++++ src/reader2/reader2_register_facets.cpp | 5 + src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 40 +++- 18 files changed, 817 insertions(+), 56 deletions(-) create mode 100644 idl/IPrintable_DExpectQArraySsm.json5 create mode 100644 idl/ISyntaxStateMachine_DExpectQArraySsm.json5 create mode 100644 include/xo/reader2/DExpectQArraySsm.hpp create mode 100644 include/xo/reader2/ExpectQArraySsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DExpectQArraySsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp create mode 100644 src/reader2/DExpectQArraySsm.cpp create mode 100644 src/reader2/IPrintable_DExpectQArraySsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b7b5a5f7..54441a8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -353,6 +353,26 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqarrayssm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ExpectQArraySsm + INPUT idl/ISyntaxStateMachine_DExpectQArraySsm.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expectqarrayssm + FACET_PKG xo_printable2 + FACET Printable + REPR ExpectQArraySsm + INPUT idl/IPrintable_DExpectQArraySsm.json5 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-reader2-genfacet-all) # ---------------------------------------------------------------- diff --git a/idl/IPrintable_DExpectQArraySsm.json5 b/idl/IPrintable_DExpectQArraySsm.json5 new file mode 100644 index 00000000..9ba8c712 --- /dev/null +++ b/idl/IPrintable_DExpectQArraySsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectQArraySsm", + using_doxygen: true, + repr: "DExpectQArraySsm", + doc: [ "implement APrintable for DExpectQArraySsm" ], +} diff --git a/idl/ISyntaxStateMachine_DExpectQArraySsm.json5 b/idl/ISyntaxStateMachine_DExpectQArraySsm.json5 new file mode 100644 index 00000000..0ace11e7 --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectQArraySsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectQArraySsm", + using_doxygen: true, + repr: "DExpectQArraySsm", + doc: [ "implement ASyntaxStateMachine for DExpectQArraySsm" ], +} diff --git a/include/xo/reader2/DExpectQArraySsm.hpp b/include/xo/reader2/DExpectQArraySsm.hpp new file mode 100644 index 00000000..5316ee34 --- /dev/null +++ b/include/xo/reader2/DExpectQArraySsm.hpp @@ -0,0 +1,138 @@ +/** @file DExpectQArraySsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +#include +//#include +#include + +namespace xo { + namespace scm { + /** + * Already in quoted-literal context + * + * [ quote-expr ... ] + * ^ ^ ^ + * | qarray_1a qarray_2(done) + * qarray_0 + * + * qarray_0 --on_leftbrace_token()--> qarray_1a [push ExpectQLiteralSsm] + * qarray_1a --on_quoted_literal()--> qarray_1a [append literal] + * qarray_1a --on_rightbrace_token()--> qarray_2(done) [report quoted array] + **/ + class QArrayXst { + public: + enum class code { + invalid = -1, + + qarray_0, + qarray_1a, + qarray_2, + + N + }; + + explicit QArrayXst(code x) : code_{x} {} + + /** @return string representation for enum @p x **/ + static const char * _descr(code x); + + code code() const noexcept { return code_; } + + enum code code_; + }; + + inline std::ostream & + operator<< (std::ostream & os, QArrayXst x) { + os << QArrayXst::_descr(x.code_); + return os; + } + + /** @class DExpectQArraySsm + * @brief parser state-machine for a literal array + **/ + class DExpectQArraySsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; + using TypeDescr = xo::reflect::TypeDescr; + using ppindentinfo = xo::print::ppindentinfo; + using size_type = std::uint32_t; + + public: + /** @defgroup scm-expectqarrayssm-ctors constructors **/ + ///@{ + + DExpectQArraySsm(); + + /** create instance, using memory from @parser_mm **/ + static obj make(DArena & parser_mm); + static DExpectQArraySsm * _make(DArena & parser_mm); + + /** start nested syntax for a quoted literal **/ + static void start(ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectformalargarrayssm-methods general methods **/ + ///@{ + + static const char * ssm_classname() { return "DExpectQArraySsm"; } + + /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ + void on_leftbracket_token(const Token & tk, + ParserStateMachine * p_psm); + + void on_rightbracket_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqarrayssm-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** mnemonic for expected input (for this ssm) in current state **/ + std::string_view get_expect_str() const; + + /** update state on incoming token @p tk, + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for nested qliteral @p lit, with overall parser state in @p p_psm. + * Appends @p lit to target array + **/ + void on_quoted_literal(obj lit, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqarrayssm-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + /** @defgroup scm-expectqarrayssm-member-vars **/ + ///@{ + + /** identifies qarray parsing state **/ + QArrayXst state_; + + /** target array **/ + DArray * array_ = nullptr; + + ///@} + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectQArraySsm.hpp */ diff --git a/include/xo/reader2/DExpectQListSsm.hpp b/include/xo/reader2/DExpectQListSsm.hpp index 2b4b70b2..1ccd0bbe 100644 --- a/include/xo/reader2/DExpectQListSsm.hpp +++ b/include/xo/reader2/DExpectQListSsm.hpp @@ -53,7 +53,7 @@ namespace xo { } /** @class DExpectQListSsm - * @brief parser state-machine for a formal parameter list + * @brief parser state-machine for a literal list **/ class DExpectQListSsm : public DSyntaxStateMachine { public: @@ -120,21 +120,6 @@ namespace xo { ///@} - private: - /** @defgroup scm-expectqlistssm-impl-methods **/ - ///@{ - - /** update local state to include parsed formal (param_name, param_type). - * If stack memory needed, get from @p parser_alloc. - * Lifetime until formal arglist completely parsed - **/ - void _accept_formal(obj expr_alloc, - DArena & parser_alloc, - const DUniqueString * param_name, - TypeDescr param_type); - - ///@} - private: /** @defgroup scm-expectqlistssm-member-vars **/ ///@{ diff --git a/include/xo/reader2/DExpectQLiteralSsm.hpp b/include/xo/reader2/DExpectQLiteralSsm.hpp index efb93f6d..b8452961 100644 --- a/include/xo/reader2/DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/DExpectQLiteralSsm.hpp @@ -24,17 +24,21 @@ namespace xo { using size_type = std::uint32_t; public: - explicit DExpectQLiteralSsm(bool cxl_on_rightparen); + explicit DExpectQLiteralSsm(bool cxl_on_rightparen, + bool cxl_on_rightbracket); /** create instance, using memory from @parser_mm **/ static obj make(DArena & parser_mm, - bool cxl_on_rightparen); + bool cxl_on_rightparen, + bool cxl_on_rightbracket); static DExpectQLiteralSsm * _make(DArena & parser_mm, - bool cxl_on_rightparen); + bool cxl_on_rightparen, + bool cxl_on_rightbracket); /** start nested syntax for a quoted literal **/ static void start(ParserStateMachine * p_psm, - bool cxl_on_rightparen = false); + bool cxl_on_rightparen = false, + bool cxl_on_rightbracket = false); /** @defgroup scm-expectformalarglistssm-methods general methods **/ ///@{ @@ -47,18 +51,38 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); - /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ + /** update state on incoming token @p tk, + * with overall parser state in @p p_psm. + * + * Forward in-place to ExpectQListSsm. + **/ void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); - /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ - void on_comma_token(const Token & tk, - ParserStateMachine * p_psm); - - /** update state on incoming rightparen token @p tk, with overall parser state in @p p_psm **/ + /** update state on incoming rightparen token @p tk, + * with overall parser state in @p p_psm + * + * Error unless @ref cxl_on_rightparen_ + **/ void on_rightparen_token(const Token & tk, ParserStateMachine * p_psm); + /** update state on incoming leftbracket token @p tk, + * with overall parser state in @p p_psm. + * + * Forward in-place to ExpectQArraySsm + **/ + void on_leftbracket_token(const Token &tk, + ParserStateMachine * p_psm); + + /** update state on incoming rightbracket token @p tk, + * with overall parser state in @p p_psm. + * + * Error unless @ref cxl_on_rightbracket_ + **/ + void on_rightbracket_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expectformalarglistssm-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -101,6 +125,8 @@ namespace xo { private: /** if true rightparen pops + delegates to parent ssm **/ bool cxl_on_rightparen_ = false; + /** if true rightbracket pops + delegates to parent ssm **/ + bool cxl_on_rightbracket_ = false; }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/ExpectQArraySsm.hpp b/include/xo/reader2/ExpectQArraySsm.hpp new file mode 100644 index 00000000..78dcf1cb --- /dev/null +++ b/include/xo/reader2/ExpectQArraySsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectQArraySsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DExpectQArraySsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp" +#include "ssm/IPrintable_DExpectQArraySsm.hpp" + +/* end ExpectQArraySsm.hpp */ diff --git a/include/xo/reader2/ssm/IPrintable_DExpectQArraySsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectQArraySsm.hpp new file mode 100644 index 00000000..8c9b2c4a --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DExpectQArraySsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectQArraySsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQArraySsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQArraySsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectQArraySsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectQArraySsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectQArraySsm + **/ + class IPrintable_DExpectQArraySsm { + public: + /** @defgroup scm-printable-dexpectqarrayssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpectqarrayssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectQArraySsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp new file mode 100644 index 00000000..78018537 --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp @@ -0,0 +1,82 @@ +/** @file ISyntaxStateMachine_DExpectQArraySsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQArraySsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQArraySsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectQArraySsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectQArraySsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectQArraySsm + **/ + class ISyntaxStateMachine_DExpectQArraySsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpectqarrayssm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexpectqarrayssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectQArraySsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectQArraySsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectQArraySsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectQArraySsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectQArraySsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectQArraySsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DExpectQArraySsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExpectQArraySsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for nested parsed expression @p expr **/ + static void on_parsed_expression(DExpectQArraySsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExpectQArraySsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectQArraySsm & self, obj lit, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 0a0c857c..4d857d53 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -63,10 +63,13 @@ namespace xo { /** expecting a quoted literal. See @ref DExpectQLiteralSsm **/ expect_qliteral, - /** expecint a quoted list. See @ref DExpectQListSsm **/ + /** expecting a quoted list. See @ref DExpectQListSsm **/ expect_qlist, - /** comes lasts, counts number of valid enums **/ + /** expecting a quoted array. See @ref DExpectQArraySsm **/ + expect_qarray, + + /** comes last, counts number of valid enums **/ N }; diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index fa88a4dd..15a7a338 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -73,6 +73,10 @@ set(SELF_SRCS ISyntaxStateMachine_DExpectQListSsm.cpp IPrintable_DExpectQListSsm.cpp + DExpectQArraySsm.cpp + ISyntaxStateMachine_DExpectQArraySsm.cpp + IPrintable_DExpectQArraySsm.cpp + DProgressSsm.cpp ISyntaxStateMachine_DProgressSsm.cpp IPrintable_DProgressSsm.cpp diff --git a/src/reader2/DExpectQArraySsm.cpp b/src/reader2/DExpectQArraySsm.cpp new file mode 100644 index 00000000..b4a9ac29 --- /dev/null +++ b/src/reader2/DExpectQArraySsm.cpp @@ -0,0 +1,222 @@ +/** @file DExpectQArraySsm.cpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#include "ExpectQArraySsm.hpp" +#include "ExpectQLiteralSsm.hpp" +#include +#include +#include + +namespace xo { + using xo::print::APrintable; + using xo::facet::FacetRegistry; + using xo::mm::AGCObject; + + namespace scm { + const char * + QArrayXst::_descr(enum code x) + { + switch (x) { + case code::invalid: break; + case code::qarray_0: return "qarray_0"; + case code::qarray_1a: return "qarray_1a"; + case code::qarray_2: return "qarray_2"; + case code::N: break; + } + + return "?QArrayXst"; + } + + DExpectQArraySsm::DExpectQArraySsm() : state_{QArrayXst::code::qarray_0} {} + + obj + DExpectQArraySsm::make(DArena & parser_mm) + { + return obj(_make(parser_mm)); + } + + DExpectQArraySsm * + DExpectQArraySsm::_make(DArena & parser_mm) + { + void * mem = parser_mm.alloc_for(); + + return new (mem) DExpectQArraySsm(); + } + + void + DExpectQArraySsm::start(ParserStateMachine * p_psm) + { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DExpectQArraySsm::make(p_psm->parser_alloc())); + } + + syntaxstatetype + DExpectQArraySsm::ssm_type() const noexcept { + return syntaxstatetype::expect_qarray; + } + + std::string_view + DExpectQArraySsm::get_expect_str() const { + switch (state_.code()) { + case QArrayXst::code::qarray_0: + return "leftparen"; + case QArrayXst::code::qarray_1a: + return "qliteral|rightparen"; + case QArrayXst::code::qarray_2: + return "(done)"; + case QArrayXst::code::invalid: + case QArrayXst::code::N: + break; + } + + return "?DExpectQArraySsm"; + } + + void + DExpectQArraySsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch(tk.tk_type()) + { + case tokentype::tk_leftbracket: + this->on_leftbracket_token(tk, p_psm); + return; + + case tokentype::tk_rightbracket: + this->on_rightbracket_token(tk, p_psm); + return; + + case tokentype::tk_comma: + case tokentype::tk_lambda: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_symbol: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_quote: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + } + + void + DExpectQArraySsm::on_leftbracket_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QArrayXst::code::qarray_0) { + this->state_ = QArrayXst(QArrayXst::code::qarray_1a); + + this->array_ = DArray::empty(p_psm->expr_alloc(), + 8 /*heuristic starting capacity*/); + + DExpectQLiteralSsm::start(p_psm, + false /*cxl_on_rightparen*/, + true /*cxl_on_rightbracket*/); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQArraySsm::on_rightbracket_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QArrayXst::code::qarray_1a) { + this->state_ = QArrayXst(QArrayXst::code::qarray_2); + + array_->shrink_to_fit(); + + obj lit = obj(array_); + + p_psm->pop_ssm(); + p_psm->on_quoted_literal(lit); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQArraySsm::on_quoted_literal(obj lit, + ParserStateMachine * p_psm) + { + if(state_.code() == QArrayXst::code::qarray_1a) { + // append lit at the end of array_ + { + assert(array_); + + // ensure sufficient capacity + if (array_->size() == array_->capacity()) { + assert(array_->capacity() > 0); + + /* reallocate w/ 2x capacity */ + this->array_ = DArray::copy(p_psm->expr_alloc(), + array_, + 2 * array_->capacity()); + } + + bool ok = array_->push_back(lit); + + assert(ok); + } + + // start syntax to receive next literal + DExpectQLiteralSsm::start(p_psm, + false /*cxl_on_rightparen*/, + true /*cxl_on_rightbracket*/); + return; + } + + Super::illegal_quoted_literal(lit, p_psm); + } + + bool + DExpectQArraySsm::pretty(const ppindentinfo & ppii) const + { + obj array(array_); + auto array_pr = FacetRegistry::instance().variant(array); + + return ppii.pps()->pretty_struct(ppii, + "DExpectQArraySsm", + refrtag("state", state_), + refrtag("expect", this->get_expect_str()), + refrtag("array", array_pr)); + } + } +} + +/* end DExpectQArraySsm.cpp */ diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index efc92a48..e03e7a39 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -5,6 +5,7 @@ #include "ExpectQLiteralSsm.hpp" #include "ExpectQListSsm.hpp" +#include "ExpectQArraySsm.hpp" #include //#include "DExpectFormalArgSsm.hpp" //#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" @@ -25,13 +26,16 @@ namespace xo { // using xo::reflect::typeseq; namespace scm { - DExpectQLiteralSsm::DExpectQLiteralSsm(bool cxl_on_rightparen) - : cxl_on_rightparen_{cxl_on_rightparen} + DExpectQLiteralSsm::DExpectQLiteralSsm(bool cxl_on_rightparen, + bool cxl_on_rightbracket) + : cxl_on_rightparen_{cxl_on_rightparen}, + cxl_on_rightbracket_{cxl_on_rightbracket} {} DExpectQLiteralSsm * DExpectQLiteralSsm::_make(DArena & arena, - bool cxl_on_rightparen) + bool cxl_on_rightparen, + bool cxl_on_rightbracket) { /* out-of-order so argl follows ssm in arena, * consistent with any subsequent arglist realloc. @@ -40,26 +44,30 @@ namespace xo { void * mem = arena.alloc_for(); - return new (mem) DExpectQLiteralSsm(cxl_on_rightparen); + return new (mem) DExpectQLiteralSsm(cxl_on_rightparen, cxl_on_rightbracket); } obj DExpectQLiteralSsm::make(DArena & arena, - bool cxl_on_rightparen) + bool cxl_on_rightparen, + bool cxl_on_rightbracket) { obj retval(_make(arena, - cxl_on_rightparen)); + cxl_on_rightparen, + cxl_on_rightbracket)); return retval; } void DExpectQLiteralSsm::start(ParserStateMachine * p_psm, - bool cxl_on_rightparen) + bool cxl_on_rightparen, + bool cxl_on_rightbracket) { DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); p_psm->push_ssm(ckp, DExpectQLiteralSsm::make(p_psm->parser_alloc(), - cxl_on_rightparen)); + cxl_on_rightparen, + cxl_on_rightbracket)); } syntaxstatetype @@ -78,6 +86,7 @@ namespace xo { ParserStateMachine * p_psm) { switch (tk.tk_type()) { + case tokentype::tk_f64: this->on_f64_token(tk, p_psm); return; @@ -90,6 +99,14 @@ namespace xo { this->on_rightparen_token(tk, p_psm); return; + case tokentype::tk_leftbracket: + this->on_leftbracket_token(tk, p_psm); + return; + + case tokentype::tk_rightbracket: + this->on_rightbracket_token(tk, p_psm); + return; + case tokentype::tk_comma: case tokentype::tk_lambda: case tokentype::tk_def: @@ -103,8 +120,6 @@ namespace xo { case tokentype::tk_semicolon: case tokentype::tk_invalid: case tokentype::tk_quote: - case tokentype::tk_leftbracket: - case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: case tokentype::tk_rightbrace: case tokentype::tk_leftangle: @@ -200,22 +215,6 @@ namespace xo { p_psm->on_token(tk); } -#ifdef NOT_YET - void - DExpectQLiteralSsm::on_comma_token(const Token & tk, - ParserStateMachine * p_psm) - { - if (fastate_ == formalarglstatetype::argl_1b) { - this->fastate_ = formalarglstatetype::argl_1a; - - DExpectFormalArgSsm::start(p_psm); - return; - } - - Super::on_token(tk, p_psm); - } -#endif - void DExpectQLiteralSsm::on_rightparen_token(const Token & tk, ParserStateMachine * p_psm) @@ -226,7 +225,31 @@ namespace xo { return; } - Super::on_token(tk, p_psm); + Super::illegal_token(tk, p_psm); + } + + void + DExpectQLiteralSsm::on_leftbracket_token(const Token & tk, + ParserStateMachine * p_psm) + { + // replace self with specialized version for parsing a literal array + + p_psm->pop_ssm(); + DExpectQArraySsm::start(p_psm); + p_psm->on_token(tk); + } + + void + DExpectQLiteralSsm::on_rightbracket_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (cxl_on_rightbracket_) { + p_psm->pop_ssm(); + p_psm->on_token(tk); + return; + } + + Super::illegal_token(tk, p_psm); } bool diff --git a/src/reader2/IPrintable_DExpectQArraySsm.cpp b/src/reader2/IPrintable_DExpectQArraySsm.cpp new file mode 100644 index 00000000..b3f875d9 --- /dev/null +++ b/src/reader2/IPrintable_DExpectQArraySsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectQArraySsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQArraySsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQArraySsm.json5] +**/ + +#include "ssm/IPrintable_DExpectQArraySsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectQArraySsm::pretty(const DExpectQArraySsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectQArraySsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp new file mode 100644 index 00000000..32d8bfd1 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp @@ -0,0 +1,79 @@ +/** @file ISyntaxStateMachine_DExpectQArraySsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQArraySsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQArraySsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectQArraySsm::ssm_type(const DExpectQArraySsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectQArraySsm::get_expect_str(const DExpectQArraySsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectQArraySsm::on_token(DExpectQArraySsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQArraySsm::on_parsed_symbol(DExpectQArraySsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExpectQArraySsm::on_parsed_typedescr(DExpectQArraySsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DExpectQArraySsm::on_parsed_formal(DExpectQArraySsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DExpectQArraySsm::on_parsed_formal_with_token(DExpectQArraySsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQArraySsm::on_parsed_formal_arglist(DExpectQArraySsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DExpectQArraySsm::on_parsed_expression(DExpectQArraySsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DExpectQArraySsm::on_parsed_expression_with_token(DExpectQArraySsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQArraySsm::on_quoted_literal(DExpectQArraySsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectQArraySsm.cpp */ diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 1df5cb82..909c1bc2 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -23,6 +23,7 @@ #include "ExpectExprSsm.hpp" #include "ExpectQLiteralSsm.hpp" #include "ExpectQListSsm.hpp" +#include "ExpectQArraySsm.hpp" #include #include @@ -87,6 +88,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + // misc types showing up in aux arena TypeRegistry::register_type(); // misc types showing up in parser stack arena @@ -103,6 +107,7 @@ namespace xo { log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); log && log(xtag("DExpectQLiteralSsm.tseq", typeseq::id())); log && log(xtag("DExpectQListSsm.tseq", typeseq::id())); + log && log(xtag("DExpectQArraySsm.tseq", typeseq::id())); log && log(xtag("DProgressSsm.tseq", typeseq::id())); log && log(xtag("DParenSsm.tseq", typeseq::id())); diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index f1d93239..9b6c0928 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -45,6 +45,8 @@ namespace xo { return "expect-qliteral"; case syntaxstatetype::expect_qlist: return "expect-qlist"; + case syntaxstatetype::expect_qarray: + return "expect-qarray"; case syntaxstatetype::N: break; } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 17022d42..0404a800 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1287,7 +1287,7 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -1319,6 +1319,44 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-batch-qarray", "[reader2][SchematikaParser]") + { + // top-level recursive function definition + + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * #q{ [4.5 7.2] }; + * ^ ^ ^^ ^ ^ ^^ + * 0 1 2| 4 5 6| + * 3 7 + **/ + + std::vector tk_v{ + /* [ 0] */ Token::quote_token(), + /* [ 1] */ Token::leftbrace_token(), + /* [ 2] */ Token::leftbracket_token(), + /* [ 3] */ Token::f64_token("4.5"), + /* [ 4] */ Token::f64_token("7.2"), + /* [ 5] */ Token::rightbracket_token(), + /* [ 6] */ Token::rightbrace_token(), + /* [ 7] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); + } + } /*namespace ut*/ } /*namespace xo*/ From 74642dfcfafc540e99a1b92a710f802025ebd91d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Mar 2026 12:12:09 +1100 Subject: [PATCH 265/342] xo-interpreter2 stack: + literal array parsing --- include/xo/tokenizer2/Token.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index 9c748933..5f8be733 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -98,9 +98,9 @@ namespace xo { /** Token representing right parenthesis @c ")" **/ static Token rightparen_token() { return Token(tokentype::tk_rightparen); } /** token representing left bracket @c "[" **/ - static Token leftbracket() { return Token(tokentype::tk_leftbracket); } + static Token leftbracket_token() { return Token(tokentype::tk_leftbracket); } /** token representing right bracket @c "]" **/ - static Token rightbracket() { return Token(tokentype::tk_rightbracket); } + static Token rightbracket_token() { return Token(tokentype::tk_rightbracket); } /** token representing left brace @c "{" **/ static Token leftbrace_token() { return Token(tokentype::tk_leftbrace); } /** token representing right brace @c "}" **/ From b544a399936e6256ec6fc3278ace652f9781191b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 4 Mar 2026 22:26:31 +1100 Subject: [PATCH 266/342] xo-gc xo-alloc2: move Collector faceet gc/ -> alloc2/ for levelling --- include/xo/reader2/reader2_register_types.hpp | 2 +- src/reader2/DExpectExprSsm.cpp | 2 +- src/reader2/DToplevelSeqSsm.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xo/reader2/reader2_register_types.hpp b/include/xo/reader2/reader2_register_types.hpp index a7e6c0e1..1d8fea34 100644 --- a/include/xo/reader2/reader2_register_types.hpp +++ b/include/xo/reader2/reader2_register_types.hpp @@ -5,7 +5,7 @@ #pragma once -#include +#include namespace xo { namespace scm { diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 57cf3836..aef5c7a4 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #ifdef NOT_YET diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index 0473660f..493c745e 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include namespace xo { using xo::scm::DProgressSsm; From b96cf33a2123d7f5dd483e12cec049fdc4ceb546 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 5 Mar 2026 00:50:58 +1100 Subject: [PATCH 267/342] refactor: + xo-stringtable2 w/ DString impl --- include/xo/reader2/ParserResult.hpp | 2 +- src/reader2/DExpectExprSsm.cpp | 4 +--- src/reader2/DToplevelSeqSsm.cpp | 16 ++++++++-------- src/reader2/init_reader2.cpp | 2 +- utest/SchematikaParser.test.cpp | 10 +++++----- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/include/xo/reader2/ParserResult.hpp b/include/xo/reader2/ParserResult.hpp index 492b78b0..9cdf1424 100644 --- a/include/xo/reader2/ParserResult.hpp +++ b/include/xo/reader2/ParserResult.hpp @@ -6,7 +6,7 @@ #pragma once #include -#include +#include #include #include diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index aef5c7a4..40ed2476 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -18,15 +18,13 @@ #include #include #include -#include +#include #include #include #ifdef NOT_YET #include "define_xs.hpp" #include "paren_xs.hpp" -#include "sequence_xs.hpp" -#include "progress_xs.hpp" #endif namespace xo { diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index 493c745e..d7444e43 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -17,17 +17,17 @@ #include //#include -#include -#include +#include +//#include -#include -#include +#include +//#include -#include -#include +#include +//#include -#include -#include +#include +//#include #include diff --git a/src/reader2/init_reader2.cpp b/src/reader2/init_reader2.cpp index a6e1a7b0..df0de7c0 100644 --- a/src/reader2/init_reader2.cpp +++ b/src/reader2/init_reader2.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include namespace xo { using xo::scm::reader2_register_facets; diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 0404a800..c299306f 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -25,10 +25,10 @@ namespace xo { using xo::scm::ParserConfig; using xo::scm::SchematikaParser; - using xo::scm::ASyntaxStateMachine; - using xo::scm::syntaxstatetype; +// using xo::scm::ASyntaxStateMachine; +// using xo::scm::syntaxstatetype; // using xo::scm::DDefineSsm; - using xo::scm::DExpectExprSsm; +// using xo::scm::DExpectExprSsm; using xo::scm::AExpression; using xo::scm::DDefineExpr; @@ -51,7 +51,7 @@ namespace xo { using xo::mm::AAllocator; using xo::mm::DArena; using xo::mm::MemorySizeInfo; - using xo::facet::with_facet; +// using xo::facet::with_facet; static InitEvidence s_init = (InitSubsys::require()); From a0fdfa2d90a81f1342db4041688c06908c3fff71 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 5 Mar 2026 13:02:12 +1100 Subject: [PATCH 268/342] xo-interpreter2 stack: refactor: string clases -> xo-stringtable2/ --- include/xo/reader2/ParserStateMachine.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 0c01e452..a247688a 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -10,9 +10,9 @@ #include #include #include -#include #include #include +#include #include #include #include From 07b7a7c9788fc6e8364256c85c777e707d8f6617 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 7 Mar 2026 11:43:47 +1100 Subject: [PATCH 269/342] xo-reader2: scaffold for using obj for types [WIP] --- cmake/xo_reader2Config.cmake.in | 1 + idl/SyntaxStateMachine.json5 | 10 ++++++++ include/xo/reader2/DSyntaxStateMachine.hpp | 19 +++++++++++++++ include/xo/reader2/ParserStateMachine.hpp | 9 ++++++++ .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 3 +++ .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 1 + .../ssm/ISyntaxStateMachine_DApplySsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectExprSsm.hpp | 2 ++ ...SyntaxStateMachine_DExpectFormalArgSsm.hpp | 2 ++ ...axStateMachine_DExpectFormalArglistSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectQArraySsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectQListSsm.hpp | 2 ++ ...ISyntaxStateMachine_DExpectQLiteralSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 2 ++ .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DIfElseSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DLambdaSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DParenSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DQuoteSsm.hpp | 2 ++ .../ssm/ISyntaxStateMachine_DSequenceSsm.hpp | 2 ++ .../ISyntaxStateMachine_DToplevelSeqSsm.hpp | 2 ++ .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 4 ++++ .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 3 +++ src/reader2/CMakeLists.txt | 1 + src/reader2/ISyntaxStateMachine_Any.cpp | 6 +++++ src/reader2/ISyntaxStateMachine_DApplySsm.cpp | 5 ++++ .../ISyntaxStateMachine_DDefineSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectExprSsm.cpp | 5 ++++ ...SyntaxStateMachine_DExpectFormalArgSsm.cpp | 5 ++++ ...axStateMachine_DExpectFormalArglistSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectQArraySsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectQListSsm.cpp | 5 ++++ ...ISyntaxStateMachine_DExpectQLiteralSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DIfElseSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DLambdaSsm.cpp | 5 ++++ src/reader2/ISyntaxStateMachine_DParenSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DProgressSsm.cpp | 5 ++++ src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DSequenceSsm.cpp | 5 ++++ .../ISyntaxStateMachine_DToplevelSeqSsm.cpp | 5 ++++ src/reader2/ParserStateMachine.cpp | 23 +++++++++++++++++++ 45 files changed, 199 insertions(+) diff --git a/cmake/xo_reader2Config.cmake.in b/cmake/xo_reader2Config.cmake.in index 14dec967..6d032cb1 100644 --- a/cmake/xo_reader2Config.cmake.in +++ b/cmake/xo_reader2Config.cmake.in @@ -9,6 +9,7 @@ include(CMakeFindDependencyMacro) find_dependency(xo_numeric) find_dependency(xo_procedure2) find_dependency(xo_gc) +find_dependency(xo_type) find_dependency(xo_tokenizer2) find_dependency(xo_expression2) find_dependency(subsys) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 815fd18e..0238749c 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -7,6 +7,7 @@ includes: [ "\"ParserStateMachine.hpp\"", "\"syntaxstatetype.hpp\"", + "", "", "", ], @@ -76,6 +77,15 @@ {type: "ParserStateMachine *", name: "p_psm"}, ], }, + { + name: "on_parsed_type", + doc: ["update state machine for type emitted by nested ssm"], + return_type: "void", + args: [ + {type: "obj", name: "type"}, + {type: "ParserStateMachine *", name: "p_psm"}, + ], + }, { name: "on_parsed_formal", doc: ["operate state machine for formal emitted by nested ssm"], diff --git a/include/xo/reader2/DSyntaxStateMachine.hpp b/include/xo/reader2/DSyntaxStateMachine.hpp index adce34e1..10aeccfa 100644 --- a/include/xo/reader2/DSyntaxStateMachine.hpp +++ b/include/xo/reader2/DSyntaxStateMachine.hpp @@ -44,6 +44,17 @@ namespace xo { self.get_expect_str()); } + /** Explicit error path **/ + void illegal_type(obj type, + ParserStateMachine * p_psm) + { + Derived & self = static_cast(*this); + + p_psm->illegal_input_on_type(Derived::ssm_classname(), + type, + self.get_expect_str()); + } + /** Explicit error path **/ void illegal_quoted_literal(obj lit, ParserStateMachine * p_psm) @@ -88,6 +99,14 @@ namespace xo { self.get_expect_str()); } + /** Default implementation for require SyntaxStateMachine facet method + **/ + void on_parsed_type(obj type, + ParserStateMachine * p_psm) + { + this->illegal_type(type, p_psm); + } + /** Default implementation for required SyntaxStateMachine facet method **/ void on_parsed_formal(const DUniqueString * param_name, diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index a247688a..2553acbf 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -234,6 +235,14 @@ namespace xo { TypeDescr td, std::string_view expect_str); + /** report illegal input arriving in syntax state machine (ssm) @p ssm_name + * when receiving type definition @p ty. + * @p expect_str sketches expected input in current ssm state + **/ + void illegal_input_on_type(std::string_view ssm_name, + obj ty, + std::string_view expect_str); + /** report illegal parsed formal (param_name, param_type) from nested ssm. * Introducing as placeholder; not expected to be reachable in * full parser diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index b7fa0a92..a010421d 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -16,6 +16,7 @@ // includes (via {facet_includes}) #include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" +#include #include #include #include @@ -67,6 +68,8 @@ public: virtual void on_parsed_symbol(Opaque data, std::string_view sym, ParserStateMachine * p_psm) = 0; /** operate state machine for incoming type description @p td **/ virtual void on_parsed_typedescr(Opaque data, TypeDescr td, ParserStateMachine * p_psm) = 0; + /** update state machine for type emitted by nested ssm **/ + virtual void on_parsed_type(Opaque data, obj type, ParserStateMachine * p_psm) = 0; /** operate state machine for formal emitted by nested ssm **/ virtual void on_parsed_formal(Opaque data, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) = 0; /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 81d00656..2f00d0a4 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -67,6 +67,7 @@ namespace scm { [[noreturn]] void on_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_symbol(Opaque, std::string_view, ParserStateMachine *) override; [[noreturn]] void on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachine *) override; + [[noreturn]] void on_parsed_type(Opaque, obj, ParserStateMachine *) override; [[noreturn]] void on_parsed_formal(Opaque, const DUniqueString *, TypeDescr, ParserStateMachine *) override; [[noreturn]] void on_parsed_formal_with_token(Opaque, const DUniqueString *, TypeDescr, const Token &, ParserStateMachine *) override; [[noreturn]] void on_parsed_formal_arglist(Opaque, DArray *, ParserStateMachine *) override; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp index 75863bfc..0b0f6972 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DApplySsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DApplySsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DApplySsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DApplySsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index 0191de54..d8b28de8 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DDefineSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index a84ed1b1..1cde9c14 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DExpectExprSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectExprSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DExpectExprSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectExprSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp index 4e924170..2c6da502 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DExpectFormalArgSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectFormalArgSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DExpectFormalArgSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectFormalArgSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp index d1e388b2..78e7db56 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DExpectFormalArglistSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectFormalArglistSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DExpectFormalArglistSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectFormalArglistSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp index 78018537..c77c635d 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DExpectQArraySsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectQArraySsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DExpectQArraySsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectQArraySsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp index 6cd1a38b..14ff3627 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DExpectQListSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectQListSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DExpectQListSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectQListSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp index 303d137e..b19181a8 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DExpectQLiteralSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectQLiteralSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DExpectQLiteralSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectQLiteralSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index f39e2af3..431cba69 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DExpectSymbolSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectSymbolSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DExpectSymbolSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectSymbolSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index ba997e28..f43f83c7 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DExpectTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DExpectTypeSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DExpectTypeSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DExpectTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp index b189bf87..6b9dd33f 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DIfElseSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DIfElseSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DIfElseSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DIfElseSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp index 9c97287f..8ba94c58 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DLambdaSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DLambdaSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DLambdaSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DLambdaSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp index 65cd1727..ef74a525 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DParenSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DParenSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DParenSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DParenSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 431892b9..c5e91891 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DProgressSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DProgressSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DProgressSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DProgressSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp index e5548af5..7f776ca0 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DQuoteSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DQuoteSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DQuoteSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DQuoteSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp index 448b296b..361922ef 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DSequenceSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DSequenceSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DSequenceSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DSequenceSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp index 9aa70c43..fbb45bef 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp @@ -61,6 +61,8 @@ namespace xo { static void on_parsed_symbol(DToplevelSeqSsm & self, std::string_view sym, ParserStateMachine * p_psm); /** operate state machine for incoming type description @p td **/ static void on_parsed_typedescr(DToplevelSeqSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DToplevelSeqSsm & self, obj type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ static void on_parsed_formal(DToplevelSeqSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); /** operate state machine for formal emitted by nested ssm **/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 4a77f0c4..67b187cf 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -15,6 +15,7 @@ #include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" +#include #include #include @@ -65,6 +66,9 @@ namespace scm { void on_parsed_typedescr(Opaque data, TypeDescr td, ParserStateMachine * p_psm) override { return I::on_parsed_typedescr(_dcast(data), td, p_psm); } + void on_parsed_type(Opaque data, obj type, ParserStateMachine * p_psm) override { + return I::on_parsed_type(_dcast(data), type, p_psm); + } void on_parsed_formal(Opaque data, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) override { return I::on_parsed_formal(_dcast(data), param_name, param_type, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 33321d14..4ac4c791 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -71,6 +71,9 @@ public: void on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm) { return O::iface()->on_parsed_typedescr(O::data(), td, p_psm); } + void on_parsed_type(obj type, ParserStateMachine * p_psm) { + return O::iface()->on_parsed_type(O::data(), type, p_psm); + } void on_parsed_formal(const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) { return O::iface()->on_parsed_formal(O::data(), param_name, param_type, p_psm); } diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 15a7a338..8633f75a 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -92,6 +92,7 @@ xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 $ xo_dependency(${SELF_LIB} xo_numeric) xo_dependency(${SELF_LIB} xo_procedure2) xo_dependency(${SELF_LIB} xo_gc) +xo_dependency(${SELF_LIB} xo_type) xo_dependency(${SELF_LIB} xo_tokenizer2) xo_dependency(${SELF_LIB} xo_expression2) #xo_dependency(${SELF_LIB} reflect) diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index ccf69ca8..7d401163 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -53,6 +53,12 @@ ISyntaxStateMachine_Any::on_parsed_typedescr(Opaque, TypeDescr, ParserStateMachi _fatal(); } +auto +ISyntaxStateMachine_Any::on_parsed_type(Opaque, obj, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_parsed_formal(Opaque, const DUniqueString *, TypeDescr, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DApplySsm.cpp b/src/reader2/ISyntaxStateMachine_DApplySsm.cpp index f5cbb4e2..cd1a550d 100644 --- a/src/reader2/ISyntaxStateMachine_DApplySsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DApplySsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DApplySsm::on_parsed_type(DApplySsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DApplySsm::on_parsed_formal(DApplySsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index be766921..e038fac3 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DDefineSsm::on_parsed_type(DDefineSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DDefineSsm::on_parsed_formal(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index d505b427..911ec4d5 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectExprSsm::on_parsed_type(DExpectExprSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DExpectExprSsm::on_parsed_formal(DExpectExprSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp index 50131470..1089d5ee 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_type(DExpectFormalArgSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DExpectFormalArgSsm::on_parsed_formal(DExpectFormalArgSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp index 982ce47a..b92e9655 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_type(DExpectFormalArglistSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DExpectFormalArglistSsm::on_parsed_formal(DExpectFormalArglistSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp index 32d8bfd1..e205409f 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectQArraySsm::on_parsed_type(DExpectQArraySsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DExpectQArraySsm::on_parsed_formal(DExpectQArraySsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp index 2d24b697..0f64936e 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_type(DExpectQListSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DExpectQListSsm::on_parsed_formal(DExpectQListSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp index 977b1194..bde94b6b 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectQLiteralSsm::on_parsed_type(DExpectQLiteralSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DExpectQLiteralSsm::on_parsed_formal(DExpectQLiteralSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index 3701069f..ebeaafe7 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_type(DExpectSymbolSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DExpectSymbolSsm::on_parsed_formal(DExpectSymbolSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index e83c591a..267810e2 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DExpectTypeSsm::on_parsed_type(DExpectTypeSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DExpectTypeSsm::on_parsed_formal(DExpectTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp index fc28d9c9..fef959ca 100644 --- a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DIfElseSsm::on_parsed_type(DIfElseSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DIfElseSsm::on_parsed_formal(DIfElseSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp index 2ce18e6b..e131c12d 100644 --- a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DLambdaSsm::on_parsed_type(DLambdaSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DLambdaSsm::on_parsed_formal(DLambdaSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp index dcd49028..05f5d4cc 100644 --- a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DParenSsm::on_parsed_type(DParenSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DParenSsm::on_parsed_formal(DParenSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index c9d1931c..f1c0e2cf 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DProgressSsm::on_parsed_type(DProgressSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DProgressSsm::on_parsed_formal(DProgressSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp b/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp index 9281d6f5..233819be 100644 --- a/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DQuoteSsm::on_parsed_type(DQuoteSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DQuoteSsm::on_parsed_formal(DQuoteSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp index 5aa181bb..714a04f8 100644 --- a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DSequenceSsm::on_parsed_type(DSequenceSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DSequenceSsm::on_parsed_formal(DSequenceSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp index 698ccefc..e78c78c7 100644 --- a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp @@ -43,6 +43,11 @@ namespace xo { self.on_parsed_typedescr(td, p_psm); } auto + ISyntaxStateMachine_DToplevelSeqSsm::on_parsed_type(DToplevelSeqSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto ISyntaxStateMachine_DToplevelSeqSsm::on_parsed_formal(DToplevelSeqSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void { self.on_parsed_formal(param_name, param_type, p_psm); diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 125ca1dd..3c640332 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -439,6 +439,29 @@ namespace xo { this->capture_error(ssm_name, errmsg); } + void + ParserStateMachine::illegal_input_on_type(std::string_view ssm_name, + obj type, + std::string_view expect_str) + { + // TODO: + // - want to write error message using DArena + // - need something like log_streambuf and/or tostr() that's arena-aware + + auto errmsg_string = tostr("Unexpected type for parsing state", + xtag("type", type), + xtag("expecting", expect_str), + xtag("ssm", ssm_name), + xtag("via", "ParserStateMachine::illegal_input_on_type")); + + assert(expr_alloc_); + + auto errmsg = DString::from_view(expr_alloc_, + std::string_view(errmsg_string)); + + this->capture_error(ssm_name, errmsg); + } + void ParserStateMachine::illegal_parsed_formal(std::string_view ssm_name, const DUniqueString * param_name, From 76af3ff3b5b2c0e64dc0bb4cadf1425e036fdfc0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 07:49:14 -0500 Subject: [PATCH 270/342] xo-reader2 stack: expand symbol table to store typedefs + typedef utest + misc qol policy choices --- CMakeLists.txt | 20 ++ idl/IPrintable_DDeftypeSsm.json5 | 16 + idl/ISyntaxStateMachine_DDeftypeSsm.json5 | 16 + include/xo/reader2/DDeftypeSsm.hpp | 186 ++++++++++++ include/xo/reader2/DExpectTypeSsm.hpp | 14 +- include/xo/reader2/DQuoteSsm.hpp | 1 - include/xo/reader2/DSyntaxStateMachine.hpp | 20 +- include/xo/reader2/DToplevelSeqSsm.hpp | 5 + include/xo/reader2/DeftypeSsm.hpp | 12 + include/xo/reader2/ParserConfig.hpp | 24 +- include/xo/reader2/ParserStateMachine.hpp | 10 +- include/xo/reader2/ReaderConfig.hpp | 24 +- .../xo/reader2/ssm/IPrintable_DDeftypeSsm.hpp | 62 ++++ .../ssm/ISyntaxStateMachine_DDeftypeSsm.hpp | 84 ++++++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 4 + src/reader2/DApplySsm.cpp | 1 + src/reader2/DDefineSsm.cpp | 12 +- src/reader2/DDeftypeSsm.cpp | 275 ++++++++++++++++++ src/reader2/DExpectExprSsm.cpp | 1 + src/reader2/DExpectFormalArgSsm.cpp | 3 +- src/reader2/DExpectFormalArglistSsm.cpp | 1 + src/reader2/DExpectQArraySsm.cpp | 1 + src/reader2/DExpectQListSsm.cpp | 1 + src/reader2/DExpectQLiteralSsm.cpp | 1 + src/reader2/DExpectSymbolSsm.cpp | 1 + src/reader2/DExpectTypeSsm.cpp | 93 ++++-- src/reader2/DIfElseSsm.cpp | 1 + src/reader2/DLambdaSsm.cpp | 30 +- src/reader2/DParenSsm.cpp | 1 + src/reader2/DProgressSsm.cpp | 1 + src/reader2/DQuoteSsm.cpp | 3 +- src/reader2/DSequenceSsm.cpp | 1 + src/reader2/DToplevelSeqSsm.cpp | 30 +- src/reader2/IPrintable_DDeftypeSsm.cpp | 28 ++ .../ISyntaxStateMachine_DDeftypeSsm.cpp | 84 ++++++ src/reader2/ParserStateMachine.cpp | 17 +- src/reader2/SchematikaParser.cpp | 13 +- src/reader2/SchematikaReader.cpp | 3 +- src/reader2/reader2_register_facets.cpp | 5 + src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 44 ++- 42 files changed, 1047 insertions(+), 107 deletions(-) create mode 100644 idl/IPrintable_DDeftypeSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DDeftypeSsm.json5 create mode 100644 include/xo/reader2/DDeftypeSsm.hpp create mode 100644 include/xo/reader2/DeftypeSsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DDeftypeSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DDeftypeSsm.hpp create mode 100644 src/reader2/DDeftypeSsm.cpp create mode 100644 src/reader2/IPrintable_DDeftypeSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DDeftypeSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 54441a8c..8e0f1e95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,26 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-deftypessm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR DeftypeSsm + INPUT idl/ISyntaxStateMachine_DDeftypeSsm.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-deftypessm + FACET_PKG xo_printable2 + FACET Printable + REPR DeftypeSsm + INPUT idl/IPrintable_DDeftypeSsm.json5 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-lambdassm diff --git a/idl/IPrintable_DDeftypeSsm.json5 b/idl/IPrintable_DDeftypeSsm.json5 new file mode 100644 index 00000000..e61f5881 --- /dev/null +++ b/idl/IPrintable_DDeftypeSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DDeftypeSsm", + using_doxygen: true, + repr: "DDeftypeSsm", + doc: [ "implement APrintable for DDeftypeSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DDeftypeSsm.json5 b/idl/ISyntaxStateMachine_DDeftypeSsm.json5 new file mode 100644 index 00000000..d3e3b174 --- /dev/null +++ b/idl/ISyntaxStateMachine_DDeftypeSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DDeftypeSsm", + using_doxygen: true, + repr: "DDeftypeSsm", + doc: [ "implement ASyntaxStateMachine for DDeftypeSsm" ], +} diff --git a/include/xo/reader2/DDeftypeSsm.hpp b/include/xo/reader2/DDeftypeSsm.hpp new file mode 100644 index 00000000..29a1d691 --- /dev/null +++ b/include/xo/reader2/DDeftypeSsm.hpp @@ -0,0 +1,186 @@ +/** @file DDeftypeSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include +#include + +namespace xo { + namespace scm { + /** + * @pre + * + * deftype foo :: f64 ; + * ^ ^ ^ ^ ^ ^ + * | | | | | (done) + * | | | | def_4 + * | | | def_3 + * | | def_2 + * | def_1 + * def_0 + * + * def_0 --on_deftype_token()--> def_1 [expect symbol] + * def_1 --on_symbol_token()--> def_2 [expect ::] + * def_2 --on_doublecolon_token()--> def_3 [start ExpectTypeSsm] + * def_3 --on_parsed_type()--> def_4 [++ symbol table] + * def_4 --on_semicolon_token()--> (done) [pop] + * + * @endpre + **/ + class DeftypeXst { + public: + enum class code { + invalid = -1, + + def_0, + def_1, + def_2, + def_3, + def_4, + + N, + }; + + explicit DeftypeXst(code x) : code_{x} {} + + /** @return string representation for enum @p x **/ + static const char * _descr(code x); + + code code() const noexcept { return code_; } + + enum code code_; + }; + + std::ostream & + operator<<(std::ostream & os, DeftypeXst x); + + /** @class DDeftypeSsm + * @brief state machine for parsing a deftype expression + **/ + class DDeftypeSsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using TypeDescr = xo::reflect::TypeDescr; + using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; + + public: + /** @defgroup scm-deftypessm-ctors constructors **/ + ///@{ + + /** constructor; using @p def_expr for initial expression scaffold **/ + explicit DDeftypeSsm(); + + /** Create instance using memory from @p parser_mm **/ + static DDeftypeSsm * _make(DArena & parser_mm); + + /** create fop referring to new DDeftypeSsm **/ + static obj make(DArena & parser_mm); + + /** start nested parser for a define-expression, + * on top of parser state machine @p p_psm + * Use @p parser_mm to allocate syntax state machines, + * and @p expr_mm to allocate expressions + **/ + static void start(DArena & parser_mm, + //obj expr_mm, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-definessm-access-methods **/ + ///@{ + + /** identify this nested state machine **/ + static const char * ssm_classname() { return "DDeftypeSsm"; } + + /** internal state **/ + DeftypeXst deftypestate() const noexcept { return deftype_xst_; } + + ///@} + /** @defgroup scm-definessm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** text describing expected/allowed input to this ssm in current state. + * Intended to drive error messages + **/ + std::string_view get_expect_str() const noexcept; + + /** operate state machine for this syntax on incoming token @p tk + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming @c deftype token @p tk, + * overall parser state in @p p_psm + **/ + void on_deftype_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming double-colon token @p tk, + * overall parser state in @p p_psm + **/ + void on_doublecolon_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax after parsing a symbol @p sym; + * overall parser state in @p p_psm + **/ + void on_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm); + + /** update state for this syntax after type @p type emitted by nested + * state machine, with overall parser state in @p p_psm + **/ + void on_parsed_type(obj type, + ParserStateMachine * p_psm); + +#ifdef NOT_YET + /** update state for this syntax after parsing a type-description @p td, + * overall parser state in @p p_psm + **/ + void on_parsed_typedescr(TypeDescr td, + ParserStateMachine * p_psm); +#endif + + /** update state for this syntax after parsing semicolon token @p tk, + * overall parser state in @p p_psm. + * if state def_4 completes deftype statement. + **/ + void on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-define-printable-facet printable facet methods **/ + ///@{ + + /** pretty-printer support **/ + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + /** @defgroup scm-deftypessm-member-vars **/ + ///@{ + + /** identify deftype ssm state **/ + DeftypeXst deftype_xst_; + + /** lhs symbol for type definition **/ + const DUniqueString * lhs_symbol_ = nullptr; + + ///@} + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DDefineSsm.hpp */ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 8d67b448..aba12f8d 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -30,14 +30,14 @@ namespace xo { using ppindentinfo = xo::print::ppindentinfo; public: - DExpectTypeSsm(); + explicit DExpectTypeSsm(bool corrected); - static DExpectTypeSsm * _make(DArena & parser_mm); + static DExpectTypeSsm * _make(DArena & parser_mm, bool corrected); /** create fop referring to new DExpectTypeSsm **/ - static obj make(DArena & parser_mm); + static obj make(DArena & parser_mm, bool corrected); - static void start(ParserStateMachine * p_psm); + static void start(bool corrected, ParserStateMachine * p_psm); static const char * ssm_classname() { return "DExpectTypeSsm"; } @@ -72,6 +72,12 @@ namespace xo { ///@} + private: + /** temporary shim. + * if true, construct obj + * if false, construct TypeDescr + **/ + bool corrected_ = false; }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/DQuoteSsm.hpp b/include/xo/reader2/DQuoteSsm.hpp index 6cbfac79..26079e8e 100644 --- a/include/xo/reader2/DQuoteSsm.hpp +++ b/include/xo/reader2/DQuoteSsm.hpp @@ -32,7 +32,6 @@ namespace xo { * * @endpre **/ - class QuoteXst { public: enum class code { diff --git a/include/xo/reader2/DSyntaxStateMachine.hpp b/include/xo/reader2/DSyntaxStateMachine.hpp index 10aeccfa..66852170 100644 --- a/include/xo/reader2/DSyntaxStateMachine.hpp +++ b/include/xo/reader2/DSyntaxStateMachine.hpp @@ -48,6 +48,7 @@ namespace xo { void illegal_type(obj type, ParserStateMachine * p_psm) { + // starting with c++23 can use "this auto&& self" instead Derived & self = static_cast(*this); p_psm->illegal_input_on_type(Derived::ssm_classname(), @@ -55,6 +56,18 @@ namespace xo { self.get_expect_str()); } + /** Explicit error path **/ + void illegal_parsed_symbol(std::string_view sym, + ParserStateMachine * p_psm) + { + // starting with c++23 can use "this auto&& self" instead + Derived & self = static_cast(*this); + + p_psm->illegal_input_on_symbol(Derived::ssm_classname(), + sym, + self.get_expect_str()); + } + /** Explicit error path **/ void illegal_quoted_literal(obj lit, ParserStateMachine * p_psm) @@ -78,12 +91,7 @@ namespace xo { void on_parsed_symbol(std::string_view sym, ParserStateMachine * p_psm) { - // starting with c++23 can use "this auto&& self" instead - Derived & self = reinterpret_cast(*this); - - p_psm->illegal_input_on_symbol(Derived::ssm_classname(), - sym, - self.get_expect_str()); + this->illegal_parsed_symbol(sym, p_psm); } /** Default implementation for required SyntaxStateMachine facet method diff --git a/include/xo/reader2/DToplevelSeqSsm.hpp b/include/xo/reader2/DToplevelSeqSsm.hpp index d20e751a..9bb9b076 100644 --- a/include/xo/reader2/DToplevelSeqSsm.hpp +++ b/include/xo/reader2/DToplevelSeqSsm.hpp @@ -84,6 +84,11 @@ namespace xo { **/ void on_def_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming @c deftype token @p tk, + * with overall parser state in @p p_psm + **/ + void on_deftype_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming lamdba token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DeftypeSsm.hpp b/include/xo/reader2/DeftypeSsm.hpp new file mode 100644 index 00000000..22ec3eec --- /dev/null +++ b/include/xo/reader2/DeftypeSsm.hpp @@ -0,0 +1,12 @@ +/** @file DeftypeSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DDeftypeSsm.hpp" +#include "ssm/ISyntaxStateMachine_DDeftypeSsm.hpp" +#include "ssm/IPrintable_DDeftypeSsm.hpp" + +/* end DeftypeSsm.hpp */ diff --git a/include/xo/reader2/ParserConfig.hpp b/include/xo/reader2/ParserConfig.hpp index 080238c7..07dcb37b 100644 --- a/include/xo/reader2/ParserConfig.hpp +++ b/include/xo/reader2/ParserConfig.hpp @@ -24,7 +24,7 @@ namespace xo { .header_{}, .debug_flag_ = false }; - /** configuration for hash map for global symbol table + /** configuration for hash map for global symbol table (variables) * * reminder: ownership chain * SchematikaReader @@ -32,9 +32,25 @@ namespace xo { * ->ParserStateMachine * ->DGlobalSymtab **/ - ArenaHashMapConfig symtab_config_ { .name_ = "global-symtab", - .hint_max_capacity_ = 64*1024, - .debug_flag_ = false }; + ArenaHashMapConfig symtab_var_config_ { + .name_ = "global-vars", + .hint_max_capacity_ = 64*1024, + .debug_flag_ = false + }; + + /** configuration for hash map for global symbol table (types) + * + * reminder: ownership chain + * SchematikaReader + * ->SchematikaParser + * ->ParserStateMachine + * ->DGlobalSymtab + **/ + ArenaHashMapConfig symtab_types_config_ { + .name_ = "global-types", + .hint_max_capacity_ = 32*1024, + .debug_flag_ = false + }; /** max capacity for unique string table **/ size_t max_stringtable_capacity_ = 4096; diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 2553acbf..f24c6bed 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -47,8 +47,10 @@ namespace xo { public: /** * @p config arena configuration for parser state - * @p symtab_config configuration for global symtab + * @p symtab_var_config configuration for global symtab variables * (maps separate dedicated memory) + * @p symtab_type_config configuration for global symtab types + * (maps to separate dedicated memory) * @p max_stringtable_capacity * hard max size for unique stringtable * @p expr_alloc allocator for schematika expressions. @@ -59,7 +61,8 @@ namespace xo { * same as @p expr_alloc. **/ ParserStateMachine(const ArenaConfig & config, - const ArenaHashMapConfig & symtab_config, + const ArenaHashMapConfig & symtab_var_config, + const ArenaHashMapConfig & symtab_type_config, size_type max_stringtable_capacity, obj expr_alloc, obj aux_alloc); @@ -151,6 +154,9 @@ namespace xo { **/ void on_parsed_typedescr(TypeDescr td); + /** respond to type emitted by nested ssm **/ + void on_parsed_type(obj type); + /** update state to consume param (name, type) emitted by * nested (expired) parsing state **/ diff --git a/include/xo/reader2/ReaderConfig.hpp b/include/xo/reader2/ReaderConfig.hpp index e139e9eb..513f515e 100644 --- a/include/xo/reader2/ReaderConfig.hpp +++ b/include/xo/reader2/ReaderConfig.hpp @@ -37,7 +37,7 @@ namespace xo { .header_{}, .debug_flag_ = false }; - /** configuration for hash map for global symbol table + /** configuration for hash map for global symbol table (variables) * * reminder: ownership chain * SchematikaReader @@ -45,9 +45,25 @@ namespace xo { * ->ParserStateMachine * ->DGlobalSymtab **/ - ArenaHashMapConfig symtab_config_ { .name_ = "global-symtab", - .hint_max_capacity_ = 64*1024, - .debug_flag_ = false }; + ArenaHashMapConfig symtab_var_config_ { + .name_ = "global-vars", + .hint_max_capacity_ = 64*1024, + .debug_flag_ = false, + }; + + /** configuration for hash map for global symbol table (types) + * + * reminder: ownership chain + * SchematikaReader + * ->SchematikaParser + * ->ParserStateMachine + * ->DGlobalSymtab + **/ + ArenaHashMapConfig symtab_types_config_ { + .name_ = "global-types", + .hint_max_capacity_ = 32*1024, + .debug_flag_ = false, + }; /** debug flag for schematika parser **/ bool parser_debug_flag_ = false; diff --git a/include/xo/reader2/ssm/IPrintable_DDeftypeSsm.hpp b/include/xo/reader2/ssm/IPrintable_DDeftypeSsm.hpp new file mode 100644 index 00000000..df8820c0 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DDeftypeSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DDeftypeSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DDeftypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DDeftypeSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DDeftypeSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DDeftypeSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DDeftypeSsm + **/ + class IPrintable_DDeftypeSsm { + public: + /** @defgroup scm-printable-ddeftypessm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-ddeftypessm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DDeftypeSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDeftypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDeftypeSsm.hpp new file mode 100644 index 00000000..114f2dab --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDeftypeSsm.hpp @@ -0,0 +1,84 @@ +/** @file ISyntaxStateMachine_DDeftypeSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DDeftypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DDeftypeSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DDeftypeSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DDeftypeSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DDeftypeSsm + **/ + class ISyntaxStateMachine_DDeftypeSsm { + public: + /** @defgroup scm-syntaxstatemachine-ddeftypessm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-ddeftypessm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DDeftypeSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DDeftypeSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DDeftypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DDeftypeSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DDeftypeSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DDeftypeSsm & self, obj type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DDeftypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DDeftypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DDeftypeSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for nested parsed expression @p expr **/ + static void on_parsed_expression(DDeftypeSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DDeftypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DDeftypeSsm & self, obj lit, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 4d857d53..a01dcb62 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -21,6 +21,9 @@ namespace xo { /** handle define-expression. See @ref DDefineSsm **/ defexpr, + /** handle deftype-expression. See @ref DDeftypeSsm **/ + deftypeexpr, + /** handle lambda-expression. See @ref DLambdaSsm **/ lambdaexpr, diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 8633f75a..53c69bc6 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -25,6 +25,10 @@ set(SELF_SRCS ISyntaxStateMachine_DDefineSsm.cpp IPrintable_DDefineSsm.cpp + DDeftypeSsm.cpp + ISyntaxStateMachine_DDeftypeSsm.cpp + IPrintable_DDeftypeSsm.cpp + DIfElseSsm.cpp ISyntaxStateMachine_DIfElseSsm.cpp IPrintable_DIfElseSsm.cpp diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index b0653a52..ad9a4e50 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -139,6 +139,7 @@ namespace xo { return; case tokentype::tk_symbol: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_if: case tokentype::tk_then: case tokentype::tk_else: diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 8266046f..344e1fc1 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -13,14 +13,6 @@ #include #include -#ifdef NOT_YET -#include "parserstatemachine.hpp" -#include "expect_symbol_xs.hpp" -#include "expect_expr_xs.hpp" -#include "expect_type_xs.hpp" -#include "pretty_expression.hpp" -#endif - namespace xo { using xo::print::APrintable; using xo::facet::FacetRegistry; @@ -526,6 +518,7 @@ namespace xo { // all the not-yet handled cases case tokentype::tk_invalid: + case tokentype::tk_deftype: case tokentype::tk_string: case tokentype::tk_f64: case tokentype::tk_i64: @@ -600,7 +593,7 @@ namespace xo { if (defstate_ == defexprstatetype::def_2) { this->defstate_ = defexprstatetype::def_3; - DExpectTypeSsm::start(p_psm); + DExpectTypeSsm::start(false /*!corrected*/, p_psm); return; } @@ -688,7 +681,6 @@ namespace xo { = FacetRegistry::instance().variant(def_expr_); assert(expr.data()); - (void)expr; return ppii.pps()->pretty_struct(ppii, "DDefineSsm", diff --git a/src/reader2/DDeftypeSsm.cpp b/src/reader2/DDeftypeSsm.cpp new file mode 100644 index 00000000..ec36391a --- /dev/null +++ b/src/reader2/DDeftypeSsm.cpp @@ -0,0 +1,275 @@ +/** @file DDeftypeSsm.cpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#include "DeftypeSsm.hpp" +#include "syntaxstatetype.hpp" +#include "ExpectSymbolSsm.hpp" +#include "ExpectTypeSsm.hpp" +#include "Constant.hpp" +#include +#include + +namespace xo { + namespace scm { + + extern const char * + DeftypeXst::_descr(enum DeftypeXst::code x) + { + switch (x) { + case code::invalid: return "invalid"; + case code::def_0: return "def_0"; + case code::def_1: return "def_1"; + case code::def_2: return "def_2"; + case code::def_3: return "def_3"; + case code::def_4: return "def_4"; + case code::N: break; + } + + return "?DeftypeXst"; + } + + std::ostream & + operator<<(std::ostream & os, DeftypeXst x) + { + os << DeftypeXst::_descr(x.code()); + return os; + } + + DDeftypeSsm::DDeftypeSsm() + : deftype_xst_{DeftypeXst::code::def_0} + {} + + DDeftypeSsm * + DDeftypeSsm::_make(DArena & parser_mm) + { + void * mem = parser_mm.alloc_for(); + + return new (mem) DDeftypeSsm(); + } + + obj + DDeftypeSsm::make(DArena & parser_mm) + { + return obj(_make(parser_mm)); + } + + void + DDeftypeSsm::start(DArena & mm, + ParserStateMachine * p_psm) + { + assert(p_psm->stack()); + + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + auto deftype_ssm = DDeftypeSsm::make(mm); + + p_psm->push_ssm(ckp, deftype_ssm); + } + + syntaxstatetype + DDeftypeSsm::ssm_type() const noexcept + { + return syntaxstatetype::deftypeexpr; + } + + std::string_view + DDeftypeSsm::get_expect_str() const noexcept + { + switch (this->deftype_xst_.code()) { + case DeftypeXst::code::invalid: + break; + case DeftypeXst::code::def_0: + return "deftype"; + case DeftypeXst::code::def_1: + return "symbol"; + case DeftypeXst::code::def_2: + return "doublecolon"; + case DeftypeXst::code::def_3: + return "type"; + case DeftypeXst::code::def_4: + return "semicolon"; + case DeftypeXst::code::N: + break; + + } + + return "?expect"; + } + + void + DDeftypeSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); + + switch (tk.tk_type()) { + + case tokentype::tk_deftype: + this->on_deftype_token(tk, p_psm); + return; + + case tokentype::tk_doublecolon: + this->on_doublecolon_token(tk, p_psm); + return; + + case tokentype::tk_semicolon: + this->on_semicolon_token(tk, p_psm); + return; + + // all the not-yet handled cases + case tokentype::tk_symbol: + case tokentype::tk_def: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_invalid: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_if: + case tokentype::tk_quote: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + Super::illegal_token(tk, p_psm); + } + + void + DDeftypeSsm::on_deftype_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (deftype_xst_.code() == DeftypeXst::code::def_0) { + this->deftype_xst_ = DeftypeXst(DeftypeXst::code::def_1); + + DExpectSymbolSsm::start(p_psm); + + /* continue in .on_parsed_symbol() */ + + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DDeftypeSsm::on_parsed_symbol(std::string_view sym_name, + ParserStateMachine * p_psm) + { + if (deftype_xst_.code() == DeftypeXst::code::def_1) { + this->deftype_xst_ = DeftypeXst(DeftypeXst::code::def_2); + this->lhs_symbol_ = p_psm->intern_string(sym_name); + + return; + } + + Super::illegal_parsed_symbol(sym_name, p_psm); + } + + void + DDeftypeSsm::on_doublecolon_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (deftype_xst_.code() == DeftypeXst::code::def_2) { + this->deftype_xst_ = DeftypeXst(DeftypeXst::code::def_3); + + DExpectTypeSsm::start(true /*corrected*/, p_psm); + + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DDeftypeSsm::on_parsed_type(obj type, + ParserStateMachine * p_psm) + { + if (deftype_xst_.code() == DeftypeXst::code::def_3) { + this->deftype_xst_ = DeftypeXst(DeftypeXst::code::def_4); + + DLocalSymtab * local = p_psm->local_symtab(); + + if (local) { + local->append_type(p_psm->expr_alloc(), + lhs_symbol_, + type); + } else { + DGlobalSymtab * global = p_psm->global_symtab(); + + DTypename * tname = DTypename::_make(p_psm->expr_alloc(), + lhs_symbol_, + type); + + global->upsert_typename(p_psm->expr_alloc(), tname); + } + + return; + } + + Super::illegal_type(type, p_psm); + } + + void + DDeftypeSsm::on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (deftype_xst_.code() == DeftypeXst::code::def_4) { + p_psm->pop_ssm(); + + // Reporting a placeholder expression to preserve policy + // that 'every toplevel statement produces an expression' + // + auto result_expr + = DConstant::make(p_psm->expr_alloc(), + DBoolean::box(p_psm->expr_alloc(), + true)); + p_psm->on_parsed_expression(result_expr); + + return; + } + + Super::illegal_token(tk, p_psm); + } + + bool + DDeftypeSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, + "DDeftypeSsm", + refrtag("deftypestate", deftype_xst_), + refrtag("expect", this->get_expect_str())); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DDeftypeSsm.cpp */ diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 40ed2476..c2d46140 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -165,6 +165,7 @@ namespace xo { // all the not-yet handled cases case tokentype::tk_invalid: + case tokentype::tk_deftype: case tokentype::tk_singleassign: case tokentype::tk_colon: case tokentype::tk_semicolon: diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index 7986a6de..db287abf 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -105,6 +105,7 @@ namespace xo { case tokentype::tk_leftparen: case tokentype::tk_lambda: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_if: case tokentype::tk_symbol: case tokentype::tk_singleassign: @@ -154,7 +155,7 @@ namespace xo { if (fstate_ == formalstatetype::formal_1) { this->fstate_ = formalstatetype::formal_2; - DExpectTypeSsm::start(p_psm); + DExpectTypeSsm::start(false /*!corrected*/, p_psm); /* control reenters via DExpectFormalArgSsm::on_parsed_typedescr() */ return; diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 1de4533b..67f327e1 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -135,6 +135,7 @@ namespace xo { // all the not-yet-handled cases case tokentype::tk_lambda: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_if: case tokentype::tk_symbol: case tokentype::tk_colon: diff --git a/src/reader2/DExpectQArraySsm.cpp b/src/reader2/DExpectQArraySsm.cpp index b4a9ac29..33ccd7c8 100644 --- a/src/reader2/DExpectQArraySsm.cpp +++ b/src/reader2/DExpectQArraySsm.cpp @@ -92,6 +92,7 @@ namespace xo { case tokentype::tk_comma: case tokentype::tk_lambda: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_if: case tokentype::tk_symbol: case tokentype::tk_colon: diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp index 2227a398..9584bfea 100644 --- a/src/reader2/DExpectQListSsm.cpp +++ b/src/reader2/DExpectQListSsm.cpp @@ -92,6 +92,7 @@ namespace xo { case tokentype::tk_comma: case tokentype::tk_lambda: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_if: case tokentype::tk_symbol: case tokentype::tk_colon: diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index e03e7a39..7dc30124 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -110,6 +110,7 @@ namespace xo { case tokentype::tk_comma: case tokentype::tk_lambda: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_if: case tokentype::tk_symbol: case tokentype::tk_colon: diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 0a5d7abb..79ae0622 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -74,6 +74,7 @@ namespace xo { case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_if: case tokentype::tk_singleassign: case tokentype::tk_colon: diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index e4078936..edd71d66 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -3,14 +3,15 @@ * @author Roland Conybeare, Aug 2024 **/ -#include "DExpectTypeSsm.hpp" -#include "ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp" +#include "ExpectTypeSsm.hpp" +//#include "ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp" #include "SyntaxStateMachine.hpp" -#include +#include #include #include #include #include +#include namespace xo { using xo::facet::with_facet; @@ -19,30 +20,32 @@ namespace xo { using xo::reflect::typeseq; namespace scm { - DExpectTypeSsm::DExpectTypeSsm() + DExpectTypeSsm::DExpectTypeSsm(bool corrected) + : corrected_{corrected} {} DExpectTypeSsm * - DExpectTypeSsm::_make(DArena & mm) + DExpectTypeSsm::_make(DArena & mm, bool corrected) { void * mem = mm.alloc(typeseq::id(), sizeof(DArena)); - return new (mem) DExpectTypeSsm(); + return new (mem) DExpectTypeSsm(corrected); } obj - DExpectTypeSsm::make(DArena & mm) + DExpectTypeSsm::make(DArena & mm, bool corrected) { - return obj(_make(mm)); + return obj(_make(mm, corrected)); } void - DExpectTypeSsm::start(ParserStateMachine * p_psm) + DExpectTypeSsm::start(bool corrected, + ParserStateMachine * p_psm) { DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); - auto ssm = DExpectTypeSsm::make(p_psm->parser_alloc()); + auto ssm = DExpectTypeSsm::make(p_psm->parser_alloc(), corrected); p_psm->push_ssm(ckp, ssm); } @@ -73,6 +76,7 @@ namespace xo { // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_if: case tokentype::tk_f64: case tokentype::tk_i64: @@ -124,32 +128,57 @@ namespace xo { { scope log(XO_DEBUG(p_psm->debug_flag())); - TypeDescr td = nullptr; + if (corrected_) { + obj type; + obj mm = p_psm->expr_alloc(); - /* TODO: replace with typetable lookup */ + if (tk.text() == "unit") + type = DAtomicType::make(mm, Metatype::t_unit()); + if (tk.text() == "bool") + type = DAtomicType::make(mm, Metatype::t_bool()); + else if (tk.text() == "str") + type = DAtomicType::make(mm, Metatype::t_str()); + else if (tk.text() == "f64") + type = DAtomicType::make(mm, Metatype::t_f64()); + else if(tk.text() == "f32") + type = DAtomicType::make(mm, Metatype::t_f32()); + else if(tk.text() == "i16") + type = DAtomicType::make(mm, Metatype::t_i16()); + else if(tk.text() == "i32") + type = DAtomicType::make(mm, Metatype::t_i32()); + else if(tk.text() == "i64") + type = DAtomicType::make(mm, Metatype::t_i64()); - if (tk.text() == "bool") - td = Reflect::require(); - else if (tk.text() == "str") - td = Reflect::require(); - else if (tk.text() == "f64") - td = Reflect::require(); - else if(tk.text() == "f32") - td = Reflect::require(); - else if(tk.text() == "i16") - td = Reflect::require(); - else if(tk.text() == "i32") - td = Reflect::require(); - else if(tk.text() == "i64") - td = Reflect::require(); + p_psm->pop_ssm(); + p_psm->on_parsed_type(type); + } else { + TypeDescr td = nullptr; - if (!td) { - Super::on_token(tk, p_psm); - return; + /* TODO: replace with typetable lookup */ + + if (tk.text() == "bool") + td = Reflect::require(); + else if (tk.text() == "str") + td = Reflect::require(); + else if (tk.text() == "f64") + td = Reflect::require(); + else if(tk.text() == "f32") + td = Reflect::require(); + else if(tk.text() == "i16") + td = Reflect::require(); + else if(tk.text() == "i32") + td = Reflect::require(); + else if(tk.text() == "i64") + td = Reflect::require(); + + if (!td) { + Super::on_token(tk, p_psm); + return; + } + + p_psm->pop_ssm(); + p_psm->on_parsed_typedescr(td); } - - p_psm->pop_ssm(); - p_psm->on_parsed_typedescr(td); } bool diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index 5a17054d..00a41750 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -147,6 +147,7 @@ namespace xo { switch (tk.tk_type()) { case tokentype::tk_symbol: case tokentype::tk_def: + case tokentype::tk_deftype: break; case tokentype::tk_if: this->on_if_token(tk, p_psm); diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index c0eb92cf..9364476a 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -3,34 +3,22 @@ * @author Roland Conybeare, Jan 2026 **/ -#include "DLambdaSsm.hpp" -#include "ssm/ISyntaxStateMachine_DLambdaSsm.hpp" -#include "DExpectFormalArglistSsm.hpp" -#include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" +#include "LambdaSsm.hpp" +//#include "ssm/ISyntaxStateMachine_DLambdaSsm.hpp" +#include "ExpectFormalArglistSsm.hpp" +//#include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" #include "DExpectTypeSsm.hpp" #include "DExpectExprSsm.hpp" #include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" #include -#include -#include +#include +//#include //#include #include #include #include -#ifdef NOT_YET -#include "define_xs.hpp" -#include "parserstatemachine.hpp" -#include "exprstatestack.hpp" -#include "expect_formal_arglist_xs.hpp" -#include "expect_expr_xs.hpp" -#include "expect_type_xs.hpp" -#include "pretty_expression.hpp" -#include "pretty_variable.hpp" -#include "xo/expression/Lambda.hpp" -#endif - namespace xo { using xo::print::APrintable; using xo::mm::AAllocator; @@ -144,6 +132,7 @@ namespace xo { // all the not-yet-handled cases case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_if: case tokentype::tk_symbol: case tokentype::tk_colon: @@ -209,7 +198,7 @@ namespace xo { if (lmstate_ == lambdastatetype::lm_2) { this->lmstate_ = lambdastatetype::lm_3; - DExpectTypeSsm::start(p_psm); + DExpectTypeSsm::start(false /*!corrected*/, p_psm); /* control reenters via .on_parsed_typedescr() */ return; @@ -300,7 +289,8 @@ namespace xo { DLocalSymtab * symtab = DLocalSymtab::_make_empty(p_psm->expr_alloc(), p_psm->local_symtab(), - arglist->size()); + arglist->size(), + 0 /*ntypes*/); assert(symtab); for (DArray::size_type i = 0, n = arglist->size(); i < n; ++i) { diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index 53dc3063..d3fb5cfa 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -102,6 +102,7 @@ namespace xo { // all the not-yet handled cases case tokentype::tk_symbol: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_colon: case tokentype::tk_singleassign: case tokentype::tk_semicolon: diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 02d09e8a..edb55001 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -284,6 +284,7 @@ namespace xo { // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_if: case tokentype::tk_quote: case tokentype::tk_leftbracket: diff --git a/src/reader2/DQuoteSsm.cpp b/src/reader2/DQuoteSsm.cpp index 1ca8a8a2..7f6dd00d 100644 --- a/src/reader2/DQuoteSsm.cpp +++ b/src/reader2/DQuoteSsm.cpp @@ -18,7 +18,7 @@ namespace xo { extern const char * QuoteXst::_descr(enum QuoteXst::code x) { - switch(x) { + switch (x) { case code::invalid: return "invalid"; case code::quote_0: return "quote_0"; case code::quote_1: return "quote_1"; @@ -104,6 +104,7 @@ namespace xo { // all the not-yet handled cases case tokentype::tk_symbol: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_colon: case tokentype::tk_singleassign: case tokentype::tk_semicolon: diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index 12d47a9d..8bb2f779 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -81,6 +81,7 @@ namespace xo { return; case tokentype::tk_symbol: case tokentype::tk_def: + case tokentype::tk_deftype: case tokentype::tk_if: case tokentype::tk_then: case tokentype::tk_else: diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index d7444e43..45a91a90 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -6,6 +6,7 @@ #include "DToplevelSeqSsm.hpp" #include "ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp" #include "DDefineSsm.hpp" +#include "DDeftypeSsm.hpp" #include "DLambdaSsm.hpp" #include "ProgressSsm.hpp" #include "DIfElseSsm.hpp" @@ -15,20 +16,10 @@ #include "VarRef.hpp" #include -//#include - #include -//#include - #include -//#include - #include -//#include - #include -//#include - #include namespace xo { @@ -133,6 +124,10 @@ namespace xo { this->on_def_token(tk, p_psm); return; + case tokentype::tk_deftype: + this->on_deftype_token(tk, p_psm); + return; + case tokentype::tk_lambda: this->on_lambda_token(tk, p_psm); return; @@ -255,6 +250,17 @@ namespace xo { */ } + void + DToplevelSeqSsm::on_deftype_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + DDeftypeSsm::start(p_psm->parser_alloc(), + p_psm); + p_psm->on_token(Token::deftype_token()); + } + void DToplevelSeqSsm::on_lambda_token(const Token & tk, ParserStateMachine * p_psm) @@ -462,8 +468,8 @@ namespace xo { void DToplevelSeqSsm::on_parsed_expression_with_token(obj expr, - const Token & tk, - ParserStateMachine * p_psm) + const Token & tk, + ParserStateMachine * p_psm) { if (tk.tk_type() == tokentype::tk_semicolon) { p_psm->capture_result("DToplevelSeqSsm::on_parsed_expression_with_token", expr); diff --git a/src/reader2/IPrintable_DDeftypeSsm.cpp b/src/reader2/IPrintable_DDeftypeSsm.cpp new file mode 100644 index 00000000..8f36fd09 --- /dev/null +++ b/src/reader2/IPrintable_DDeftypeSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DDeftypeSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DDeftypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DDeftypeSsm.json5] +**/ + +#include "ssm/IPrintable_DDeftypeSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DDeftypeSsm::pretty(const DDeftypeSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DDeftypeSsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DDeftypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DDeftypeSsm.cpp new file mode 100644 index 00000000..9fcc835f --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DDeftypeSsm.cpp @@ -0,0 +1,84 @@ +/** @file ISyntaxStateMachine_DDeftypeSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DDeftypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DDeftypeSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DDeftypeSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DDeftypeSsm::ssm_type(const DDeftypeSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DDeftypeSsm::get_expect_str(const DDeftypeSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DDeftypeSsm::on_token(DDeftypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DDeftypeSsm::on_parsed_symbol(DDeftypeSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DDeftypeSsm::on_parsed_typedescr(DDeftypeSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DDeftypeSsm::on_parsed_type(DDeftypeSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto + ISyntaxStateMachine_DDeftypeSsm::on_parsed_formal(DDeftypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DDeftypeSsm::on_parsed_formal_with_token(DDeftypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto + ISyntaxStateMachine_DDeftypeSsm::on_parsed_formal_arglist(DDeftypeSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DDeftypeSsm::on_parsed_expression(DDeftypeSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DDeftypeSsm::on_parsed_expression_with_token(DDeftypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + auto + ISyntaxStateMachine_DDeftypeSsm::on_quoted_literal(DDeftypeSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DDeftypeSsm.cpp */ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 3c640332..360ae43e 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -25,7 +25,8 @@ namespace xo { namespace scm { ParserStateMachine::ParserStateMachine(const ArenaConfig & config, - const ArenaHashMapConfig & symtab_config, + const ArenaHashMapConfig & symtab_var_config, + const ArenaHashMapConfig & symtab_type_config, size_type max_stringtable_capacity, obj expr_alloc, obj aux_alloc) @@ -33,7 +34,9 @@ namespace xo { parser_alloc_{DArena::map(config)}, expr_alloc_{expr_alloc}, aux_alloc_{aux_alloc}, - global_symtab_{DGlobalSymtab::make(expr_alloc, aux_alloc, symtab_config)}, + global_symtab_{DGlobalSymtab::make(expr_alloc, aux_alloc, + symtab_var_config, + symtab_type_config)}, debug_flag_{config.debug_flag_} { } @@ -275,6 +278,16 @@ namespace xo { this->stack_->top().on_parsed_typedescr(td, this); } + void + ParserStateMachine::on_parsed_type(obj type) + { + scope log(XO_DEBUG(debug_flag_)); + + assert(stack_); + + this->stack_->top().on_parsed_type(type, this); + } + void ParserStateMachine::on_parsed_formal(const DUniqueString * sym, TypeDescr td) diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index 74e17576..d6ab1a0a 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -23,11 +23,14 @@ namespace xo { SchematikaParser::SchematikaParser(const ParserConfig & cfg, obj expr_alloc, obj aux_alloc) - : psm_{cfg.parser_arena_config_, - cfg.symtab_config_, - cfg.max_stringtable_capacity_, - expr_alloc, - aux_alloc}, + : psm_{ + cfg.parser_arena_config_, + cfg.symtab_var_config_, + cfg.symtab_types_config_, + cfg.max_stringtable_capacity_, + expr_alloc, + aux_alloc + }, debug_flag_{cfg.debug_flag_} { } diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index f9cad55a..0725a18c 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -15,7 +15,8 @@ namespace xo { : tokenizer_{config.tk_buffer_config_, config.tk_debug_flag_}, parser_{ParserConfig(config.parser_arena_config_, - config.symtab_config_, + config.symtab_var_config_, + config.symtab_types_config_, config.max_stringtable_cap_, config.parser_debug_flag_), expr_alloc, diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 909c1bc2..5262c1e9 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -8,6 +8,7 @@ #include "SchematikaParser.hpp" #include "ToplevelSeqSsm.hpp" #include "DefineSsm.hpp" +#include "DeftypeSsm.hpp" #include "LambdaSsm.hpp" #include "IfElseSsm.hpp" #include "ApplySsm.hpp" @@ -47,6 +48,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); @@ -98,6 +102,7 @@ namespace xo { log && log(xtag("DToplevelSeqSsm.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); + log && log(xtag("DDeftypeSsm.tseq", typeseq::id())); log && log(xtag("DLambdaSsm.tseq", typeseq::id())); log && log(xtag("DIfElseSsm.tseq", typeseq::id())); log && log(xtag("DExpectFormalArglistSsm.tseq", typeseq::id())); diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index 9b6c0928..4aa21b0c 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -15,6 +15,8 @@ namespace xo { break; case syntaxstatetype::defexpr: return "defexpr"; + case syntaxstatetype::deftypeexpr: + return "deftypeexpr"; case syntaxstatetype::lambdaexpr: return "lambdaexpr"; case syntaxstatetype::ifelseexpr: diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index c299306f..c2591815 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -77,7 +77,8 @@ namespace xo { ParserConfig cfg; cfg.parser_arena_config_.size_ = 16 * 1024; /* editor bait: symbol table */ - cfg.symtab_config_.hint_max_capacity_ = 128; + cfg.symtab_var_config_.hint_max_capacity_ = 128; + cfg.symtab_types_config_.hint_max_capacity_ = 64; cfg.max_stringtable_capacity_ = 512; cfg.debug_flag_ = false; @@ -272,6 +273,45 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-batch-deftype", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_batch_session(); + + /** Walkthrough parsing input equivalent to: + * + * deftype foo :: f64; + **/ + + std::vector tk_v{ + Token::deftype_token(), + Token::symbol_token("foo"), + Token::doublecolon_token(), + Token::symbol_token("f64"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + // placeholder for form's sake. + // deftype doesn't actuallly produce any executable content + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + + log && fixture.log_memory_layout(&log); + } + TEST_CASE("SchematikaParser-interactive-def2", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); @@ -1325,7 +1365,7 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); From 458fd04ca2b89c48673dd216d34ff930bd0d065b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 07:49:14 -0500 Subject: [PATCH 271/342] xo-reader2 stack: expand symbol table to store typedefs + typedef utest + misc qol policy choices --- include/xo/tokenizer2/Token.hpp | 6 ++++-- include/xo/tokenizer2/tokentype.hpp | 3 +++ src/tokenizer2/Tokenizer.cpp | 2 ++ src/tokenizer2/tokentype.cpp | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index 5f8be733..c7c43287 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -111,8 +111,8 @@ namespace xo { static Token comma_token() { return Token(tokentype::tk_comma); } /** token representing colon @c ":" **/ static Token colon_token() { return Token(tokentype::tk_colon); } - /** token representing double-colo @c "::" **/ - static Token doublecolon() { return Token(tokentype::tk_doublecolon); } + /** token representing double-colon @c "::" **/ + static Token doublecolon_token() { return Token(tokentype::tk_doublecolon); } /** token representing semicolon @c ";" **/ static Token semicolon_token() { return Token(tokentype::tk_semicolon); } /** token representing single-assignment @c "=" (editor bait: equal_token) **/ @@ -138,6 +138,8 @@ namespace xo { static Token type() { return Token(tokentype::tk_type); } /** token representing keyword @c def **/ static Token def_token() { return Token(tokentype::tk_def); } + /** token representing keyword @c deftype **/ + static Token deftype_token() { return Token(tokentype::tk_deftype); } /** token representing keyword @c lambda **/ static Token lambda_token() { return Token(tokentype::tk_lambda); } /** token representing keyword @c if **/ diff --git a/include/xo/tokenizer2/tokentype.hpp b/include/xo/tokenizer2/tokentype.hpp index 3f259f8d..d0290b05 100644 --- a/include/xo/tokenizer2/tokentype.hpp +++ b/include/xo/tokenizer2/tokentype.hpp @@ -146,6 +146,9 @@ namespace xo { /** keyword @c 'def' **/ tk_def, + /** keyword @c 'deftype' **/ + tk_deftype, + /** keyword @c 'lambda' **/ tk_lambda, diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index 323c2d8d..f6ac7c2f 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -591,6 +591,8 @@ namespace xo { tk_type = tokentype::tk_type; } else if (tk_text == "def") { tk_type = tokentype::tk_def; + } else if (tk_text == "deftype") { + tk_type = tokentype::tk_deftype; } else if (tk_text == "lambda") { tk_type = tokentype::tk_lambda; } else if (tk_text == "if") { diff --git a/src/tokenizer2/tokentype.cpp b/src/tokenizer2/tokentype.cpp index 0831940f..7df59eec 100644 --- a/src/tokenizer2/tokentype.cpp +++ b/src/tokenizer2/tokentype.cpp @@ -51,6 +51,7 @@ namespace xo { CASE(tk_type); CASE(tk_def); + CASE(tk_deftype); CASE(tk_lambda); CASE(tk_if); CASE(tk_then); From a7dcf260d1bf6b1ddd745d9cffc6306ccb380854 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 08:41:57 -0500 Subject: [PATCH 272/342] build: retiring REPR argument to xo_add_genfacetimpl() --- CMakeLists.txt | 72 +++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e0f1e95..6605df49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-toplevelseqssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ToplevelSeqSsm +# REPR ToplevelSeqSsm INPUT idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 ) @@ -47,7 +47,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-toplevelseqssm FACET_PKG xo_printable2 FACET Printable - REPR ToplevelSeqSsm +# REPR ToplevelSeqSsm INPUT idl/IPrintable_DToplevelSeqSsm.json5 ) @@ -58,7 +58,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-definessm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR DefineSsm +# REPR DefineSsm INPUT idl/ISyntaxStateMachine_DDefineSsm.json5 ) @@ -67,7 +67,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-definessm FACET_PKG xo_printable2 FACET Printable - REPR DefineSsm +# REPR DefineSsm INPUT idl/IPrintable_DDefineSsm.json5 ) @@ -78,7 +78,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-deftypessm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR DeftypeSsm +# REPR DeftypeSsm INPUT idl/ISyntaxStateMachine_DDeftypeSsm.json5 ) @@ -87,7 +87,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-deftypessm FACET_PKG xo_printable2 FACET Printable - REPR DeftypeSsm +# REPR DeftypeSsm INPUT idl/IPrintable_DDeftypeSsm.json5 ) @@ -98,7 +98,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-lambdassm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR LambdaSsm +# REPR LambdaSsm INPUT idl/ISyntaxStateMachine_DLambdaSsm.json5 ) @@ -107,7 +107,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-lambdassm FACET_PKG xo_printable2 FACET Printable - REPR LambdaSsm +# REPR LambdaSsm INPUT idl/IPrintable_DLambdaSsm.json5 ) @@ -118,7 +118,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-parenssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ParenSsm +# REPR ParenSsm INPUT idl/ISyntaxStateMachine_DParenSsm.json5 ) @@ -127,7 +127,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-parenssm FACET_PKG xo_printable2 FACET Printable - REPR ParenSsm +# REPR ParenSsm INPUT idl/IPrintable_DParenSsm.json5 ) @@ -138,7 +138,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectformalarglistssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ExpectFormalArglistSsm +# REPR ExpectFormalArglistSsm INPUT idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 ) @@ -147,7 +147,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectformalarglistssm FACET_PKG xo_printable2 FACET Printable - REPR ExpectFormalArglistSsm +# REPR ExpectFormalArglistSsm INPUT idl/IPrintable_DExpectFormalArglistSsm.json5 ) @@ -158,7 +158,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectformalargssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ExpectFormalArgSsm +# REPR ExpectFormalArgSsm INPUT idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 ) @@ -167,7 +167,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectformalargssm FACET_PKG xo_printable2 FACET Printable - REPR ExpectFormalArgSsm +# REPR ExpectFormalArgSsm INPUT idl/IPrintable_DExpectFormalArgSsm.json5 ) @@ -178,7 +178,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-ifelsessm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR IfElseSsm +# REPR IfElseSsm INPUT idl/ISyntaxStateMachine_DIfElseSsm.json5 ) @@ -187,7 +187,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-ifelsessm FACET_PKG xo_printable2 FACET Printable - REPR IfElseSsm +# REPR IfElseSsm INPUT idl/IPrintable_DIfElseSsm.json5 ) @@ -198,7 +198,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-sequencessm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR SequenceSsm +# REPR SequenceSsm INPUT idl/ISyntaxStateMachine_DSequenceSsm.json5 ) @@ -207,7 +207,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-sequencessm FACET_PKG xo_printable2 FACET Printable - REPR SequenceSsm +# REPR SequenceSsm INPUT idl/IPrintable_DSequenceSsm.json5 ) @@ -218,7 +218,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-applyssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ApplySsm +# REPR ApplySsm INPUT idl/ISyntaxStateMachine_DApplySsm.json5 ) @@ -227,7 +227,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-applyssm FACET_PKG xo_printable2 FACET Printable - REPR ApplySsm +# REPR ApplySsm INPUT idl/IPrintable_DApplySsm.json5 ) @@ -238,7 +238,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectsymbolssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ExpectSymbolSsm +# REPR ExpectSymbolSsm INPUT idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 ) @@ -247,7 +247,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectsymbolssm FACET_PKG xo_printable2 FACET Printable - REPR ExpectSymbolSsm +# REPR ExpectSymbolSsm INPUT idl/IPrintable_DExpectSymbolSsm.json5 ) @@ -258,7 +258,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expecttypessm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ExpectTypeSsm +# REPR ExpectTypeSsm INPUT idl/ISyntaxStateMachine_DExpectTypeSsm.json5 ) @@ -267,7 +267,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expecttypessm FACET_PKG xo_printable2 FACET Printable - REPR ExpectTypeSsm +# REPR ExpectTypeSsm INPUT idl/IPrintable_DExpectTypeSsm.json5 ) @@ -278,7 +278,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectexprssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ExpectExprSsm +# REPR ExpectExprSsm INPUT idl/ISyntaxStateMachine_DExpectExprSsm.json5 ) @@ -287,7 +287,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectexprssm FACET_PKG xo_printable2 FACET Printable - REPR ExpectExprSsm +# REPR ExpectExprSsm INPUT idl/IPrintable_DExpectExprSsm.json5 ) @@ -298,7 +298,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-progressssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ProgressSsm +# REPR ProgressSsm INPUT idl/ISyntaxStateMachine_DProgressSsm.json5 ) @@ -307,7 +307,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-progressssm FACET_PKG xo_printable2 FACET Printable - REPR ProgressSsm +# REPR ProgressSsm INPUT idl/IPrintable_DProgressSsm.json5 ) @@ -318,7 +318,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-quotessm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR QuoteSsm +# REPR QuoteSsm INPUT idl/ISyntaxStateMachine_DQuoteSsm.json5 ) @@ -327,7 +327,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-quotessm FACET_PKG xo_printable2 FACET Printable - REPR QuoteSsm +# REPR QuoteSsm INPUT idl/IPrintable_DQuoteSsm.json5 ) @@ -338,7 +338,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqliteralssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ExpectQLiteralSsm +# REPR ExpectQLiteralSsm INPUT idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5 ) @@ -347,7 +347,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectqliteralssm FACET_PKG xo_printable2 FACET Printable - REPR ExpectQLiteralSsm +# REPR ExpectQLiteralSsm INPUT idl/IPrintable_DExpectQLiteralSsm.json5 ) @@ -358,7 +358,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqlistssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ExpectQListSsm +# REPR ExpectQListSsm INPUT idl/ISyntaxStateMachine_DExpectQListSsm.json5 ) @@ -367,7 +367,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectqlistssm FACET_PKG xo_printable2 FACET Printable - REPR ExpectQListSsm +# REPR ExpectQListSsm INPUT idl/IPrintable_DExpectQListSsm.json5 ) @@ -378,7 +378,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqarrayssm FACET_PKG xo_reader2 FACET SyntaxStateMachine - REPR ExpectQArraySsm +# REPR ExpectQArraySsm INPUT idl/ISyntaxStateMachine_DExpectQArraySsm.json5 ) @@ -387,7 +387,7 @@ xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectqarrayssm FACET_PKG xo_printable2 FACET Printable - REPR ExpectQArraySsm +# REPR ExpectQArraySsm INPUT idl/IPrintable_DExpectQArraySsm.json5 ) From aaf3f25347d7164b5562a94c01fb99df969c614a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 10:03:46 -0500 Subject: [PATCH 273/342] build: retire FACET argument to genfacetimpl --- CMakeLists.txt | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6605df49..93f23788 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,6 @@ xo_add_genfacet( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-toplevelseqssm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ToplevelSeqSsm INPUT idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 ) @@ -46,7 +45,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-toplevelseqssm FACET_PKG xo_printable2 - FACET Printable # REPR ToplevelSeqSsm INPUT idl/IPrintable_DToplevelSeqSsm.json5 ) @@ -57,7 +55,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-definessm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR DefineSsm INPUT idl/ISyntaxStateMachine_DDefineSsm.json5 ) @@ -66,7 +63,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-definessm FACET_PKG xo_printable2 - FACET Printable # REPR DefineSsm INPUT idl/IPrintable_DDefineSsm.json5 ) @@ -77,7 +73,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-deftypessm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR DeftypeSsm INPUT idl/ISyntaxStateMachine_DDeftypeSsm.json5 ) @@ -86,7 +81,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-deftypessm FACET_PKG xo_printable2 - FACET Printable # REPR DeftypeSsm INPUT idl/IPrintable_DDeftypeSsm.json5 ) @@ -97,7 +91,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-lambdassm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR LambdaSsm INPUT idl/ISyntaxStateMachine_DLambdaSsm.json5 ) @@ -106,7 +99,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-lambdassm FACET_PKG xo_printable2 - FACET Printable # REPR LambdaSsm INPUT idl/IPrintable_DLambdaSsm.json5 ) @@ -117,7 +109,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-parenssm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ParenSsm INPUT idl/ISyntaxStateMachine_DParenSsm.json5 ) @@ -126,7 +117,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-parenssm FACET_PKG xo_printable2 - FACET Printable # REPR ParenSsm INPUT idl/IPrintable_DParenSsm.json5 ) @@ -137,7 +127,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectformalarglistssm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ExpectFormalArglistSsm INPUT idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 ) @@ -146,7 +135,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectformalarglistssm FACET_PKG xo_printable2 - FACET Printable # REPR ExpectFormalArglistSsm INPUT idl/IPrintable_DExpectFormalArglistSsm.json5 ) @@ -157,7 +145,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectformalargssm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ExpectFormalArgSsm INPUT idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 ) @@ -166,7 +153,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectformalargssm FACET_PKG xo_printable2 - FACET Printable # REPR ExpectFormalArgSsm INPUT idl/IPrintable_DExpectFormalArgSsm.json5 ) @@ -177,7 +163,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-ifelsessm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR IfElseSsm INPUT idl/ISyntaxStateMachine_DIfElseSsm.json5 ) @@ -186,7 +171,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-ifelsessm FACET_PKG xo_printable2 - FACET Printable # REPR IfElseSsm INPUT idl/IPrintable_DIfElseSsm.json5 ) @@ -197,7 +181,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-sequencessm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR SequenceSsm INPUT idl/ISyntaxStateMachine_DSequenceSsm.json5 ) @@ -206,7 +189,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-sequencessm FACET_PKG xo_printable2 - FACET Printable # REPR SequenceSsm INPUT idl/IPrintable_DSequenceSsm.json5 ) @@ -217,7 +199,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-applyssm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ApplySsm INPUT idl/ISyntaxStateMachine_DApplySsm.json5 ) @@ -226,7 +207,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-applyssm FACET_PKG xo_printable2 - FACET Printable # REPR ApplySsm INPUT idl/IPrintable_DApplySsm.json5 ) @@ -237,7 +217,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectsymbolssm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ExpectSymbolSsm INPUT idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 ) @@ -246,7 +225,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectsymbolssm FACET_PKG xo_printable2 - FACET Printable # REPR ExpectSymbolSsm INPUT idl/IPrintable_DExpectSymbolSsm.json5 ) @@ -257,7 +235,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expecttypessm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ExpectTypeSsm INPUT idl/ISyntaxStateMachine_DExpectTypeSsm.json5 ) @@ -266,7 +243,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expecttypessm FACET_PKG xo_printable2 - FACET Printable # REPR ExpectTypeSsm INPUT idl/IPrintable_DExpectTypeSsm.json5 ) @@ -277,7 +253,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectexprssm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ExpectExprSsm INPUT idl/ISyntaxStateMachine_DExpectExprSsm.json5 ) @@ -286,7 +261,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectexprssm FACET_PKG xo_printable2 - FACET Printable # REPR ExpectExprSsm INPUT idl/IPrintable_DExpectExprSsm.json5 ) @@ -297,7 +271,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-progressssm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ProgressSsm INPUT idl/ISyntaxStateMachine_DProgressSsm.json5 ) @@ -306,7 +279,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-progressssm FACET_PKG xo_printable2 - FACET Printable # REPR ProgressSsm INPUT idl/IPrintable_DProgressSsm.json5 ) @@ -317,7 +289,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-quotessm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR QuoteSsm INPUT idl/ISyntaxStateMachine_DQuoteSsm.json5 ) @@ -326,7 +297,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-quotessm FACET_PKG xo_printable2 - FACET Printable # REPR QuoteSsm INPUT idl/IPrintable_DQuoteSsm.json5 ) @@ -337,7 +307,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqliteralssm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ExpectQLiteralSsm INPUT idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5 ) @@ -346,7 +315,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectqliteralssm FACET_PKG xo_printable2 - FACET Printable # REPR ExpectQLiteralSsm INPUT idl/IPrintable_DExpectQLiteralSsm.json5 ) @@ -357,7 +325,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqlistssm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ExpectQListSsm INPUT idl/ISyntaxStateMachine_DExpectQListSsm.json5 ) @@ -366,7 +333,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectqlistssm FACET_PKG xo_printable2 - FACET Printable # REPR ExpectQListSsm INPUT idl/IPrintable_DExpectQListSsm.json5 ) @@ -377,7 +343,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqarrayssm FACET_PKG xo_reader2 - FACET SyntaxStateMachine # REPR ExpectQArraySsm INPUT idl/ISyntaxStateMachine_DExpectQArraySsm.json5 ) @@ -386,7 +351,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectqarrayssm FACET_PKG xo_printable2 - FACET Printable # REPR ExpectQArraySsm INPUT idl/IPrintable_DExpectQArraySsm.json5 ) From 8bb36ae3e0e5b9142e1fd7b793863dcfd78b6f13 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 10:06:59 -0500 Subject: [PATCH 274/342] xo-reader2: tidy CMakeLists.txt --- CMakeLists.txt | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 93f23788..42869a58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,6 @@ xo_add_genfacet( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-toplevelseqssm FACET_PKG xo_reader2 -# REPR ToplevelSeqSsm INPUT idl/ISyntaxStateMachine_DToplevelSeqSsm.json5 ) @@ -45,7 +44,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-toplevelseqssm FACET_PKG xo_printable2 -# REPR ToplevelSeqSsm INPUT idl/IPrintable_DToplevelSeqSsm.json5 ) @@ -55,7 +53,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-definessm FACET_PKG xo_reader2 -# REPR DefineSsm INPUT idl/ISyntaxStateMachine_DDefineSsm.json5 ) @@ -63,7 +60,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-definessm FACET_PKG xo_printable2 -# REPR DefineSsm INPUT idl/IPrintable_DDefineSsm.json5 ) @@ -73,7 +69,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-deftypessm FACET_PKG xo_reader2 -# REPR DeftypeSsm INPUT idl/ISyntaxStateMachine_DDeftypeSsm.json5 ) @@ -81,7 +76,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-deftypessm FACET_PKG xo_printable2 -# REPR DeftypeSsm INPUT idl/IPrintable_DDeftypeSsm.json5 ) @@ -91,7 +85,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-lambdassm FACET_PKG xo_reader2 -# REPR LambdaSsm INPUT idl/ISyntaxStateMachine_DLambdaSsm.json5 ) @@ -99,7 +92,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-lambdassm FACET_PKG xo_printable2 -# REPR LambdaSsm INPUT idl/IPrintable_DLambdaSsm.json5 ) @@ -109,7 +101,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-parenssm FACET_PKG xo_reader2 -# REPR ParenSsm INPUT idl/ISyntaxStateMachine_DParenSsm.json5 ) @@ -117,7 +108,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-parenssm FACET_PKG xo_printable2 -# REPR ParenSsm INPUT idl/IPrintable_DParenSsm.json5 ) @@ -127,7 +117,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectformalarglistssm FACET_PKG xo_reader2 -# REPR ExpectFormalArglistSsm INPUT idl/ISyntaxStateMachine_DExpectFormalArglistSsm.json5 ) @@ -135,7 +124,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectformalarglistssm FACET_PKG xo_printable2 -# REPR ExpectFormalArglistSsm INPUT idl/IPrintable_DExpectFormalArglistSsm.json5 ) @@ -145,7 +133,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectformalargssm FACET_PKG xo_reader2 -# REPR ExpectFormalArgSsm INPUT idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 ) @@ -153,7 +140,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectformalargssm FACET_PKG xo_printable2 -# REPR ExpectFormalArgSsm INPUT idl/IPrintable_DExpectFormalArgSsm.json5 ) @@ -163,7 +149,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-ifelsessm FACET_PKG xo_reader2 -# REPR IfElseSsm INPUT idl/ISyntaxStateMachine_DIfElseSsm.json5 ) @@ -171,7 +156,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-ifelsessm FACET_PKG xo_printable2 -# REPR IfElseSsm INPUT idl/IPrintable_DIfElseSsm.json5 ) @@ -181,7 +165,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-sequencessm FACET_PKG xo_reader2 -# REPR SequenceSsm INPUT idl/ISyntaxStateMachine_DSequenceSsm.json5 ) @@ -189,7 +172,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-sequencessm FACET_PKG xo_printable2 -# REPR SequenceSsm INPUT idl/IPrintable_DSequenceSsm.json5 ) @@ -199,7 +181,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-applyssm FACET_PKG xo_reader2 -# REPR ApplySsm INPUT idl/ISyntaxStateMachine_DApplySsm.json5 ) @@ -207,7 +188,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-applyssm FACET_PKG xo_printable2 -# REPR ApplySsm INPUT idl/IPrintable_DApplySsm.json5 ) @@ -217,7 +197,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectsymbolssm FACET_PKG xo_reader2 -# REPR ExpectSymbolSsm INPUT idl/ISyntaxStateMachine_DExpectSymbolSsm.json5 ) @@ -225,7 +204,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectsymbolssm FACET_PKG xo_printable2 -# REPR ExpectSymbolSsm INPUT idl/IPrintable_DExpectSymbolSsm.json5 ) @@ -235,7 +213,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expecttypessm FACET_PKG xo_reader2 -# REPR ExpectTypeSsm INPUT idl/ISyntaxStateMachine_DExpectTypeSsm.json5 ) @@ -243,7 +220,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expecttypessm FACET_PKG xo_printable2 -# REPR ExpectTypeSsm INPUT idl/IPrintable_DExpectTypeSsm.json5 ) @@ -253,7 +229,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectexprssm FACET_PKG xo_reader2 -# REPR ExpectExprSsm INPUT idl/ISyntaxStateMachine_DExpectExprSsm.json5 ) @@ -261,7 +236,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectexprssm FACET_PKG xo_printable2 -# REPR ExpectExprSsm INPUT idl/IPrintable_DExpectExprSsm.json5 ) @@ -271,7 +245,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-progressssm FACET_PKG xo_reader2 -# REPR ProgressSsm INPUT idl/ISyntaxStateMachine_DProgressSsm.json5 ) @@ -279,7 +252,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-progressssm FACET_PKG xo_printable2 -# REPR ProgressSsm INPUT idl/IPrintable_DProgressSsm.json5 ) @@ -289,7 +261,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-quotessm FACET_PKG xo_reader2 -# REPR QuoteSsm INPUT idl/ISyntaxStateMachine_DQuoteSsm.json5 ) @@ -297,7 +268,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-quotessm FACET_PKG xo_printable2 -# REPR QuoteSsm INPUT idl/IPrintable_DQuoteSsm.json5 ) @@ -307,7 +277,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqliteralssm FACET_PKG xo_reader2 -# REPR ExpectQLiteralSsm INPUT idl/ISyntaxStateMachine_DExpectQLiteralSsm.json5 ) @@ -315,7 +284,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectqliteralssm FACET_PKG xo_printable2 -# REPR ExpectQLiteralSsm INPUT idl/IPrintable_DExpectQLiteralSsm.json5 ) @@ -325,7 +293,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqlistssm FACET_PKG xo_reader2 -# REPR ExpectQListSsm INPUT idl/ISyntaxStateMachine_DExpectQListSsm.json5 ) @@ -333,7 +300,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectqlistssm FACET_PKG xo_printable2 -# REPR ExpectQListSsm INPUT idl/IPrintable_DExpectQListSsm.json5 ) @@ -343,7 +309,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqarrayssm FACET_PKG xo_reader2 -# REPR ExpectQArraySsm INPUT idl/ISyntaxStateMachine_DExpectQArraySsm.json5 ) @@ -351,7 +316,6 @@ xo_add_genfacetimpl( xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-printable-expectqarrayssm FACET_PKG xo_printable2 -# REPR ExpectQArraySsm INPUT idl/IPrintable_DExpectQArraySsm.json5 ) From afe34f1d8a34b8d247ba6c66eae4798a329f19bd Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 10:21:17 -0500 Subject: [PATCH 275/342] xo-reader2: refactor: generated file locn for IfElseSsm --- idl/IPrintable_DIfElseSsm.json5 | 4 ++-- idl/ISyntaxStateMachine_DIfElseSsm.json5 | 4 ++-- include/xo/reader2/IfElseSsm.hpp | 6 +++--- include/xo/reader2/{ => ifelse}/DIfElseSsm.hpp | 0 .../reader2/{ssm => ifelse}/IPrintable_DIfElseSsm.hpp | 0 .../{ssm => ifelse}/ISyntaxStateMachine_DIfElseSsm.hpp | 0 src/reader2/CMakeLists.txt | 4 ++-- src/reader2/DIfElseSsm.cpp | 10 +++------- src/reader2/DToplevelSeqSsm.cpp | 3 ++- src/reader2/{ => facet}/IPrintable_DIfElseSsm.cpp | 2 +- .../{ => facet}/ISyntaxStateMachine_DIfElseSsm.cpp | 2 +- 11 files changed, 16 insertions(+), 19 deletions(-) rename include/xo/reader2/{ => ifelse}/DIfElseSsm.hpp (100%) rename include/xo/reader2/{ssm => ifelse}/IPrintable_DIfElseSsm.hpp (100%) rename include/xo/reader2/{ssm => ifelse}/ISyntaxStateMachine_DIfElseSsm.hpp (100%) rename src/reader2/{ => facet}/IPrintable_DIfElseSsm.cpp (93%) rename src/reader2/{ => facet}/ISyntaxStateMachine_DIfElseSsm.cpp (98%) diff --git a/idl/IPrintable_DIfElseSsm.json5 b/idl/IPrintable_DIfElseSsm.json5 index dbcdbb0a..7c57eb7a 100644 --- a/idl/IPrintable_DIfElseSsm.json5 +++ b/idl/IPrintable_DIfElseSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "ifelse", includes: [ "", "" ], local_types: [], diff --git a/idl/ISyntaxStateMachine_DIfElseSsm.json5 b/idl/ISyntaxStateMachine_DIfElseSsm.json5 index 25feadde..eb2ea371 100644 --- a/idl/ISyntaxStateMachine_DIfElseSsm.json5 +++ b/idl/ISyntaxStateMachine_DIfElseSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "ifelse", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/include/xo/reader2/IfElseSsm.hpp b/include/xo/reader2/IfElseSsm.hpp index eaa6948d..7fa7fcc5 100644 --- a/include/xo/reader2/IfElseSsm.hpp +++ b/include/xo/reader2/IfElseSsm.hpp @@ -5,8 +5,8 @@ #pragma once -#include "DIfElseSsm.hpp" -#include "ssm/ISyntaxStateMachine_DIfElseSsm.hpp" -#include "ssm/IPrintable_DIfElseSsm.hpp" +#include "ifelse/DIfElseSsm.hpp" +#include "ifelse/ISyntaxStateMachine_DIfElseSsm.hpp" +#include "ifelse/IPrintable_DIfElseSsm.hpp" /* end IfElseSsm.hpp */ diff --git a/include/xo/reader2/DIfElseSsm.hpp b/include/xo/reader2/ifelse/DIfElseSsm.hpp similarity index 100% rename from include/xo/reader2/DIfElseSsm.hpp rename to include/xo/reader2/ifelse/DIfElseSsm.hpp diff --git a/include/xo/reader2/ssm/IPrintable_DIfElseSsm.hpp b/include/xo/reader2/ifelse/IPrintable_DIfElseSsm.hpp similarity index 100% rename from include/xo/reader2/ssm/IPrintable_DIfElseSsm.hpp rename to include/xo/reader2/ifelse/IPrintable_DIfElseSsm.hpp diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp similarity index 100% rename from include/xo/reader2/ssm/ISyntaxStateMachine_DIfElseSsm.hpp rename to include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 53c69bc6..66a5e8f8 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -30,8 +30,8 @@ set(SELF_SRCS IPrintable_DDeftypeSsm.cpp DIfElseSsm.cpp - ISyntaxStateMachine_DIfElseSsm.cpp - IPrintable_DIfElseSsm.cpp + facet/ISyntaxStateMachine_DIfElseSsm.cpp + facet/IPrintable_DIfElseSsm.cpp DSequenceSsm.cpp ISyntaxStateMachine_DSequenceSsm.cpp diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index 00a41750..5752dbdc 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -3,22 +3,18 @@ * @author Roland Conybeare, Jul 2025 **/ -#include "DIfElseSsm.hpp" -#include "ssm/ISyntaxStateMachine_DIfElseSsm.hpp" +#include "ifelse/DIfElseSsm.hpp" +#include "ifelse/ISyntaxStateMachine_DIfElseSsm.hpp" #include "ssm/IPrintable_DDefineSsm.hpp" #include "DExpectExprSsm.hpp" #include #include #include -//#include "exprstatestack.hpp" -//#include "parserstatemachine.hpp" -//#include "expect_expr_xs.hpp" -//#include "xo/indentlog/print/ppdetail_atomic.hpp" namespace xo { using xo::print::APrintable; using xo::facet::FacetRegistry; - using xo::facet::with_facet; +// using xo::facet::with_facet; using xo::reflect::typeseq; namespace scm { diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index 45a91a90..f43d1a62 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -9,7 +9,8 @@ #include "DDeftypeSsm.hpp" #include "DLambdaSsm.hpp" #include "ProgressSsm.hpp" -#include "DIfElseSsm.hpp" +#include "IfElseSsm.hpp" +//#include "ifelse/DIfElseSsm.hpp" #include "QuoteSsm.hpp" #include "ParenSsm.hpp" #include "ExpectExprSsm.hpp" diff --git a/src/reader2/IPrintable_DIfElseSsm.cpp b/src/reader2/facet/IPrintable_DIfElseSsm.cpp similarity index 93% rename from src/reader2/IPrintable_DIfElseSsm.cpp rename to src/reader2/facet/IPrintable_DIfElseSsm.cpp index d0ef4bb3..50a98996 100644 --- a/src/reader2/IPrintable_DIfElseSsm.cpp +++ b/src/reader2/facet/IPrintable_DIfElseSsm.cpp @@ -11,7 +11,7 @@ * [idl/IPrintable_DIfElseSsm.json5] **/ -#include "ssm/IPrintable_DIfElseSsm.hpp" +#include "ifelse/IPrintable_DIfElseSsm.hpp" namespace xo { namespace scm { diff --git a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp similarity index 98% rename from src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp rename to src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp index fef959ca..7ebfbeca 100644 --- a/src/reader2/ISyntaxStateMachine_DIfElseSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp @@ -11,7 +11,7 @@ * [idl/ISyntaxStateMachine_DIfElseSsm.json5] **/ -#include "ssm/ISyntaxStateMachine_DIfElseSsm.hpp" +#include "ifelse/ISyntaxStateMachine_DIfElseSsm.hpp" namespace xo { namespace scm { From 309af002d2fcfefc30613d8b389804a36bd72248 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 10:27:04 -0500 Subject: [PATCH 276/342] xo-reader2: refactor: move Lambda genfacet files to subdirs --- idl/IPrintable_DLambdaSsm.json5 | 4 ++-- idl/ISyntaxStateMachine_DLambdaSsm.json5 | 4 ++-- include/xo/reader2/LambdaSsm.hpp | 6 +++--- include/xo/reader2/{ => lambda}/DLambdaSsm.hpp | 0 .../reader2/{ssm => lambda}/IPrintable_DLambdaSsm.hpp | 0 .../ISyntaxStateMachine_DLambdaSsm.hpp | 0 src/reader2/CMakeLists.txt | 4 ++-- src/reader2/DToplevelSeqSsm.cpp | 11 ++++++----- src/reader2/{ => facet}/IPrintable_DLambdaSsm.cpp | 2 +- .../{ => facet}/ISyntaxStateMachine_DLambdaSsm.cpp | 2 +- 10 files changed, 17 insertions(+), 16 deletions(-) rename include/xo/reader2/{ => lambda}/DLambdaSsm.hpp (100%) rename include/xo/reader2/{ssm => lambda}/IPrintable_DLambdaSsm.hpp (100%) rename include/xo/reader2/{ssm => lambda}/ISyntaxStateMachine_DLambdaSsm.hpp (100%) rename src/reader2/{ => facet}/IPrintable_DLambdaSsm.cpp (93%) rename src/reader2/{ => facet}/ISyntaxStateMachine_DLambdaSsm.cpp (98%) diff --git a/idl/IPrintable_DLambdaSsm.json5 b/idl/IPrintable_DLambdaSsm.json5 index 035f71f1..3f625a27 100644 --- a/idl/IPrintable_DLambdaSsm.json5 +++ b/idl/IPrintable_DLambdaSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "lambda", includes: [ "", "" ], local_types: [], diff --git a/idl/ISyntaxStateMachine_DLambdaSsm.json5 b/idl/ISyntaxStateMachine_DLambdaSsm.json5 index 413c64c8..951c511f 100644 --- a/idl/ISyntaxStateMachine_DLambdaSsm.json5 +++ b/idl/ISyntaxStateMachine_DLambdaSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "lambda", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/include/xo/reader2/LambdaSsm.hpp b/include/xo/reader2/LambdaSsm.hpp index 49ac731b..25e7a2e4 100644 --- a/include/xo/reader2/LambdaSsm.hpp +++ b/include/xo/reader2/LambdaSsm.hpp @@ -3,8 +3,8 @@ * @author Roland Conybeare, Feb 2026 **/ -#include "DLambdaSsm.hpp" -#include "ssm/ISyntaxStateMachine_DLambdaSsm.hpp" -#include "ssm/IPrintable_DLambdaSsm.hpp" +#include "lambda/DLambdaSsm.hpp" +#include "lambda/ISyntaxStateMachine_DLambdaSsm.hpp" +#include "lambda/IPrintable_DLambdaSsm.hpp" /* end LambdaSsm.hpp */ diff --git a/include/xo/reader2/DLambdaSsm.hpp b/include/xo/reader2/lambda/DLambdaSsm.hpp similarity index 100% rename from include/xo/reader2/DLambdaSsm.hpp rename to include/xo/reader2/lambda/DLambdaSsm.hpp diff --git a/include/xo/reader2/ssm/IPrintable_DLambdaSsm.hpp b/include/xo/reader2/lambda/IPrintable_DLambdaSsm.hpp similarity index 100% rename from include/xo/reader2/ssm/IPrintable_DLambdaSsm.hpp rename to include/xo/reader2/lambda/IPrintable_DLambdaSsm.hpp diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp similarity index 100% rename from include/xo/reader2/ssm/ISyntaxStateMachine_DLambdaSsm.hpp rename to include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 66a5e8f8..a6293f3f 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -38,8 +38,8 @@ set(SELF_SRCS IPrintable_DSequenceSsm.cpp DLambdaSsm.cpp - ISyntaxStateMachine_DLambdaSsm.cpp - IPrintable_DLambdaSsm.cpp + facet/ISyntaxStateMachine_DLambdaSsm.cpp + facet/IPrintable_DLambdaSsm.cpp DApplySsm.cpp ISyntaxStateMachine_DApplySsm.cpp diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index f43d1a62..17365193 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -7,7 +7,8 @@ #include "ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp" #include "DDefineSsm.hpp" #include "DDeftypeSsm.hpp" -#include "DLambdaSsm.hpp" +#include "LambdaSsm.hpp" +//#include "lambda/DLambdaSsm.hpp" #include "ProgressSsm.hpp" #include "IfElseSsm.hpp" //#include "ifelse/DIfElseSsm.hpp" @@ -24,13 +25,13 @@ #include namespace xo { - using xo::scm::DProgressSsm; + //using xo::scm::DProgressSsm; using xo::scm::DConstant; - using xo::scm::DFloat; + //using xo::scm::DFloat; using xo::mm::AGCObject; - using xo::mm::AAllocator; + //using xo::mm::AAllocator; using xo::mm::DArena; - using xo::facet::with_facet; + //using xo::facet::with_facet; using xo::reflect::typeseq; namespace scm { diff --git a/src/reader2/IPrintable_DLambdaSsm.cpp b/src/reader2/facet/IPrintable_DLambdaSsm.cpp similarity index 93% rename from src/reader2/IPrintable_DLambdaSsm.cpp rename to src/reader2/facet/IPrintable_DLambdaSsm.cpp index 4e7a09d8..bd1437bd 100644 --- a/src/reader2/IPrintable_DLambdaSsm.cpp +++ b/src/reader2/facet/IPrintable_DLambdaSsm.cpp @@ -11,7 +11,7 @@ * [idl/IPrintable_DLambdaSsm.json5] **/ -#include "ssm/IPrintable_DLambdaSsm.hpp" +#include "lambda/IPrintable_DLambdaSsm.hpp" namespace xo { namespace scm { diff --git a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp similarity index 98% rename from src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp rename to src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp index e131c12d..098e49c3 100644 --- a/src/reader2/ISyntaxStateMachine_DLambdaSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp @@ -11,7 +11,7 @@ * [idl/ISyntaxStateMachine_DLambdaSsm.json5] **/ -#include "ssm/ISyntaxStateMachine_DLambdaSsm.hpp" +#include "lambda/ISyntaxStateMachine_DLambdaSsm.hpp" namespace xo { namespace scm { From af978694ac4180147fc0b6aaa2b04e021695b30a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 10:32:31 -0500 Subject: [PATCH 277/342] xo-reader2: refactor: move deftype impl to deftype/ subdir --- idl/IPrintable_DDeftypeSsm.json5 | 4 ++-- idl/ISyntaxStateMachine_DDeftypeSsm.json5 | 4 ++-- include/xo/reader2/DeftypeSsm.hpp | 6 +++--- include/xo/reader2/{ => deftype}/DDeftypeSsm.hpp | 0 .../xo/reader2/{ssm => deftype}/IPrintable_DDeftypeSsm.hpp | 0 .../{ssm => deftype}/ISyntaxStateMachine_DDeftypeSsm.hpp | 0 src/reader2/CMakeLists.txt | 4 ++-- src/reader2/DToplevelSeqSsm.cpp | 4 +--- src/reader2/{ => facet}/IPrintable_DDeftypeSsm.cpp | 2 +- src/reader2/{ => facet}/ISyntaxStateMachine_DDeftypeSsm.cpp | 2 +- 10 files changed, 12 insertions(+), 14 deletions(-) rename include/xo/reader2/{ => deftype}/DDeftypeSsm.hpp (100%) rename include/xo/reader2/{ssm => deftype}/IPrintable_DDeftypeSsm.hpp (100%) rename include/xo/reader2/{ssm => deftype}/ISyntaxStateMachine_DDeftypeSsm.hpp (100%) rename src/reader2/{ => facet}/IPrintable_DDeftypeSsm.cpp (93%) rename src/reader2/{ => facet}/ISyntaxStateMachine_DDeftypeSsm.cpp (98%) diff --git a/idl/IPrintable_DDeftypeSsm.json5 b/idl/IPrintable_DDeftypeSsm.json5 index e61f5881..00b81fdb 100644 --- a/idl/IPrintable_DDeftypeSsm.json5 +++ b/idl/IPrintable_DDeftypeSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "deftype", includes: [ "", "" ], local_types: [], diff --git a/idl/ISyntaxStateMachine_DDeftypeSsm.json5 b/idl/ISyntaxStateMachine_DDeftypeSsm.json5 index d3e3b174..722e3409 100644 --- a/idl/ISyntaxStateMachine_DDeftypeSsm.json5 +++ b/idl/ISyntaxStateMachine_DDeftypeSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "deftype", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/include/xo/reader2/DeftypeSsm.hpp b/include/xo/reader2/DeftypeSsm.hpp index 22ec3eec..324875ba 100644 --- a/include/xo/reader2/DeftypeSsm.hpp +++ b/include/xo/reader2/DeftypeSsm.hpp @@ -5,8 +5,8 @@ #pragma once -#include "DDeftypeSsm.hpp" -#include "ssm/ISyntaxStateMachine_DDeftypeSsm.hpp" -#include "ssm/IPrintable_DDeftypeSsm.hpp" +#include "deftype/DDeftypeSsm.hpp" +#include "deftype/ISyntaxStateMachine_DDeftypeSsm.hpp" +#include "deftype/IPrintable_DDeftypeSsm.hpp" /* end DeftypeSsm.hpp */ diff --git a/include/xo/reader2/DDeftypeSsm.hpp b/include/xo/reader2/deftype/DDeftypeSsm.hpp similarity index 100% rename from include/xo/reader2/DDeftypeSsm.hpp rename to include/xo/reader2/deftype/DDeftypeSsm.hpp diff --git a/include/xo/reader2/ssm/IPrintable_DDeftypeSsm.hpp b/include/xo/reader2/deftype/IPrintable_DDeftypeSsm.hpp similarity index 100% rename from include/xo/reader2/ssm/IPrintable_DDeftypeSsm.hpp rename to include/xo/reader2/deftype/IPrintable_DDeftypeSsm.hpp diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDeftypeSsm.hpp b/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp similarity index 100% rename from include/xo/reader2/ssm/ISyntaxStateMachine_DDeftypeSsm.hpp rename to include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index a6293f3f..6f610db0 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -26,8 +26,8 @@ set(SELF_SRCS IPrintable_DDefineSsm.cpp DDeftypeSsm.cpp - ISyntaxStateMachine_DDeftypeSsm.cpp - IPrintable_DDeftypeSsm.cpp + facet/ISyntaxStateMachine_DDeftypeSsm.cpp + facet/IPrintable_DDeftypeSsm.cpp DIfElseSsm.cpp facet/ISyntaxStateMachine_DIfElseSsm.cpp diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index 17365193..2b5b0dcb 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -6,12 +6,10 @@ #include "DToplevelSeqSsm.hpp" #include "ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp" #include "DDefineSsm.hpp" -#include "DDeftypeSsm.hpp" +#include "DeftypeSsm.hpp" #include "LambdaSsm.hpp" -//#include "lambda/DLambdaSsm.hpp" #include "ProgressSsm.hpp" #include "IfElseSsm.hpp" -//#include "ifelse/DIfElseSsm.hpp" #include "QuoteSsm.hpp" #include "ParenSsm.hpp" #include "ExpectExprSsm.hpp" diff --git a/src/reader2/IPrintable_DDeftypeSsm.cpp b/src/reader2/facet/IPrintable_DDeftypeSsm.cpp similarity index 93% rename from src/reader2/IPrintable_DDeftypeSsm.cpp rename to src/reader2/facet/IPrintable_DDeftypeSsm.cpp index 8f36fd09..eb7351d2 100644 --- a/src/reader2/IPrintable_DDeftypeSsm.cpp +++ b/src/reader2/facet/IPrintable_DDeftypeSsm.cpp @@ -11,7 +11,7 @@ * [idl/IPrintable_DDeftypeSsm.json5] **/ -#include "ssm/IPrintable_DDeftypeSsm.hpp" +#include "deftype/IPrintable_DDeftypeSsm.hpp" namespace xo { namespace scm { diff --git a/src/reader2/ISyntaxStateMachine_DDeftypeSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp similarity index 98% rename from src/reader2/ISyntaxStateMachine_DDeftypeSsm.cpp rename to src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp index 9fcc835f..2491eee2 100644 --- a/src/reader2/ISyntaxStateMachine_DDeftypeSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp @@ -11,7 +11,7 @@ * [idl/ISyntaxStateMachine_DDeftypeSsm.json5] **/ -#include "ssm/ISyntaxStateMachine_DDeftypeSsm.hpp" +#include "deftype/ISyntaxStateMachine_DDeftypeSsm.hpp" namespace xo { namespace scm { From 6a0333765a54976c00d2ce13bd254134bb54d24a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 10:42:42 -0500 Subject: [PATCH 278/342] xo-reader2: refactor: move apply genfacet to subdirs --- idl/IPrintable_DApplySsm.json5 | 4 ++-- idl/ISyntaxStateMachine_DApplySsm.json5 | 4 ++-- include/xo/reader2/ApplySsm.hpp | 6 +++--- include/xo/reader2/{ => apply}/DApplySsm.hpp | 0 include/xo/reader2/{ssm => apply}/IPrintable_DApplySsm.hpp | 0 .../{ssm => apply}/ISyntaxStateMachine_DApplySsm.hpp | 0 src/reader2/CMakeLists.txt | 4 ++-- src/reader2/{ => facet}/IPrintable_DApplySsm.cpp | 2 +- src/reader2/{ => facet}/ISyntaxStateMachine_DApplySsm.cpp | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) rename include/xo/reader2/{ => apply}/DApplySsm.hpp (100%) rename include/xo/reader2/{ssm => apply}/IPrintable_DApplySsm.hpp (100%) rename include/xo/reader2/{ssm => apply}/ISyntaxStateMachine_DApplySsm.hpp (100%) rename src/reader2/{ => facet}/IPrintable_DApplySsm.cpp (94%) rename src/reader2/{ => facet}/ISyntaxStateMachine_DApplySsm.cpp (98%) diff --git a/idl/IPrintable_DApplySsm.json5 b/idl/IPrintable_DApplySsm.json5 index 6f2a531d..37330b12 100644 --- a/idl/IPrintable_DApplySsm.json5 +++ b/idl/IPrintable_DApplySsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "apply", includes: [ "", "" ], local_types: [], diff --git a/idl/ISyntaxStateMachine_DApplySsm.json5 b/idl/ISyntaxStateMachine_DApplySsm.json5 index bc433fdf..80df12c7 100644 --- a/idl/ISyntaxStateMachine_DApplySsm.json5 +++ b/idl/ISyntaxStateMachine_DApplySsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "apply", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/include/xo/reader2/ApplySsm.hpp b/include/xo/reader2/ApplySsm.hpp index 6e9f9a9d..9ddc5b5a 100644 --- a/include/xo/reader2/ApplySsm.hpp +++ b/include/xo/reader2/ApplySsm.hpp @@ -5,8 +5,8 @@ #pragma once -#include "DApplySsm.hpp" -#include "ssm/ISyntaxStateMachine_DApplySsm.hpp" -#include "ssm/IPrintable_DApplySsm.hpp" +#include "apply/DApplySsm.hpp" +#include "apply/ISyntaxStateMachine_DApplySsm.hpp" +#include "apply/IPrintable_DApplySsm.hpp" /* end ApplySsm.hpp */ diff --git a/include/xo/reader2/DApplySsm.hpp b/include/xo/reader2/apply/DApplySsm.hpp similarity index 100% rename from include/xo/reader2/DApplySsm.hpp rename to include/xo/reader2/apply/DApplySsm.hpp diff --git a/include/xo/reader2/ssm/IPrintable_DApplySsm.hpp b/include/xo/reader2/apply/IPrintable_DApplySsm.hpp similarity index 100% rename from include/xo/reader2/ssm/IPrintable_DApplySsm.hpp rename to include/xo/reader2/apply/IPrintable_DApplySsm.hpp diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp b/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp similarity index 100% rename from include/xo/reader2/ssm/ISyntaxStateMachine_DApplySsm.hpp rename to include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 6f610db0..455fadee 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -42,8 +42,8 @@ set(SELF_SRCS facet/IPrintable_DLambdaSsm.cpp DApplySsm.cpp - ISyntaxStateMachine_DApplySsm.cpp - IPrintable_DApplySsm.cpp + facet/ISyntaxStateMachine_DApplySsm.cpp + facet/IPrintable_DApplySsm.cpp DParenSsm.cpp ISyntaxStateMachine_DParenSsm.cpp diff --git a/src/reader2/IPrintable_DApplySsm.cpp b/src/reader2/facet/IPrintable_DApplySsm.cpp similarity index 94% rename from src/reader2/IPrintable_DApplySsm.cpp rename to src/reader2/facet/IPrintable_DApplySsm.cpp index 5066b082..20e40bfc 100644 --- a/src/reader2/IPrintable_DApplySsm.cpp +++ b/src/reader2/facet/IPrintable_DApplySsm.cpp @@ -11,7 +11,7 @@ * [idl/IPrintable_DApplySsm.json5] **/ -#include "ssm/IPrintable_DApplySsm.hpp" +#include "apply/IPrintable_DApplySsm.hpp" namespace xo { namespace scm { diff --git a/src/reader2/ISyntaxStateMachine_DApplySsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp similarity index 98% rename from src/reader2/ISyntaxStateMachine_DApplySsm.cpp rename to src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp index cd1a550d..abe625c8 100644 --- a/src/reader2/ISyntaxStateMachine_DApplySsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp @@ -11,7 +11,7 @@ * [idl/ISyntaxStateMachine_DApplySsm.json5] **/ -#include "ssm/ISyntaxStateMachine_DApplySsm.hpp" +#include "apply/ISyntaxStateMachine_DApplySsm.hpp" namespace xo { namespace scm { From 46637ec16a2eb84b190c94220a731a381ea4a246 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 14:13:48 -0500 Subject: [PATCH 279/342] xo-reader2: parse list types + utest --- CMakeLists.txt | 16 ++ idl/IPrintable_DExpectListTypeSsm.json5 | 16 ++ ...yntaxStateMachine_DExpectListTypeSsm.json5 | 16 ++ include/xo/reader2/DExpectQArraySsm.hpp | 10 +- include/xo/reader2/DExpectTypeSsm.hpp | 21 +- include/xo/reader2/ExpectListTypeSsm.hpp | 12 + .../expect_listtype/DExpectListTypeSsm.hpp | 149 +++++++++++++ .../IPrintable_DExpectListTypeSsm.hpp | 62 ++++++ ...ISyntaxStateMachine_DExpectListTypeSsm.hpp | 84 +++++++ include/xo/reader2/ifelse/DIfElseSsm.hpp | 13 +- include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 4 + src/reader2/DExpectListTypeSsm.cpp | 207 ++++++++++++++++++ src/reader2/DExpectTypeSsm.cpp | 45 ++-- .../facet/IPrintable_DExpectListTypeSsm.cpp | 28 +++ ...ISyntaxStateMachine_DExpectListTypeSsm.cpp | 84 +++++++ src/reader2/reader2_register_facets.cpp | 5 + src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 42 ++++ 19 files changed, 786 insertions(+), 33 deletions(-) create mode 100644 idl/IPrintable_DExpectListTypeSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DExpectListTypeSsm.json5 create mode 100644 include/xo/reader2/ExpectListTypeSsm.hpp create mode 100644 include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp create mode 100644 include/xo/reader2/expect_listtype/IPrintable_DExpectListTypeSsm.hpp create mode 100644 include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp create mode 100644 src/reader2/DExpectListTypeSsm.cpp create mode 100644 src/reader2/facet/IPrintable_DExpectListTypeSsm.cpp create mode 100644 src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 42869a58..faf792a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,6 +225,22 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expectlisttypessm + FACET_PKG xo_reader2 + INPUT idl/ISyntaxStateMachine_DExpectListTypeSsm.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expectlisttypessm + FACET_PKG xo_printable2 + INPUT idl/IPrintable_DExpectListTypeSsm.json5 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectexprssm diff --git a/idl/IPrintable_DExpectListTypeSsm.json5 b/idl/IPrintable_DExpectListTypeSsm.json5 new file mode 100644 index 00000000..2403eb59 --- /dev/null +++ b/idl/IPrintable_DExpectListTypeSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2/facet", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "expect_listtype", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectListTypeSsm", + using_doxygen: true, + repr: "DExpectListTypeSsm", + doc: [ "implement APrintable for DExpectListTypeSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DExpectListTypeSsm.json5 b/idl/ISyntaxStateMachine_DExpectListTypeSsm.json5 new file mode 100644 index 00000000..9a616675 --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectListTypeSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2/facet", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "expect_listtype", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectListTypeSsm", + using_doxygen: true, + repr: "DExpectListTypeSsm", + doc: [ "implement ASyntaxStateMachine for DExpectListTypeSsm" ], +} \ No newline at end of file diff --git a/include/xo/reader2/DExpectQArraySsm.hpp b/include/xo/reader2/DExpectQArraySsm.hpp index 5316ee34..929460dc 100644 --- a/include/xo/reader2/DExpectQArraySsm.hpp +++ b/include/xo/reader2/DExpectQArraySsm.hpp @@ -16,13 +16,13 @@ namespace xo { * Already in quoted-literal context * * [ quote-expr ... ] - * ^ ^ ^ - * | qarray_1a qarray_2(done) - * qarray_0 + * ^ ^ ^ ^ + * | qarray_1a | qarray_2(done) + * qarray_0 qarray_1a * - * qarray_0 --on_leftbrace_token()--> qarray_1a [push ExpectQLiteralSsm] + * qarray_0 --on_leftbracket_token()--> qarray_1a [push ExpectQLiteralSsm] * qarray_1a --on_quoted_literal()--> qarray_1a [append literal] - * qarray_1a --on_rightbrace_token()--> qarray_2(done) [report quoted array] + * qarray_1a --on_rightbracket_token()--> qarray_2(done) [report quoted array] **/ class QArrayXst { public: diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index aba12f8d..2901c95a 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -14,12 +14,14 @@ namespace xo { /** @class DExpectTypeSsm * @brief syntax state-machine for accepting a Schemtika typename-expression * - * Jan 2026 - * Placeholder implementation at present. - * Only types are a handful of baked-in values - * * @pre - * + * any universal polymorphic type + * unit empty type (like c/c++ void) + * f64 64-bit float + * i32 32-bit signed integer + * list parameterized list (polymorphic if T is any) + * array parameterized array (polymorphic if T is any) + * function function (U x ...) -> T * @endpre **/ class DExpectTypeSsm : public DSyntaxStateMachine { @@ -30,17 +32,26 @@ namespace xo { using ppindentinfo = xo::print::ppindentinfo; public: + /** @defgroup scm-expecttype-ctors constructors **/ + ///@{ + explicit DExpectTypeSsm(bool corrected); + /** create instance **/ static DExpectTypeSsm * _make(DArena & parser_mm, bool corrected); /** create fop referring to new DExpectTypeSsm **/ static obj make(DArena & parser_mm, bool corrected); + ///@} + /** @defgroup scm-expecttype-general-methods general methods **/ + ///@{ + static void start(bool corrected, ParserStateMachine * p_psm); static const char * ssm_classname() { return "DExpectTypeSsm"; } + ///@} /** @defgroup scm-expecttype-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/include/xo/reader2/ExpectListTypeSsm.hpp b/include/xo/reader2/ExpectListTypeSsm.hpp new file mode 100644 index 00000000..63f388a3 --- /dev/null +++ b/include/xo/reader2/ExpectListTypeSsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectListTypeSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "expect_listtype/DExpectListTypeSsm.hpp" +#include "expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp" +#include "expect_listtype/IPrintable_DExpectListTypeSsm.hpp" + +/* end ExpectListTypeSsm.hpp */ diff --git a/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp b/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp new file mode 100644 index 00000000..38f04ca1 --- /dev/null +++ b/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp @@ -0,0 +1,149 @@ +/** @file DExpectListTypeSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" + +namespace xo { + namespace scm { + + /** + * list < type-expr > + * ^ ^ ^ ^ ^ + * | | | | (done) + * | | | type_3 --on_rightangle_token() --> (done) [pop + report listtype] + * | | type_2 --on_parsed_type()--> type_3 + * | type_1 --on_leftangle_token() --> type_2 [push ExpectTypeSsm] + * type_0 --on_symbol_token()--> type_1 + * + **/ + class ListTypeXst { + public: + enum class code { + invalid = -1, + + type_0, + type_1, + type_2, + type_3, + + N, + }; + + explicit ListTypeXst(code x) : code_{x} {} + + /** @return string representation for enum @p x **/ + static const char * _descr(code x); + + code code() const noexcept { return code_; } + + enum code code_; + }; + + inline std::ostream & + operator<<(std::ostream & os, ListTypeXst x) { + os << ListTypeXst::_descr(x.code_); + return os; + } + + /** @class DExpectListTypeSsm + * @brief parser state-machine for a list type + * + * Examples: + * @pre + * list + * list> + * @endpre + **/ + class DExpectListTypeSsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using TypeDescr = xo::reflect::TypeDescr; + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; + + public: + /** default ctor **/ + explicit DExpectListTypeSsm(); + + /** create instance. Get memory from @p parser_mm **/ + static DExpectListTypeSsm * _make(DArena & parser_mm); + + /** create instance as fop. Get memory from @p parser_mm **/ + static obj make(DArena & parser_mm); + + /** start nested state machine to parse a list type **/ + static void start(ParserStateMachine * p_psm); + + /** @defgroup scm-expectlisttypessm-expression-methods general methods **/ + ///@{ + + static const char * ssm_classname() { return "DExpectListTypeSsm"; } + + syntaxstatetype ssm_type() const noexcept; + + std::string_view get_expect_str() const noexcept; + + /** update ssm for symbol token @p tk, with overall parsing state in @p p_psm. + * in state type_0: advance to type_1. + * otherwise error + **/ + void on_symbol_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update ssm for leftangle (<) token @p tk, with overall parser state in @p p_psm. + * in state type_1: advance to type_2, pushing nested ExpectTypeSsm. + * otherwise error. + **/ + void on_leftangle_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update ssm for rightangle (>) token @p tk, with overall parser state in @p p_psm. + * in state type_3: aseemble list type, report completed syntax to parent ssm + **/ + void on_rightangle_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectlisttypessm-expression-facet expression facet methods **/ + ///@{ + + /** update ssm for token @p tk, with overall state in @p p_psm **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update ssm for type @p type produced by nested ssm, with overall parser + * state in @p p_psm. + * in state type_2: @p type is element type for target list type. + * otherwise error. + **/ + void on_parsed_type(obj type, ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectlisttypessm-printable-facet printable facet methods **/ + ///@{ + + /** pretty-printing support **/ + bool pretty(const ppindentinfo & ppii) const; + + ///@} + private: + /** @defgroup scm-expectlisttypessm-instance-vars instance variables **/ + ///@{ + + /** local parsing state **/ + ListTypeXst state_{ListTypeXst::code::type_0}; + + /** element type for target list type **/ + obj elt_type_; + + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectListTypeSsm.hpp */ diff --git a/include/xo/reader2/expect_listtype/IPrintable_DExpectListTypeSsm.hpp b/include/xo/reader2/expect_listtype/IPrintable_DExpectListTypeSsm.hpp new file mode 100644 index 00000000..b799d6ca --- /dev/null +++ b/include/xo/reader2/expect_listtype/IPrintable_DExpectListTypeSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectListTypeSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectListTypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectListTypeSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectListTypeSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectListTypeSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectListTypeSsm + **/ + class IPrintable_DExpectListTypeSsm { + public: + /** @defgroup scm-printable-dexpectlisttypessm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpectlisttypessm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectListTypeSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp b/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp new file mode 100644 index 00000000..37a653f9 --- /dev/null +++ b/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp @@ -0,0 +1,84 @@ +/** @file ISyntaxStateMachine_DExpectListTypeSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectListTypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectListTypeSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectListTypeSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectListTypeSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectListTypeSsm + **/ + class ISyntaxStateMachine_DExpectListTypeSsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpectlisttypessm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexpectlisttypessm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectListTypeSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectListTypeSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectListTypeSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectListTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectListTypeSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DExpectListTypeSsm & self, obj type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectListTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DExpectListTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExpectListTypeSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for nested parsed expression @p expr **/ + static void on_parsed_expression(DExpectListTypeSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExpectListTypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectListTypeSsm & self, obj lit, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ifelse/DIfElseSsm.hpp b/include/xo/reader2/ifelse/DIfElseSsm.hpp index 345f3fa5..cded3e6f 100644 --- a/include/xo/reader2/ifelse/DIfElseSsm.hpp +++ b/include/xo/reader2/ifelse/DIfElseSsm.hpp @@ -85,14 +85,14 @@ namespace xo { obj expr_mm, ParserStateMachine * p_psm); - static const char * ssm_classname() { return "DIfElseSsm"; } - - DSyntaxStateMachine * super() { return this; } - ///@} /** @defgroup scm-ifelsessm-expression-methods general methods **/ ///@{ + static const char * ssm_classname() { return "DIfElseSsm"; } + + DSyntaxStateMachine * super() { return this; } + /** operate state machine on if-token input @p tk, * with overall parser state in @p p_psm **/ @@ -178,6 +178,9 @@ namespace xo { #endif private: + /** @defgroup scm-expectlisttypessm-instance-vars instance variables **/ + ///@{ + ifexprstatetype ifstate_ = ifexprstatetype::invalid; /** scaffold ifelse-expression here. * This will eventually be the output of this ssm @@ -186,6 +189,8 @@ namespace xo { **/ obj if_expr_; + ///@} + }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index a01dcb62..dd34054a 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -60,6 +60,9 @@ namespace xo { /** expecting a type. See @ref DExpectTypeSsm **/ expect_type, + /** expecting a list type. See @ref DExpectListTypeSsm **/ + expect_listtype, + /** expecting a rhs expression. See @ref DExpectExprSsm **/ expect_rhs_expression, diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 455fadee..af8bf4af 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -65,6 +65,10 @@ set(SELF_SRCS ISyntaxStateMachine_DExpectTypeSsm.cpp IPrintable_DExpectTypeSsm.cpp + DExpectListTypeSsm.cpp + facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp + facet/IPrintable_DExpectListTypeSsm.cpp + DExpectExprSsm.cpp ISyntaxStateMachine_DExpectExprSsm.cpp IPrintable_DExpectExprSsm.cpp diff --git a/src/reader2/DExpectListTypeSsm.cpp b/src/reader2/DExpectListTypeSsm.cpp new file mode 100644 index 00000000..3b040962 --- /dev/null +++ b/src/reader2/DExpectListTypeSsm.cpp @@ -0,0 +1,207 @@ +/** @file DExpectListTypeSsm.cpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#include "ExpectListTypeSsm.hpp" +#include "ExpectTypeSsm.hpp" +#include "syntaxstatetype.hpp" +#include +#include + +namespace xo { + namespace scm { + + const char * + ListTypeXst::_descr(enum code x) + { + switch (x) { + case code::invalid: return "?invalid"; + case code::type_0: return "type_0"; + case code::type_1: return "type_1"; + case code::type_2: return "type_2"; + case code::type_3: return "type_3"; + case code::N: break; + } + + return "?ListTypeXst"; + } + + DExpectListTypeSsm::DExpectListTypeSsm() = default; + + DExpectListTypeSsm * + DExpectListTypeSsm::_make(DArena & parser_mm) + { + void * mem = parser_mm.alloc_for(); + + return new (mem) DExpectListTypeSsm(); + } + + obj + DExpectListTypeSsm::make(DArena & parser_mm) + { + return obj(_make(parser_mm)); + } + + void + DExpectListTypeSsm::start(ParserStateMachine * p_psm) + { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DExpectListTypeSsm::make(p_psm->parser_alloc())); + } + + syntaxstatetype + DExpectListTypeSsm::ssm_type() const noexcept + { + return syntaxstatetype::expect_listtype; + } + + std::string_view + DExpectListTypeSsm::get_expect_str() const noexcept + { + switch(state_.code()) { + case ListTypeXst::code::invalid: + case ListTypeXst::code::N: + break; + case ListTypeXst::code::type_0: + return "list"; + case ListTypeXst::code::type_1: + return "leftangle"; + case ListTypeXst::code::type_2: + return "type"; + case ListTypeXst::code::type_3: + return "rightangle"; + } + + return "?ExpectListTypeSsm"; + } + + void + DExpectListTypeSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (tk.tk_type()) { + + case tokentype::tk_symbol: + this->on_symbol_token(tk, p_psm); + return; + + case tokentype::tk_leftangle: + this->on_leftangle_token(tk, p_psm); + return; + + case tokentype::tk_rightangle: + this->on_rightangle_token(tk, p_psm); + return; + + // all the {not-yet-handled, illegal} cases + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_quote: + case tokentype::tk_def: + case tokentype::tk_deftype: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_if: + case tokentype::tk_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_lambda: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectListTypeSsm::on_symbol_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == ListTypeXst::code::type_0) { + this->state_ = ListTypeXst(ListTypeXst::code::type_1); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectListTypeSsm::on_leftangle_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == ListTypeXst::code::type_1) { + this->state_ = ListTypeXst(ListTypeXst::code::type_2); + DExpectTypeSsm::start(true /*corrected*/, p_psm); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectListTypeSsm::on_parsed_type(obj type, ParserStateMachine * p_psm) + { + if (state_.code() == ListTypeXst::code::type_2) { + this->state_ = ListTypeXst(ListTypeXst::code::type_3); + this->elt_type_ = type; + return; + } + + Super::illegal_type(type, p_psm); + } + + void + DExpectListTypeSsm::on_rightangle_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == ListTypeXst::code::type_3) { + obj result = DListType::make(p_psm->expr_alloc(), + elt_type_); + p_psm->pop_ssm(); + p_psm->on_parsed_type(result); + return; + } + + Super::illegal_token(tk, p_psm); + } + + bool + DExpectListTypeSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct + (ppii, + "DExpectListTypeSsm"); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectListTypeSsm.cpp */ diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index edd71d66..600b7650 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -4,7 +4,7 @@ **/ #include "ExpectTypeSsm.hpp" -//#include "ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp" +#include "ExpectListTypeSsm.hpp" #include "SyntaxStateMachine.hpp" #include #include @@ -132,25 +132,32 @@ namespace xo { obj type; obj mm = p_psm->expr_alloc(); - if (tk.text() == "unit") - type = DAtomicType::make(mm, Metatype::t_unit()); - if (tk.text() == "bool") - type = DAtomicType::make(mm, Metatype::t_bool()); - else if (tk.text() == "str") - type = DAtomicType::make(mm, Metatype::t_str()); - else if (tk.text() == "f64") - type = DAtomicType::make(mm, Metatype::t_f64()); - else if(tk.text() == "f32") - type = DAtomicType::make(mm, Metatype::t_f32()); - else if(tk.text() == "i16") - type = DAtomicType::make(mm, Metatype::t_i16()); - else if(tk.text() == "i32") - type = DAtomicType::make(mm, Metatype::t_i32()); - else if(tk.text() == "i64") - type = DAtomicType::make(mm, Metatype::t_i64()); + if (tk.text() == "list") { + /* replace top ssm with specialized list-type ssm parser */ + p_psm->pop_ssm(); + DExpectListTypeSsm::start(p_psm); + p_psm->on_token(tk); + } else { + if (tk.text() == "unit") + type = DAtomicType::make(mm, Metatype::t_unit()); + if (tk.text() == "bool") + type = DAtomicType::make(mm, Metatype::t_bool()); + else if (tk.text() == "str") + type = DAtomicType::make(mm, Metatype::t_str()); + else if (tk.text() == "f64") + type = DAtomicType::make(mm, Metatype::t_f64()); + else if(tk.text() == "f32") + type = DAtomicType::make(mm, Metatype::t_f32()); + else if(tk.text() == "i16") + type = DAtomicType::make(mm, Metatype::t_i16()); + else if(tk.text() == "i32") + type = DAtomicType::make(mm, Metatype::t_i32()); + else if(tk.text() == "i64") + type = DAtomicType::make(mm, Metatype::t_i64()); - p_psm->pop_ssm(); - p_psm->on_parsed_type(type); + p_psm->pop_ssm(); + p_psm->on_parsed_type(type); + } } else { TypeDescr td = nullptr; diff --git a/src/reader2/facet/IPrintable_DExpectListTypeSsm.cpp b/src/reader2/facet/IPrintable_DExpectListTypeSsm.cpp new file mode 100644 index 00000000..8f90fad5 --- /dev/null +++ b/src/reader2/facet/IPrintable_DExpectListTypeSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectListTypeSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectListTypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectListTypeSsm.json5] +**/ + +#include "expect_listtype/IPrintable_DExpectListTypeSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectListTypeSsm::pretty(const DExpectListTypeSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectListTypeSsm.cpp */ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp new file mode 100644 index 00000000..bd8ac996 --- /dev/null +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp @@ -0,0 +1,84 @@ +/** @file ISyntaxStateMachine_DExpectListTypeSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectListTypeSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectListTypeSsm.json5] +**/ + +#include "expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectListTypeSsm::ssm_type(const DExpectListTypeSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectListTypeSsm::get_expect_str(const DExpectListTypeSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectListTypeSsm::on_token(DExpectListTypeSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectListTypeSsm::on_parsed_symbol(DExpectListTypeSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExpectListTypeSsm::on_parsed_typedescr(DExpectListTypeSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DExpectListTypeSsm::on_parsed_type(DExpectListTypeSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto + ISyntaxStateMachine_DExpectListTypeSsm::on_parsed_formal(DExpectListTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DExpectListTypeSsm::on_parsed_formal_with_token(DExpectListTypeSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectListTypeSsm::on_parsed_formal_arglist(DExpectListTypeSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DExpectListTypeSsm::on_parsed_expression(DExpectListTypeSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DExpectListTypeSsm::on_parsed_expression_with_token(DExpectListTypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectListTypeSsm::on_quoted_literal(DExpectListTypeSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectListTypeSsm.cpp */ diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index 5262c1e9..dc9915ef 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -21,6 +21,7 @@ #include "ExpectFormalArgSsm.hpp" #include "ExpectSymbolSsm.hpp" #include "ExpectTypeSsm.hpp" +#include "ExpectListTypeSsm.hpp" #include "ExpectExprSsm.hpp" #include "ExpectQLiteralSsm.hpp" #include "ExpectQListSsm.hpp" @@ -57,6 +58,7 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); FacetRegistry::register_impl(); @@ -74,6 +76,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index 4aa21b0c..5968b1bb 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -41,6 +41,8 @@ namespace xo { return "expect-symbol"; case syntaxstatetype::expect_type: return "expect-type"; + case syntaxstatetype::expect_listtype: + return "expect-listtype"; case syntaxstatetype::expect_rhs_expression: return "expect-rhs-expression"; case syntaxstatetype::expect_qliteral: diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index c2591815..3921148d 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -312,6 +312,48 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-batch-deftype-2", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_batch_session(); + + /** Walkthrough parsing input equivalent to: + * + * deftype foo :: list; + **/ + + std::vector tk_v{ + Token::deftype_token(), + Token::symbol_token("foo"), + Token::doublecolon_token(), + Token::symbol_token("list"), + Token::leftangle_token(), + Token::symbol_token("f64"), + Token::rightangle_token(), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + // placeholder for form's sake. + // deftype doesn't actuallly produce any executable content + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + + log && fixture.log_memory_layout(&log); + } + TEST_CASE("SchematikaParser-interactive-def2", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); From caa8e31d025ad962ca34e31fc5597ea0e076af26 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 14:13:48 -0500 Subject: [PATCH 280/342] xo-reader2: parse list types + utest --- include/xo/tokenizer2/Token.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index c7c43287..7537a2b0 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -90,9 +90,9 @@ namespace xo { /** token representing quote @c "'" **/ static Token quote_token() { return Token(tokentype::tk_quote); } /** token representing left angle bracket @c "<" **/ - static Token leftangle() { return Token(tokentype::tk_leftangle); } + static Token leftangle_token() { return Token(tokentype::tk_leftangle); } /** token representing right angle bracket @c ">" **/ - static Token rightangle() { return Token(tokentype::tk_rightangle); } + static Token rightangle_token() { return Token(tokentype::tk_rightangle); } /** token representing left parenthesis @c "(" **/ static Token leftparen_token() { return Token(tokentype::tk_leftparen); } /** Token representing right parenthesis @c ")" **/ From 31c32cbca7c64b2bce418a2ea9772b44f3b6ad9c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 15:40:38 -0500 Subject: [PATCH 281/342] xo-interpreter2 stack: + nth() primitive --- include/xo/reader2/DExpectQLiteralSsm.hpp | 6 ++++ src/reader2/DExpectQLiteralSsm.cpp | 18 +++++++++-- utest/SchematikaParser.test.cpp | 38 +++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/include/xo/reader2/DExpectQLiteralSsm.hpp b/include/xo/reader2/DExpectQLiteralSsm.hpp index b8452961..7073283a 100644 --- a/include/xo/reader2/DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/DExpectQLiteralSsm.hpp @@ -51,6 +51,12 @@ namespace xo { void on_f64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for i64 token @p tk, with overall parser state in @p p_psm. + * delegates to parent ssm via @ref on_quoted_literal + **/ + void on_i64_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state on incoming token @p tk, * with overall parser state in @p p_psm. * diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index 7dc30124..92309ddc 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -7,7 +7,7 @@ #include "ExpectQListSsm.hpp" #include "ExpectQArraySsm.hpp" #include -//#include "DExpectFormalArgSsm.hpp" +#include //#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" //#include //#include @@ -91,6 +91,10 @@ namespace xo { this->on_f64_token(tk, p_psm); return; + case tokentype::tk_i64: + this->on_i64_token(tk, p_psm); + return; + case tokentype::tk_leftparen: this->on_leftparen_token(tk, p_psm); return; @@ -116,7 +120,6 @@ namespace xo { case tokentype::tk_colon: case tokentype::tk_singleassign: case tokentype::tk_string: - case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_semicolon: case tokentype::tk_invalid: @@ -161,6 +164,17 @@ namespace xo { p_psm->on_quoted_literal(literal); } + void + DExpectQLiteralSsm::on_i64_token(const Token & tk, + ParserStateMachine * p_psm) + { + auto literal = DInteger::box(p_psm->expr_alloc(), + tk.i64_value()); + + p_psm->pop_ssm(); + p_psm->on_quoted_literal(literal); + } + #ifdef NOT_YET void DExpectQLiteralSsm::_accept_formal(obj expr_alloc, diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 3921148d..0b1fea58 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1401,6 +1401,44 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-batch-qlist2", "[reader2][SchematikaParser]") + { + // top-level recursive function definition + + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * #q{ (4 7.2) }; + * ^ ^ ^^ ^ ^ ^^ + * 0 1 2| 4 5 6| + * 3 7 + **/ + + std::vector tk_v{ + /* [ 0] */ Token::quote_token(), + /* [ 1] */ Token::leftbrace_token(), + /* [ 2] */ Token::leftparen_token(), + /* [ 3] */ Token::i64_token("4"), + /* [ 4] */ Token::f64_token("7.2"), + /* [ 5] */ Token::rightparen_token(), + /* [ 6] */ Token::rightbrace_token(), + /* [ 7] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); + } + TEST_CASE("SchematikaParser-batch-qarray", "[reader2][SchematikaParser]") { // top-level recursive function definition From cc42c98928c3c5132086b13426f7a24a587028f0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 16:19:40 -0500 Subject: [PATCH 282/342] xo-interpreter2: + nil + cons --- include/xo/reader2/DExpectExprSsm.hpp | 8 +++- include/xo/reader2/DToplevelSeqSsm.hpp | 5 ++ src/reader2/DApplySsm.cpp | 1 + src/reader2/DDefineSsm.cpp | 1 + src/reader2/DDeftypeSsm.cpp | 1 + src/reader2/DExpectExprSsm.cpp | 22 +++++++++ src/reader2/DExpectFormalArgSsm.cpp | 1 + src/reader2/DExpectFormalArglistSsm.cpp | 1 + src/reader2/DExpectListTypeSsm.cpp | 1 + src/reader2/DExpectQArraySsm.cpp | 1 + src/reader2/DExpectQListSsm.cpp | 1 + src/reader2/DExpectQLiteralSsm.cpp | 1 + src/reader2/DExpectSymbolSsm.cpp | 1 + src/reader2/DExpectTypeSsm.cpp | 1 + src/reader2/DIfElseSsm.cpp | 1 + src/reader2/DLambdaSsm.cpp | 1 + src/reader2/DParenSsm.cpp | 1 + src/reader2/DProgressSsm.cpp | 1 + src/reader2/DQuoteSsm.cpp | 1 + src/reader2/DSequenceSsm.cpp | 1 + src/reader2/DToplevelSeqSsm.cpp | 38 +++++++++++++-- utest/SchematikaParser.test.cpp | 63 +++++++++++++++++++++++++ 22 files changed, 148 insertions(+), 5 deletions(-) diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 539fbb39..66189754 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -84,12 +84,18 @@ namespace xo { void on_quote_token(const Token & tk, ParserStateMachine * p_psm); - /** step state machine for this syntax on incoming boolean literal token @p tkk + /** step state machine for this syntax on incoming boolean literal token @p tk * with overall parser state in @p p_psm **/ void on_bool_token(const Token & tk, ParserStateMachine * p_psm); + /** step state machine for this syntax on incoming nil literal token @p tk + * with overall parser state in @p p_psm. + **/ + void on_nil_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/DToplevelSeqSsm.hpp b/include/xo/reader2/DToplevelSeqSsm.hpp index 9bb9b076..2466ed1e 100644 --- a/include/xo/reader2/DToplevelSeqSsm.hpp +++ b/include/xo/reader2/DToplevelSeqSsm.hpp @@ -119,6 +119,11 @@ namespace xo { **/ void on_bool_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming nil token @p tk, + * overall parser state in @p p_psm + **/ + void on_nil_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming leftparen token @p tk, * overall parser state in @p p_psm **/ diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index ad9a4e50..cd591c9c 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -171,6 +171,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_let: diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 344e1fc1..2f7f99be 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -546,6 +546,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/src/reader2/DDeftypeSsm.cpp b/src/reader2/DDeftypeSsm.cpp index ec36391a..383f4fee 100644 --- a/src/reader2/DDeftypeSsm.cpp +++ b/src/reader2/DDeftypeSsm.cpp @@ -150,6 +150,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index c2d46140..f4fabfc9 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -155,6 +156,10 @@ namespace xo { this->on_bool_token(tk, p_psm); return; + case tokentype::tk_nil: + this->on_nil_token(tk, p_psm); + return; + case tokentype::tk_if: this->on_if_token(tk, p_psm); return; @@ -372,6 +377,23 @@ namespace xo { p_psm); } + void + DExpectExprSsm::on_nil_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + auto nil = DList::nil(); + auto expr = DConstant::make(p_psm->expr_alloc(), nil); + + // DProgressSsm responsible for resolving cases like + // nil ++ nil; + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); + } + void DExpectExprSsm::on_f64_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index db287abf..a17d094c 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -135,6 +135,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 67f327e1..9f7da033 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -165,6 +165,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/src/reader2/DExpectListTypeSsm.cpp b/src/reader2/DExpectListTypeSsm.cpp index 3b040962..1f42d171 100644 --- a/src/reader2/DExpectListTypeSsm.cpp +++ b/src/reader2/DExpectListTypeSsm.cpp @@ -127,6 +127,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/src/reader2/DExpectQArraySsm.cpp b/src/reader2/DExpectQArraySsm.cpp index 33ccd7c8..aa89862f 100644 --- a/src/reader2/DExpectQArraySsm.cpp +++ b/src/reader2/DExpectQArraySsm.cpp @@ -122,6 +122,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp index 9584bfea..f3f50b81 100644 --- a/src/reader2/DExpectQListSsm.cpp +++ b/src/reader2/DExpectQListSsm.cpp @@ -122,6 +122,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index 92309ddc..4cb26099 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -140,6 +140,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 79ae0622..17cdca06 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -101,6 +101,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 600b7650..9eb2b15d 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -107,6 +107,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index 5752dbdc..b915c061 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -186,6 +186,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_let: diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 9364476a..ac19c7e0 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -163,6 +163,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index d3fb5cfa..7bf28d02 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -132,6 +132,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index edb55001..be927bef 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -309,6 +309,7 @@ namespace xo { this->on_operator_token(tk, p_psm); return; + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: break; diff --git a/src/reader2/DQuoteSsm.cpp b/src/reader2/DQuoteSsm.cpp index 7f6dd00d..c61ed632 100644 --- a/src/reader2/DQuoteSsm.cpp +++ b/src/reader2/DQuoteSsm.cpp @@ -133,6 +133,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index 8bb2f779..b2b237dd 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -114,6 +114,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_let: diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index 2b5b0dcb..612f64fd 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -152,6 +153,10 @@ namespace xo { this->on_bool_token(tk, p_psm); return; + case tokentype::tk_nil: + this->on_nil_token(tk, p_psm); + return; + case tokentype::tk_leftparen: this->on_leftparen_token(tk, p_psm); return; @@ -378,7 +383,7 @@ namespace xo { break; } - Super::on_token(tk, p_psm); + Super::illegal_token(tk, p_psm); } void @@ -404,7 +409,32 @@ namespace xo { break; } - Super::on_token(tk, p_psm); + Super::illegal_token(tk, p_psm); + } + + void + DToplevelSeqSsm::on_nil_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (seqtype_) { + case exprseqtype::toplevel_interactive: + { + auto dvalue = DList::nil(); + auto expr = DConstant::make(p_psm->expr_alloc(), dvalue); + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); + return; + } + case exprseqtype::toplevel_batch: + break; + case exprseqtype::N: + assert(false); + break; + } + + Super::illegal_token(tk, p_psm); } void @@ -431,7 +461,7 @@ namespace xo { break; } - Super::on_token(tk, p_psm); + Super::illegal_token(tk, p_psm); } void @@ -454,7 +484,7 @@ namespace xo { break; } - Super::on_token(tk, p_psm); + Super::illegal_token(tk, p_psm); } void diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 0b1fea58..6f97d7a0 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ namespace xo { using xo::scm::Token; using xo::mm::AGCObject; using xo::scm::DPrimitive_gco_2_gco_gco; + using xo::scm::DList; using xo::scm::DString; using xo::scm::DFloat; using xo::scm::DInteger; @@ -603,6 +605,67 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-interactive-nil", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * nil ; + * + **/ + + { + auto & result = parser.on_token(Token::nil_token()); + + log && log("after nil token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(!result.is_error()); + REQUIRE(result.is_incomplete()); + } + + { + auto & result = parser.on_token(Token::semicolon_token()); + + log && log("after semicolon token:"); + log && log(xtag("parser", &parser)); + log && log(xtag("result", result)); + + REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(!result.is_error()); + REQUIRE(result.is_expression()); + REQUIRE(result.result_expr()); + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + + REQUIRE(expr->value()); + + auto value_list = obj::from(expr->value()); + + REQUIRE(value_list); + + REQUIRE(value_list->is_empty()); + } + + //REQUIRE(result.is_error()); + //// illegal input on token + //REQUIRE(result.error_description()); + + log && fixture.log_memory_layout(&log); + } + TEST_CASE("SchematikaParser-interactive-arith", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); From 6f95f38373e4c8d0bcf6b3de106d1422e56d2845 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Mar 2026 16:19:40 -0500 Subject: [PATCH 283/342] xo-interpreter2: + nil + cons --- include/xo/tokenizer2/Token.hpp | 2 ++ include/xo/tokenizer2/tokentype.hpp | 3 +++ src/tokenizer2/Tokenizer.cpp | 2 ++ src/tokenizer2/tokentype.cpp | 1 + 4 files changed, 8 insertions(+) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index 7537a2b0..0968a9e9 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -134,6 +134,8 @@ namespace xo { /** token for @c "==" **/ static Token cmpeq_token() { return Token(tokentype::tk_cmpeq); } + /** token representing keyword @c nil **/ + static Token nil_token() { return Token(tokentype::tk_nil); } /** token representing keyword @c type **/ static Token type() { return Token(tokentype::tk_type); } /** token representing keyword @c def **/ diff --git a/include/xo/tokenizer2/tokentype.hpp b/include/xo/tokenizer2/tokentype.hpp index d0290b05..5f7e1937 100644 --- a/include/xo/tokenizer2/tokentype.hpp +++ b/include/xo/tokenizer2/tokentype.hpp @@ -140,6 +140,9 @@ namespace xo { /** operator @c '!=' **/ tk_cmpne, + /** keyword @c 'nil' **/ + tk_nil, + /** keyword @c 'type' **/ tk_type, diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index f6ac7c2f..2a6f8ed9 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -587,6 +587,8 @@ namespace xo { if ((tk_text == "true") || (tk_text == "false")) { tk_type = tokentype::tk_bool; keep_text = true; + } else if (tk_text == "nil") { + tk_type = tokentype::tk_nil; } else if (tk_text == "type") { tk_type = tokentype::tk_type; } else if (tk_text == "def") { diff --git a/src/tokenizer2/tokentype.cpp b/src/tokenizer2/tokentype.cpp index 7df59eec..b8a013da 100644 --- a/src/tokenizer2/tokentype.cpp +++ b/src/tokenizer2/tokentype.cpp @@ -49,6 +49,7 @@ namespace xo { CASE(tk_cmpeq); CASE(tk_cmpne); + CASE(tk_nil); CASE(tk_type); CASE(tk_def); CASE(tk_deftype); From 3dc6268dfe91a0ccab60120d94fa014ade03ab08 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 20:26:08 -0500 Subject: [PATCH 284/342] xo-interpreter2 stack: refactor + bugfix operator expr --- CMakeLists.txt | 16 ++ idl/IGCObject_DGlobalEnv.json5 | 18 ++ idl/IPrintable_DGlobalEnv.json5 | 16 ++ include/xo/reader2/DGlobalEnv.hpp | 94 ++++++ include/xo/reader2/GlobalEnv.hpp | 12 + include/xo/reader2/ParserConfig.hpp | 4 + include/xo/reader2/ParserStateMachine.hpp | 45 ++- include/xo/reader2/ReaderConfig.hpp | 4 + .../xo/reader2/env/IGCObject_DGlobalEnv.hpp | 67 +++++ .../xo/reader2/env/IPrintable_DGlobalEnv.hpp | 62 ++++ src/reader2/CMakeLists.txt | 4 + src/reader2/DGlobalEnv.cpp | 145 ++++++++++ src/reader2/DProgressSsm.cpp | 272 +++--------------- src/reader2/ParserStateMachine.cpp | 2 + src/reader2/SchematikaParser.cpp | 1 + src/reader2/SchematikaReader.cpp | 1 + src/reader2/facet/IGCObject_DGlobalEnv.cpp | 39 +++ src/reader2/facet/IPrintable_DGlobalEnv.cpp | 28 ++ src/reader2/reader2_register_facets.cpp | 9 + src/reader2/reader2_register_types.cpp | 7 +- 20 files changed, 615 insertions(+), 231 deletions(-) create mode 100644 idl/IGCObject_DGlobalEnv.json5 create mode 100644 idl/IPrintable_DGlobalEnv.json5 create mode 100644 include/xo/reader2/DGlobalEnv.hpp create mode 100644 include/xo/reader2/GlobalEnv.hpp create mode 100644 include/xo/reader2/env/IGCObject_DGlobalEnv.hpp create mode 100644 include/xo/reader2/env/IPrintable_DGlobalEnv.hpp create mode 100644 src/reader2/DGlobalEnv.cpp create mode 100644 src/reader2/facet/IGCObject_DGlobalEnv.cpp create mode 100644 src/reader2/facet/IPrintable_DGlobalEnv.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index faf792a9..a88c83e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -337,6 +337,22 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-gcobject-globalenv + FACET_PKG xo_alloc2 + INPUT idl/IGCObject_DGlobalEnv.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-globalenv + FACET_PKG xo_printable2 + INPUT idl/IPrintable_DGlobalEnv.json5 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-reader2-genfacet-all) # ---------------------------------------------------------------- diff --git a/idl/IGCObject_DGlobalEnv.json5 b/idl/IGCObject_DGlobalEnv.json5 new file mode 100644 index 00000000..1a590527 --- /dev/null +++ b/idl/IGCObject_DGlobalEnv.json5 @@ -0,0 +1,18 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2/facet", + output_hpp_dir: "include/xo/interpreter2", + output_impl_subdir: "env", + includes: [ + "", + "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/GCObject.json5", + brief: "provide AGCObject interface for GlobalEnv", + using_doxygen: true, + repr: "DGlobalEnv", + doc: [ "implement AGCObject for DGlobalEnv" ], +} diff --git a/idl/IPrintable_DGlobalEnv.json5 b/idl/IPrintable_DGlobalEnv.json5 new file mode 100644 index 00000000..0a05eb62 --- /dev/null +++ b/idl/IPrintable_DGlobalEnv.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/interpreter2/facet", + output_hpp_dir: "include/xo/interpreter2", + output_impl_subdir: "env", + includes: [ "", + "" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DGlobalEnv", + using_doxygen: true, + repr: "DGlobalEnv", + doc: [ "implement APrintable for DGlobalEnv" ], +} diff --git a/include/xo/reader2/DGlobalEnv.hpp b/include/xo/reader2/DGlobalEnv.hpp new file mode 100644 index 00000000..da7f8536 --- /dev/null +++ b/include/xo/reader2/DGlobalEnv.hpp @@ -0,0 +1,94 @@ +/** @file DGlobalEnv.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include +#include + +namespace xo { + namespace scm { + + /** @brief runtime bindings for global variabels + * + * Implementation here uses a DArenaHashMap to hold pairs. + * The hash map has its own memory outside GC space. + * Keys are DUniqueStrings, also outside GC space. + * Values are regular gc-aware objects, generally will be in GC space. + * + * We need collector to traverse all the values in a global env + * on each cycle. Arrange that by having DGlobalEnv itself + * in GC space. + * + **/ + class DGlobalEnv { + public: + using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; + using AAllocator = xo::mm::AAllocator; + using AGCObject = xo::mm::AGCObject; + using MemorySizeVisitor = xo::mm::MemorySizeVisitor; + using ppindentinfo = xo::print::ppindentinfo; + using size_type = std::uint32_t; + + public: + /** @defgroup scm-globalenv-ctors constructors **/ + ///@{ + + DGlobalEnv(DGlobalSymtab * symtab, DArray * values); + + static DGlobalEnv * _make(obj mm, + DGlobalSymtab * symtab); + + + ///@} + /** @defgroup scm-globalenv-methods methods **/ + ///@{ + + /** symbol-table size. Is the number of distinct global variables **/ + size_type n_vars() const noexcept { return symtab_->n_vars(); } + + /** lookup current value associated with binding @p ix **/ + obj lookup_value(Binding ix) const noexcept; + + /** assign value associated with binding @p to @p x. + * If need to expand size of this env, use memory from @p mm + **/ + void assign_value(obj mm, Binding ix, obj x); + + /** create/establish global for symbol @p sym with resolved type @p td + * and associate with @p value. + **/ + DVariable * _upsert_value(obj mm, + const DUniqueString * sym, + TypeDescr td, + obj value); + + ///@} + /** @defgroup scm-globalenv-gcobject-facet **/ + ///@{ + + std::size_t shallow_size() const noexcept; + DGlobalEnv * shallow_copy(obj mm) const noexcept; + std::size_t forward_children(obj gc) noexcept; + + ///@} + /** @defgroup scm-globalenv-printable-facet **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + + /** symbol table assigns a unique index for each symbol **/ + DGlobalSymtab * symtab_; + + /** value for a symbol S will be in values_[symtab->lookup_binding(S)] **/ + DArray * values_ = nullptr; + }; + } +} diff --git a/include/xo/reader2/GlobalEnv.hpp b/include/xo/reader2/GlobalEnv.hpp new file mode 100644 index 00000000..94bafc42 --- /dev/null +++ b/include/xo/reader2/GlobalEnv.hpp @@ -0,0 +1,12 @@ +/** @file GlobalEnv.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DGlobalEnv.hpp" +#include "env/IGCObject_DGlobalEnv.hpp" +#include "env/IPrintable_DGlobalEnv.hpp" + +/* end GlobalEnv.hpp */ diff --git a/include/xo/reader2/ParserConfig.hpp b/include/xo/reader2/ParserConfig.hpp index 07dcb37b..2804be7b 100644 --- a/include/xo/reader2/ParserConfig.hpp +++ b/include/xo/reader2/ParserConfig.hpp @@ -5,6 +5,7 @@ #pragma once +#include #include #include @@ -55,6 +56,9 @@ namespace xo { /** max capacity for unique string table **/ size_t max_stringtable_capacity_ = 4096; + /** flags controlling which primitives to install **/ + InstallFlags pm_install_flags_ = InstallFlags::f_all; + /** control SchematikaParser debug logging **/ bool debug_flag_ = false; }; diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index f24c6bed..aa2797d0 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -6,11 +6,13 @@ #pragma once #include "ParserResult.hpp" +#include "GlobalEnv.hpp" #include #include #include #include #include +#include #include #include #include @@ -45,6 +47,9 @@ namespace xo { using size_type = std::size_t; public: + /** @defgroup scm-parserstatemachine-ctors constructors **/ + ///@{ + /** * @p config arena configuration for parser state * @p symtab_var_config configuration for global symtab variables @@ -53,6 +58,8 @@ namespace xo { * (maps to separate dedicated memory) * @p max_stringtable_capacity * hard max size for unique stringtable + * @p pm_install_flags + * flags controlling primitives to install * @p expr_alloc allocator for schematika expressions. * Probably shared with execution. * @p aux_alloc auxiliary allocator for non-copyable memory @@ -64,12 +71,17 @@ namespace xo { const ArenaHashMapConfig & symtab_var_config, const ArenaHashMapConfig & symtab_type_config, size_type max_stringtable_capacity, + InstallFlags pm_install_flags, obj expr_alloc, obj aux_alloc); - /** non-trivial dtor for @ref global_symtab_ **/ - ~ParserStateMachine() = default; + /** not copyable (need to put global_env into gc **/ + ParserStateMachine(const ParserStateMachine & other) = delete; + /** non-trivial dtor for @ref global_symtab_ **/ + ~ParserStateMachine(); + + ///@} /** @defgroup scm-parserstatemachine-accessors accessor methods **/ ///@{ @@ -80,6 +92,21 @@ namespace xo { DLocalSymtab * local_symtab() const noexcept { return local_symtab_; } const ParserResult & result() const noexcept { return result_; } + /** polymoprhihc multiply primitive. Use to implement infix op* **/ + obj multiply_pm() const; + /** polymorphic divide primitive. Use to implement infix op/ **/ + obj divide_pm() const; + /** polymorphic add primitive. Use to implement infix op+ **/ + obj add_pm() const; + /** polymorphic subtract primitive. Use to implement infix op- **/ + obj subtract_pm() const; + /** polymorphic equality comparison. Use to implement infix op== **/ + obj cmpeq_pm() const; + /** polymorphic inequality comparison. Use to implement infix op!= **/ + obj cmpne_pm() const; + /** polymorphich less-than comparison. Use to implement infix op< **/ + obj cmplt_pm() const; + /** true iff state machine is currently idle (at top-level) **/ bool is_at_toplevel() const noexcept; @@ -378,6 +405,20 @@ namespace xo { **/ DLocalSymtab * local_symtab_ = nullptr; + /** global variable bindings (builtin primitives) **/ + obj global_env_; + + /** bindings for special builtin primitives + * (asociated with hardwired operator syntax) + **/ + Binding multiply_binding_; + Binding divide_binding_; + Binding add_binding_; + Binding subtract_binding_; + Binding cmpeq_binding_; + Binding cmpne_binding_; + Binding cmplt_binding_; + /** current output from parser **/ ParserResult result_; diff --git a/include/xo/reader2/ReaderConfig.hpp b/include/xo/reader2/ReaderConfig.hpp index 513f515e..9af06879 100644 --- a/include/xo/reader2/ReaderConfig.hpp +++ b/include/xo/reader2/ReaderConfig.hpp @@ -5,6 +5,7 @@ #pragma once +#include #include #include #include @@ -71,6 +72,9 @@ namespace xo { /** max size (in bytes) of stringtable **/ size_t max_stringtable_cap_ = 64*1024; + /** flags controlling which primitives to install **/ + InstallFlags pm_install_flags_ = InstallFlags::f_all; + /** debug flag for schematika_reader **/ bool reader_debug_flag_ = false; }; diff --git a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp new file mode 100644 index 00000000..a2fcb5f6 --- /dev/null +++ b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp @@ -0,0 +1,67 @@ +/** @file IGCObject_DGlobalEnv.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DGlobalEnv.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DGlobalEnv.json5] + **/ + +#pragma once + +#include "GCObject.hpp" +#include +#include +#include "DGlobalEnv.hpp" + +namespace xo { namespace scm { class IGCObject_DGlobalEnv; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IGCObject_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IGCObject_DGlobalEnv + **/ + class IGCObject_DGlobalEnv { + public: + /** @defgroup scm-gcobject-dglobalenv-type-traits **/ + ///@{ + using size_type = xo::mm::AGCObject::size_type; + using AAllocator = xo::mm::AGCObject::AAllocator; + using ACollector = xo::mm::AGCObject::ACollector; + using Copaque = xo::mm::AGCObject::Copaque; + using Opaque = xo::mm::AGCObject::Opaque; + ///@} + /** @defgroup scm-gcobject-dglobalenv-methods **/ + ///@{ + // const methods + /** memory consumption for this instance **/ + static size_type shallow_size(const DGlobalEnv & self) noexcept; + /** copy instance using allocator **/ + static Opaque shallow_copy(const DGlobalEnv & self, obj mm) noexcept; + + // non-const methods + /** during GC: forward immdiate children **/ + static size_type forward_children(DGlobalEnv & self, obj gc) noexcept; + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/env/IPrintable_DGlobalEnv.hpp b/include/xo/reader2/env/IPrintable_DGlobalEnv.hpp new file mode 100644 index 00000000..6efcd963 --- /dev/null +++ b/include/xo/reader2/env/IPrintable_DGlobalEnv.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DGlobalEnv.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DGlobalEnv.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DGlobalEnv.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DGlobalEnv.hpp" + +namespace xo { namespace scm { class IPrintable_DGlobalEnv; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DGlobalEnv + **/ + class IPrintable_DGlobalEnv { + public: + /** @defgroup scm-printable-dglobalenv-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dglobalenv-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DGlobalEnv & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index af8bf4af..bb49efb8 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -14,6 +14,10 @@ set(SELF_SRCS ParserStack.cpp ParserResult.cpp + DGlobalEnv.cpp + facet/IGCObject_DGlobalEnv.cpp + facet/IPrintable_DGlobalEnv.cpp + syntaxstatetype.cpp ISyntaxStateMachine_Any.cpp diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp new file mode 100644 index 00000000..fcc92efa --- /dev/null +++ b/src/reader2/DGlobalEnv.cpp @@ -0,0 +1,145 @@ +/** @file DGlobalEnv.cpp + * + * @author Roland Conybeare, Feb 2026 +**/ + +#include "GlobalEnv.hpp" +#include +#include + +namespace xo { + using xo::mm::AAllocator; + using xo::mm::AGCObject; + + namespace scm { + + DGlobalEnv::DGlobalEnv(DGlobalSymtab * symtab, DArray * values) + : symtab_{symtab}, values_{values} + {} + + DGlobalEnv * + DGlobalEnv::_make(obj mm, + DGlobalSymtab * symtab) + { + DArray * values = DArray::empty(mm, symtab->var_capacity()); + + void * mem = mm.alloc_for(); + + return new (mem) DGlobalEnv(symtab, values); + } + + obj + DGlobalEnv::lookup_value(Binding ix) const noexcept + { + if (!ix.is_global()) { + assert(false); + return obj(); + } + + if (ix.j_slot() >= static_cast(values_->size())) { + assert(false); + return obj(); + } + + return (*values_)[ix.j_slot()]; + } + + void + DGlobalEnv::assign_value(obj mm, Binding ix, obj x) + { + scope log(XO_DEBUG(true), + xtag("ix.j_slot", ix.j_slot()), + xtag("values.cap", values_->capacity())); + + assert(ix.is_global()); + + if (ix.j_slot() >= static_cast(values_->size())) { + // Control will come here in interpreter as new definitions are introduced. + // After seeing + // def foo = 1.2345; + // introducing new symbol foo: + // GlobalSymtab extends to include foo without this GlobalEnv + // knowing about it. + + if (ix.j_slot() + 1 > static_cast(values_->capacity())) { + // realloc global array for more size + + size_t cap_2x = 2 * values_->capacity(); + + while (cap_2x < static_cast(ix.j_slot() + 1)) + cap_2x = 2 * cap_2x; + + DArray * values_2x = DArray::copy(mm, values_, cap_2x); + assert(values_2x); + + if (values_2x) { + log && log("STUB: need write barrier for GC (also in GlobalSymtab!)"); + this->values_ = values_2x; + } else { + return; + } + } + + /** expand size sot that j_slot is valid **/ + values_->resize(ix.j_slot() + 1); + } + + log && log("STUB: need write barrier for GC here"); + (*values_)[ix.j_slot()] = x; + } + + DVariable * + DGlobalEnv::_upsert_value(obj mm, + const DUniqueString * sym, + TypeDescr td, + obj value) + { + DVariable * var + = DVariable::make(mm, sym, TypeRef::resolved(td)); + + assert(var); + + symtab_->upsert_variable(mm, var); + this->assign_value(mm, var->path(), value); + + return var; + } + + // ----- AGCObject facet ----- + + std::size_t + DGlobalEnv::shallow_size() const noexcept + { + return sizeof(*this); + } + + DGlobalEnv * + DGlobalEnv::shallow_copy(obj mm) const noexcept + { + return mm.std_copy_for(this); + } + + std::size_t + DGlobalEnv::forward_children(obj gc) noexcept + { + gc.forward_inplace(&symtab_); + gc.forward_inplace(&values_); + + return this->shallow_size(); + } + + // ----- APrintable facet ----- + + bool + DGlobalEnv::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct + (ppii, + "DGlobalEnv", + refrtag("n_vars", symtab_->n_vars())); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DGlobalEnv.cpp */ diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index be927bef..e2b0d1a1 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -603,173 +603,6 @@ namespace xo { p_psm->on_error(self_name, std::move(errmsg)); } - rp - progress_xs::assemble_expr(parserstatemachine * p_psm) { - /* need to defer building Apply incase expr followed by higher-precedence operator: - * consider input like - * 3.14 + 2.0 * ... - */ - - constexpr const char * c_self_name = "progress_xs::assemble_expr"; - - if ((op_type_ != optype::invalid) && (rhs_.get() == nullptr)) { - std::string errmsg = tostr("expected expression on rhs of operator op", - xtag("lhs", lhs_), - xtag("op", op_type_)); - - p_psm->on_error(c_self_name, errmsg); - } - - /* consecutive expressions not legal, e.g: - * 3.14 6.28 - * but expressions surrounding an infix operators is: - * 3.14 / 6.28 - */ - switch (op_type_) { - case optype::invalid: - return this->lhs_; - - case optype::op_assign: - { - bp lhs = Variable::from(this->lhs_); - - if (!lhs) { - throw std::runtime_error - (tostr("progress_xs::assemble_expr", - " expect variable on lhs of assignment operator :=", - xtag("lhs", lhs_), - xtag("rhs", rhs_))); - } - - return AssignExpr::make(lhs.promote(), - this->rhs_); - } - - case optype::op_equal: - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_eq_i64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - - case optype::op_not_equal: - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_ne_i64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - - case optype::op_less: - // TODO: floating-point less-than - - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_lt_i64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - - case optype::op_less_equal: - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_le_i64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - - case optype::op_great: - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_gt_i64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - - case optype::op_great_equal: - // TODO: upconvert integer->double - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_ge_i64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - - assert(false); - - case optype::op_add: - // TODO: upconvert integer->double - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_add2_i64(lhs_, rhs_); - } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { - return Apply::make_add2_f64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - case optype::op_subtract: - // TODO: upconvert integer->double - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_sub2_i64(lhs_, rhs_); - } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { - return Apply::make_sub2_f64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - - case optype::op_multiply: - // TODO: upconvert integer->double - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_mul2_i64(lhs_, rhs_); - } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { - return Apply::make_mul2_f64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - - break; - - case optype::op_divide: - // TODO: upconvert integer->double - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_div2_i64(lhs_, rhs_); - } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { - return Apply::make_div2_f64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - - case optype::n_optype: - /* unreachable */ - assert(false); - return nullptr; - } - - return nullptr; - } - void progress_xs::on_expr(bp expr, parserstatemachine * p_psm) @@ -1216,11 +1049,10 @@ namespace xo { obj assemble_numeric_expr_aux(obj expr_alloc, const TypeRef::prefix_type & prefix, - DPrimitive_gco_2_gco_gco * p_gco_pm, + obj pm_obj, obj lhs, obj rhs) { - auto pm_obj = with_facet::mkobj(p_gco_pm); auto fn_expr = DConstant::make(expr_alloc, pm_obj); /* note: @@ -1247,6 +1079,23 @@ namespace xo { tref, fn_expr, lhs, rhs); } + +#ifdef OBSOLETE + obj + assemble_numeric_expr_aux(obj expr_alloc, + const TypeRef::prefix_type & prefix, + DPrimitive_gco_2_gco_gco * p_gco_pm, + obj lhs, + obj rhs) + { + auto pm_obj = with_facet::mkobj(p_gco_pm); + + return assemble_numeric_expr_aux(expr_alloc, + prefix, + pm_obj, + lhs, rhs); + } +#endif } obj @@ -1288,41 +1137,21 @@ namespace xo { return assemble_numeric_expr_aux (p_psm->expr_alloc(), TypeRef::prefix_type::from_chars("_cmpeq_gco"), - &NumericPrimitives::s_cmpeq_gco_gco_pm, + p_psm->cmpeq_pm(), lhs_, rhs_); -#ifdef OBSOLETE - { - auto pm_obj = (with_facet::mkobj - (&NumericPrimitives::s_cmpeq_gco_gco_pm)); - auto fn_expr = (DConstant::make - (p_psm->expr_alloc(), pm_obj)); - - // see note on op_multiply - - TypeRef tref = TypeRef::dwim - (TypeRef::prefix_type::from_chars("_equal_gco"), - nullptr); - - return DApplyExpr::make2(p_psm->expr_alloc(), - tref, - fn_expr, lhs_, rhs_); - } - break; -#endif - case optype::op_not_equal: return assemble_numeric_expr_aux (p_psm->expr_alloc(), TypeRef::prefix_type::from_chars("_cmpne_gco"), - &NumericPrimitives::s_cmpne_gco_gco_pm, + p_psm->cmpne_pm(), lhs_, rhs_); case optype::op_less: return assemble_numeric_expr_aux (p_psm->expr_alloc(), TypeRef::prefix_type::from_chars("_cmplt_gco"), - &NumericPrimitives::s_cmplt_gco_gco_pm, + p_psm->cmplt_pm(), lhs_, rhs_); case optype::op_less_equal: @@ -1335,45 +1164,18 @@ namespace xo { return assemble_numeric_expr_aux (p_psm->expr_alloc(), TypeRef::prefix_type::from_chars("_mul_gco"), - &NumericPrimitives::s_mul_gco_gco_pm, + p_psm->multiply_pm(), //&NumericPrimitives::s_mul_gco_gco_pm lhs_, rhs_); -#ifdef OBSOLETE - { - auto pm_obj = (with_facet::mkobj - (&NumericPrimitives::s_mul_gco_gco_pm)); - auto fn_expr = (DConstant::make - (p_psm->expr_alloc(), pm_obj)); - - /* note: - * 1. don't assume we know lhs_ / rhs_ value types yet. - * perhaps have expression like - * f(..) * g(..) - * where f is the function that contains current ssm. - * - * 2. consequence: we need representation for - * polymorphic multiply on unknown numeric arguments. - * - * 3. TypeRef::dwim(..) is a placeholder. - * Plan to later provide abstract interpreter - * (ie compiler pass :) to drive type inference/unification - * - * 4. Alternatively could supply type-annotation syntax - * so human can assist inference; context here is we want - * to automate the boring stuff - */ - - TypeRef tref = TypeRef::dwim - (TypeRef::prefix_type::from_chars("_mul_gco"), - nullptr); - - return DApplyExpr::make2(p_psm->expr_alloc(), - tref, fn_expr, lhs_, rhs_); - } -#endif - break; case optype::op_divide: + return assemble_numeric_expr_aux + (p_psm->expr_alloc(), + TypeRef::prefix_type::from_chars("_div_gco"), + p_psm->divide_pm(), // &NumericPrimitives::s_div_gco_gco_pm + lhs_, rhs_); + +#ifdef OBSOLETE { auto pm_obj = (with_facet::mkobj (&NumericPrimitives::s_div_gco_gco_pm)); @@ -1405,10 +1207,17 @@ namespace xo { return DApplyExpr::make2(p_psm->expr_alloc(), tref, fn_expr, lhs_, rhs_); } +#endif break; case optype::op_add: + return assemble_numeric_expr_aux + (p_psm->expr_alloc(), + TypeRef::prefix_type::from_chars("_add_gco"), + p_psm->add_pm(), + lhs_, rhs_); +#ifdef OBSOLETE { auto pm_obj = (with_facet::mkobj (&NumericPrimitives::s_add_gco_gco_pm)); @@ -1440,10 +1249,18 @@ namespace xo { return DApplyExpr::make2(p_psm->expr_alloc(), tref, fn_expr, lhs_, rhs_); } +#endif break; case optype::op_subtract: /* editor bait: op_minus */ + return assemble_numeric_expr_aux + (p_psm->expr_alloc(), + TypeRef::prefix_type::from_chars("_sub_gco"), + p_psm->subtract_pm(), + lhs_, rhs_); + +#ifdef OBSOLETE { auto pm_obj = (with_facet::mkobj (&NumericPrimitives::s_sub_gco_gco_pm)); @@ -1459,6 +1276,7 @@ namespace xo { return DApplyExpr::make2(p_psm->expr_alloc(), tref, fn_expr, lhs_, rhs_); } +#endif break; diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 360ae43e..55845f3b 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -8,8 +8,10 @@ #include "SyntaxStateMachine.hpp" #include "ToplevelSeqSsm.hpp" #include "DefineSsm.hpp" +#include #include #include +#include #include #include #include diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index d6ab1a0a..acfbeaa1 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -28,6 +28,7 @@ namespace xo { cfg.symtab_var_config_, cfg.symtab_types_config_, cfg.max_stringtable_capacity_, + cfg.pm_install_flags_, expr_alloc, aux_alloc }, diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index 0725a18c..98ef2292 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -18,6 +18,7 @@ namespace xo { config.symtab_var_config_, config.symtab_types_config_, config.max_stringtable_cap_, + config.pm_install_flags_, config.parser_debug_flag_), expr_alloc, aux_alloc}, diff --git a/src/reader2/facet/IGCObject_DGlobalEnv.cpp b/src/reader2/facet/IGCObject_DGlobalEnv.cpp new file mode 100644 index 00000000..76606d6f --- /dev/null +++ b/src/reader2/facet/IGCObject_DGlobalEnv.cpp @@ -0,0 +1,39 @@ +/** @file IGCObject_DGlobalEnv.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DGlobalEnv.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DGlobalEnv.json5] +**/ + +#include "env/IGCObject_DGlobalEnv.hpp" + +namespace xo { + namespace scm { + auto + IGCObject_DGlobalEnv::shallow_size(const DGlobalEnv & self) noexcept -> size_type + { + return self.shallow_size(); + } + + auto + IGCObject_DGlobalEnv::shallow_copy(const DGlobalEnv & self, obj mm) noexcept -> Opaque + { + return self.shallow_copy(mm); + } + + auto + IGCObject_DGlobalEnv::forward_children(DGlobalEnv & self, obj gc) noexcept -> size_type + { + return self.forward_children(gc); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IGCObject_DGlobalEnv.cpp */ diff --git a/src/reader2/facet/IPrintable_DGlobalEnv.cpp b/src/reader2/facet/IPrintable_DGlobalEnv.cpp new file mode 100644 index 00000000..84fc561c --- /dev/null +++ b/src/reader2/facet/IPrintable_DGlobalEnv.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DGlobalEnv.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DGlobalEnv.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DGlobalEnv.json5] +**/ + +#include "env/IPrintable_DGlobalEnv.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DGlobalEnv::pretty(const DGlobalEnv & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DGlobalEnv.cpp */ diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index dc9915ef..ccabe3a9 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -33,6 +33,7 @@ namespace xo { using xo::print::APrintable; + using xo::mm::AGCObject; using xo::facet::FacetRegistry; using xo::facet::TypeRegistry; using xo::facet::typeseq; @@ -43,6 +44,13 @@ namespace xo { { scope log(XO_DEBUG(true)); + // GlobalEnv + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + // SyntaxStateMachine + FacetRegistry::register_impl(); FacetRegistry::register_impl(); @@ -105,6 +113,7 @@ namespace xo { // misc types showing up in parser stack arena TypeRegistry::register_type(); + log && log(xtag("DGlobalEnv.tseq", typeseq::id())); log && log(xtag("DToplevelSeqSsm.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); log && log(xtag("DDeftypeSsm.tseq", typeseq::id())); diff --git a/src/reader2/reader2_register_types.cpp b/src/reader2/reader2_register_types.cpp index 3720752d..3d6a0fe0 100644 --- a/src/reader2/reader2_register_types.cpp +++ b/src/reader2/reader2_register_types.cpp @@ -4,22 +4,25 @@ **/ #include "reader2_register_types.hpp" +#include "GlobalEnv.hpp" #include namespace xo { using xo::mm::ACollector; + using xo::mm::AGCObject; + using xo::facet::impl_for; using xo::scope; namespace scm { bool - reader2_register_types(obj /*gc*/) + reader2_register_types(obj gc) { scope log(XO_DEBUG(true)); bool ok = true; - /* no gc-aware types yet; scaffold for future use */ + ok &= gc.install_type(impl_for()); return ok; } From b2073f832bcc3f21d5d87e53254c7a035af6c7e7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 20:38:09 -0500 Subject: [PATCH 285/342] xo-reader2: + parser utest, different precedence order --- utest/SchematikaParser.test.cpp | 69 +++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 6f97d7a0..7908a756 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -856,6 +856,75 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-interactive-arith4", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * 7 + 2 / 3; + * + **/ + + std::vector tk_v{ + Token::i64_token("7"), + Token::plus_token(), + Token::i64_token("2"), + Token::slash_token(), + Token::i64_token("3"), + Token::semicolon_token(), + }; + + INFO(testname); + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + REQUIRE(expr->n_args() == 2); + + auto fn = obj::from(expr->fn()); + REQUIRE(fn); + + auto pm = obj::from(fn->value()); + REQUIRE(pm); + REQUIRE(pm->name() == "_add"); + + auto lhs = obj::from(expr->arg(0)); + REQUIRE(lhs); + + auto lhs_i64 = obj::from(lhs->value()); + REQUIRE(lhs_i64->value() == 7); + + auto rhs = obj::from(expr->arg(1)); + REQUIRE(rhs); + + auto rhs_lhs = obj::from(rhs->arg(0)); + REQUIRE(rhs_lhs); + auto rhs_lhs_i64 = obj::from(rhs_lhs->value()); + REQUIRE(rhs_lhs_i64); + REQUIRE(rhs_lhs_i64->value() == 2); + + auto rhs_rhs = obj::from(rhs->arg(1)); + REQUIRE(rhs_rhs); + auto rhs_rhs_i64 = obj::from(rhs_rhs->value()); + REQUIRE(rhs_rhs_i64); + REQUIRE(rhs_rhs_i64->value() == 3); + } + + log && fixture.log_memory_layout(&log); + } + #ifdef OBSOLETE TEST_CASE("SchematikaParser-interactive-arith3-bad", "[reader2][SchematikaParser]") { From ccc99686863eb2968087a941b9e44c788f7ff774 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 20:38:36 -0500 Subject: [PATCH 286/342] xo-reader2: drop some debug --- utest/SchematikaParser.test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 7908a756..4d3f943b 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -279,7 +279,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -318,7 +318,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); From e6cf7510837c78a541ccbbc9fd77abf6b30f1acd Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 20:39:05 -0500 Subject: [PATCH 287/342] xo-reader2: globalenv setup --- src/reader2/ParserStateMachine.cpp | 183 ++++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 3 deletions(-) diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 55845f3b..2b2ade05 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -20,16 +20,69 @@ #include namespace xo { - using xo::mm::MemorySizeInfo; + using xo::mm::ACollector; + using xo::mm::AAllocator; + using xo::mm::AGCObject; using xo::print::APrintable; + using xo::reflect::TypeDescr; using xo::facet::FacetRegistry; - using xo::facet::with_facet; namespace scm { + namespace { + /** Create global environment and populate with builtin primitives. + * Get memory from @p mm, with symbol names in @p stringtable. + * Stash symbol names in @p global_symtab, which coordinates with + * new global environment. + * @p pm_install_flags controls which primitives to install + **/ + obj + global_env_setup(StringTable & stringtable, + obj mm, + DGlobalSymtab * global_symtab, + InstallFlags pm_install_flags) + { + DGlobalEnv * env = DGlobalEnv::_make(mm, + global_symtab); + + InstallSink sink = ([env, mm, &stringtable] + (std::string_view name, + TypeDescr fn_td, + obj pm, + InstallFlags flags) + { + scope log(XO_DEBUG(false)); + + log && log(xtag("name", name)); + + (void)flags; + + obj pm_gco = pm.to_facet(); + + const DUniqueString * sym + = stringtable.intern(name); + + env->_upsert_value(mm, + sym, + fn_td, + pm_gco); + + return true; + }); + + PrimitiveRegistry::instance() + .install_primitives(mm, + sink, + pm_install_flags); + + return obj(env); + } + } + ParserStateMachine::ParserStateMachine(const ArenaConfig & config, const ArenaHashMapConfig & symtab_var_config, const ArenaHashMapConfig & symtab_type_config, size_type max_stringtable_capacity, + InstallFlags pm_install_flags, obj expr_alloc, obj aux_alloc) : stringtable_{max_stringtable_capacity}, @@ -39,14 +92,138 @@ namespace xo { global_symtab_{DGlobalSymtab::make(expr_alloc, aux_alloc, symtab_var_config, symtab_type_config)}, + global_env_{global_env_setup(stringtable_, + expr_alloc_, + global_symtab_.data(), + pm_install_flags)}, debug_flag_{config.debug_flag_} { + obj gc = expr_alloc_.try_to_facet(); + if (gc) { + gc.add_gc_root(&global_env_); + } + + { + const DUniqueString * name = stringtable_.lookup("_mul"); + assert(name); + this->multiply_binding_ = global_symtab_->lookup_binding(name); + } + + { + const DUniqueString * name = stringtable_.lookup("_div"); + assert(name); + this->divide_binding_ = global_symtab_->lookup_binding(name); + } + + { + const DUniqueString * name = stringtable_.lookup("_add"); + assert(name); + this->add_binding_ = global_symtab_->lookup_binding(name); + } + + { + const DUniqueString * name = stringtable_.lookup("_sub"); + assert(name); + this->subtract_binding_ = global_symtab_->lookup_binding(name); + } + + { + const DUniqueString * name = stringtable_.lookup("_cmpeq"); + assert(name); + this->cmpeq_binding_ = global_symtab_->lookup_binding(name); + } + + { + const DUniqueString * name = stringtable_.lookup("_cmpne"); + assert(name); + this->cmpne_binding_ = global_symtab_->lookup_binding(name); + } + + { + const DUniqueString * name = stringtable_.lookup("_cmplt"); + assert(name); + this->cmplt_binding_ = global_symtab_->lookup_binding(name); + } + } + + ParserStateMachine::~ParserStateMachine() + { + obj gc = expr_alloc_.try_to_facet(); + + if (gc) { + scope log(XO_DEBUG(true), "remove_gc_root not implemented"); + + gc.remove_gc_root(&global_env_); + } + } + + obj + ParserStateMachine::multiply_pm() const + { + obj retval = global_env_->lookup_value(multiply_binding_); + assert(retval); + + return retval; + } + + obj + ParserStateMachine::divide_pm() const + { + obj retval = global_env_->lookup_value(divide_binding_); + assert(retval); + + return retval; + } + + obj + ParserStateMachine::add_pm() const + { + obj retval = global_env_->lookup_value(add_binding_); + assert(retval); + + return retval; + } + + obj + ParserStateMachine::subtract_pm() const + { + obj retval = global_env_->lookup_value(subtract_binding_); + assert(retval); + + return retval; + } + + obj + ParserStateMachine::cmpeq_pm() const + { + obj retval = global_env_->lookup_value(cmpeq_binding_); + assert(retval); + + return retval; + } + + obj + ParserStateMachine::cmpne_pm() const + { + obj retval = global_env_->lookup_value(cmpne_binding_); + assert(retval); + + return retval; + } + + obj + ParserStateMachine::cmplt_pm() const + { + obj retval = global_env_->lookup_value(cmplt_binding_); + assert(retval); + + return retval; } bool ParserStateMachine::is_at_toplevel() const noexcept { - /* top-level alwyas has DToplevelSeqSsm */ + /* top-level always has DToplevelSeqSsm */ ParserStack * s = stack_; From 6acad261119dfe8b9ebdf6f0798c22361408913f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 20:40:04 -0500 Subject: [PATCH 288/342] xo-reader2: drop debug --- src/reader2/DGlobalEnv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp index fcc92efa..386db966 100644 --- a/src/reader2/DGlobalEnv.cpp +++ b/src/reader2/DGlobalEnv.cpp @@ -47,7 +47,7 @@ namespace xo { void DGlobalEnv::assign_value(obj mm, Binding ix, obj x) { - scope log(XO_DEBUG(true), + scope log(XO_DEBUG(false), xtag("ix.j_slot", ix.j_slot()), xtag("values.cap", values_->capacity())); From 88bf0475ecb17fdf86485d017e4739a29f2dc378 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 20:40:35 -0500 Subject: [PATCH 289/342] xo-reader2: bugfix: gather inputs before pop --- src/reader2/DProgressSsm.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index e2b0d1a1..59317a78 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -410,17 +410,25 @@ namespace xo { * a + b * ... (a + (b * ...)) */ + obj lhs1 = lhs_; + optype op_type1 = op_type_; + obj rhs1 = rhs_; + + assert(lhs1); + assert(op_type1 != optype::invalid); + assert(rhs1); + p_psm->pop_ssm(); /* (a + ..) */ DProgressSsm::start(p_psm->parser_alloc(), - lhs_, - op_type_, + lhs1, + op_type1, p_psm); DExpectExprSsm::start(p_psm); /* (b * ..) */ DProgressSsm::start(p_psm->parser_alloc(), - rhs_, + rhs1, op_type2, p_psm); DExpectExprSsm::start(p_psm); From 8fda8c8f143eb72a0f4bfd100589d1fe940fabbd Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 21:00:16 -0500 Subject: [PATCH 290/342] xo-reader2 stack: + op<= setup --- include/xo/reader2/ParserStateMachine.hpp | 3 +++ src/reader2/ParserStateMachine.cpp | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index aa2797d0..f8a0a796 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -106,6 +106,8 @@ namespace xo { obj cmpne_pm() const; /** polymorphich less-than comparison. Use to implement infix op< **/ obj cmplt_pm() const; + /** polymorphich less-or-equal comparison. Use to implement infix op<= **/ + obj cmple_pm() const; /** true iff state machine is currently idle (at top-level) **/ bool is_at_toplevel() const noexcept; @@ -418,6 +420,7 @@ namespace xo { Binding cmpeq_binding_; Binding cmpne_binding_; Binding cmplt_binding_; + Binding cmple_binding_; /** current output from parser **/ ParserResult result_; diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 2b2ade05..71c52791 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -144,6 +144,12 @@ namespace xo { assert(name); this->cmplt_binding_ = global_symtab_->lookup_binding(name); } + + { + const DUniqueString * name = stringtable_.lookup("_cmple"); + assert(name); + this->cmple_binding_ = global_symtab_->lookup_binding(name); + } } ParserStateMachine::~ParserStateMachine() @@ -220,6 +226,15 @@ namespace xo { return retval; } + obj + ParserStateMachine::cmple_pm() const + { + obj retval = global_env_->lookup_value(cmple_binding_); + assert(retval); + + return retval; + } + bool ParserStateMachine::is_at_toplevel() const noexcept { From 417ad2ac7878f77759d3c7d41d4de6ac4c3b5bf1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 21:08:58 -0500 Subject: [PATCH 291/342] xo-reader2 stack: support op<= --- src/reader2/DApplySsm.cpp | 2 +- src/reader2/DDefineSsm.cpp | 2 +- src/reader2/DDeftypeSsm.cpp | 2 +- src/reader2/DExpectExprSsm.cpp | 2 +- src/reader2/DExpectFormalArgSsm.cpp | 2 +- src/reader2/DExpectFormalArglistSsm.cpp | 2 +- src/reader2/DExpectListTypeSsm.cpp | 2 +- src/reader2/DExpectQArraySsm.cpp | 2 +- src/reader2/DExpectQListSsm.cpp | 2 +- src/reader2/DExpectQLiteralSsm.cpp | 2 +- src/reader2/DExpectSymbolSsm.cpp | 2 +- src/reader2/DExpectTypeSsm.cpp | 2 +- src/reader2/DIfElseSsm.cpp | 2 +- src/reader2/DLambdaSsm.cpp | 2 +- src/reader2/DParenSsm.cpp | 2 +- src/reader2/DProgressSsm.cpp | 67 +++---------------------- src/reader2/DQuoteSsm.cpp | 2 +- src/reader2/DSequenceSsm.cpp | 2 +- src/reader2/DToplevelSeqSsm.cpp | 2 +- 19 files changed, 26 insertions(+), 77 deletions(-) diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index cd591c9c..dc263b75 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -158,7 +158,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 2f7f99be..ba7c1a01 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -533,7 +533,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DDeftypeSsm.cpp b/src/reader2/DDeftypeSsm.cpp index 383f4fee..ca0baf7f 100644 --- a/src/reader2/DDeftypeSsm.cpp +++ b/src/reader2/DDeftypeSsm.cpp @@ -138,7 +138,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index f4fabfc9..ae7a0cb6 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -179,7 +179,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index a17d094c..e20a935c 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -122,7 +122,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 9f7da033..65adb978 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -153,7 +153,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_doublecolon: diff --git a/src/reader2/DExpectListTypeSsm.cpp b/src/reader2/DExpectListTypeSsm.cpp index 1f42d171..f99810f3 100644 --- a/src/reader2/DExpectListTypeSsm.cpp +++ b/src/reader2/DExpectListTypeSsm.cpp @@ -114,7 +114,7 @@ namespace xo { case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DExpectQArraySsm.cpp b/src/reader2/DExpectQArraySsm.cpp index aa89862f..aee31dbc 100644 --- a/src/reader2/DExpectQArraySsm.cpp +++ b/src/reader2/DExpectQArraySsm.cpp @@ -110,7 +110,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_doublecolon: diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp index f3f50b81..731dec1c 100644 --- a/src/reader2/DExpectQListSsm.cpp +++ b/src/reader2/DExpectQListSsm.cpp @@ -110,7 +110,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_doublecolon: diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index 4cb26099..73b7efd5 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -128,7 +128,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_doublecolon: diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 17cdca06..0437417d 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -88,7 +88,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 9eb2b15d..cbe73dae 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -91,7 +91,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index b915c061..0a49bf38 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -173,7 +173,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index ac19c7e0..8503e4e9 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -151,7 +151,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index 7bf28d02..3eeb1f5e 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -119,7 +119,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 59317a78..d52a98c0 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -134,7 +134,7 @@ namespace xo { return optype::op_not_equal; case tokentype::tk_leftangle: // [<] return optype::op_less; - case tokentype::tk_lessequal: + case tokentype::tk_cmple: // [<=] return optype::op_less_equal; case tokentype::tk_rightangle: return optype::op_great; @@ -291,7 +291,6 @@ namespace xo { case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_doublecolon: @@ -306,6 +305,7 @@ namespace xo { case tokentype::tk_cmpeq: case tokentype::tk_cmpne: case tokentype::tk_leftangle: + case tokentype::tk_cmple: this->on_operator_token(tk, p_psm); return; @@ -1163,6 +1163,12 @@ namespace xo { lhs_, rhs_); case optype::op_less_equal: + return assemble_numeric_expr_aux + (p_psm->expr_alloc(), + TypeRef::prefix_type::from_chars("_cmple_gco"), + p_psm->cmple_pm(), + lhs_, rhs_); + case optype::op_great: case optype::op_great_equal: assert(false); @@ -1175,7 +1181,6 @@ namespace xo { p_psm->multiply_pm(), //&NumericPrimitives::s_mul_gco_gco_pm lhs_, rhs_); - break; case optype::op_divide: return assemble_numeric_expr_aux (p_psm->expr_alloc(), @@ -1183,42 +1188,6 @@ namespace xo { p_psm->divide_pm(), // &NumericPrimitives::s_div_gco_gco_pm lhs_, rhs_); -#ifdef OBSOLETE - { - auto pm_obj = (with_facet::mkobj - (&NumericPrimitives::s_div_gco_gco_pm)); - auto fn_expr = (DConstant::make - (p_psm->expr_alloc(), pm_obj)); - - /* note: - * 1. don't assume we know lhs_ / rhs_ value types yet. - * perhaps have expression like - * f(..) * g(..) - * where f is the function that contains current ssm. - * - * 2. consequence: we need representation for - * polymorphic multiply on unknown numeric arguments. - * - * 3. TypeRef::dwim(..) is a placeholder. - * Plan to later provide abstract interpreter - * (ie compiler pass :) to drive type inference/unification - * - * 4. Alternatively could supply type-annotation syntax - * so human can assist inference; context here is we want - * to automate the boring stuff - */ - - TypeRef tref = TypeRef::dwim - (TypeRef::prefix_type::from_chars("_div_gco"), - nullptr); - - return DApplyExpr::make2(p_psm->expr_alloc(), - tref, fn_expr, lhs_, rhs_); - } -#endif - - break; - case optype::op_add: return assemble_numeric_expr_aux (p_psm->expr_alloc(), @@ -1268,26 +1237,6 @@ namespace xo { p_psm->subtract_pm(), lhs_, rhs_); -#ifdef OBSOLETE - { - auto pm_obj = (with_facet::mkobj - (&NumericPrimitives::s_sub_gco_gco_pm)); - auto fn_expr = (DConstant::make - (p_psm->expr_alloc(), pm_obj)); - - // see comment on op_multiply re need for poly impl - - TypeRef tref = TypeRef::dwim - (TypeRef::prefix_type::from_chars("_sub_gco"), - nullptr); - - return DApplyExpr::make2(p_psm->expr_alloc(), - tref, fn_expr, lhs_, rhs_); - } -#endif - - break; - #ifdef NOT_YET case optype::op_assign: { diff --git a/src/reader2/DQuoteSsm.cpp b/src/reader2/DQuoteSsm.cpp index c61ed632..2e335064 100644 --- a/src/reader2/DQuoteSsm.cpp +++ b/src/reader2/DQuoteSsm.cpp @@ -120,7 +120,7 @@ namespace xo { case tokentype::tk_rightbracket: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index b2b237dd..6311a2ae 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -101,7 +101,7 @@ namespace xo { case tokentype::tk_leftbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index 612f64fd..193ea42c 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -174,7 +174,7 @@ namespace xo { case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: - case tokentype::tk_lessequal: + case tokentype::tk_cmple: case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_comma: From 41f704f7ab484a94154d82ba3c4919affeda7f4e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 21:08:58 -0500 Subject: [PATCH 292/342] xo-reader2 stack: support op<= --- include/xo/tokenizer2/tokentype.hpp | 2 +- src/tokenizer2/Tokenizer.cpp | 2 +- src/tokenizer2/tokentype.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xo/tokenizer2/tokentype.hpp b/include/xo/tokenizer2/tokentype.hpp index 5f7e1937..18857af9 100644 --- a/include/xo/tokenizer2/tokentype.hpp +++ b/include/xo/tokenizer2/tokentype.hpp @@ -92,7 +92,7 @@ namespace xo { tk_rightangle, /** less-equal @c '<=' **/ - tk_lessequal, + tk_cmple, /** great-equal @c '>=' **/ tk_greatequal, diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index 2a6f8ed9..76881e7f 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -486,7 +486,7 @@ namespace xo { log && log("leftangle or lessequal token"); if (*(ix + 1) == '=') { - tk_type = tokentype::tk_lessequal; + tk_type = tokentype::tk_cmple; ++ix; ++ix; } else { diff --git a/src/tokenizer2/tokentype.cpp b/src/tokenizer2/tokentype.cpp index b8a013da..e704b38d 100644 --- a/src/tokenizer2/tokentype.cpp +++ b/src/tokenizer2/tokentype.cpp @@ -29,7 +29,7 @@ namespace xo { CASE(tk_leftangle); CASE(tk_rightangle); - CASE(tk_lessequal); + CASE(tk_cmple); CASE(tk_greatequal); CASE(tk_dot); CASE(tk_comma); From 6104515656f173d2c82b025b2fa9fd01493fad67 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 23:41:21 -0500 Subject: [PATCH 293/342] xo-reader2: + op>= support --- include/xo/reader2/ParserStateMachine.hpp | 7 +++++-- src/reader2/DApplySsm.cpp | 2 +- src/reader2/DDefineSsm.cpp | 2 +- src/reader2/DDeftypeSsm.cpp | 2 +- src/reader2/DExpectExprSsm.cpp | 2 +- src/reader2/DExpectFormalArgSsm.cpp | 2 +- src/reader2/DExpectFormalArglistSsm.cpp | 2 +- src/reader2/DExpectListTypeSsm.cpp | 2 +- src/reader2/DExpectQArraySsm.cpp | 2 +- src/reader2/DExpectQListSsm.cpp | 2 +- src/reader2/DExpectQLiteralSsm.cpp | 2 +- src/reader2/DExpectSymbolSsm.cpp | 2 +- src/reader2/DExpectTypeSsm.cpp | 2 +- src/reader2/DIfElseSsm.cpp | 2 +- src/reader2/DLambdaSsm.cpp | 2 +- src/reader2/DParenSsm.cpp | 2 +- src/reader2/DProgressSsm.cpp | 12 +++++++++--- src/reader2/DQuoteSsm.cpp | 2 +- src/reader2/DSequenceSsm.cpp | 2 +- src/reader2/DToplevelSeqSsm.cpp | 2 +- src/reader2/ParserStateMachine.cpp | 15 +++++++++++++++ 21 files changed, 47 insertions(+), 23 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index f8a0a796..3ae647dc 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -104,10 +104,12 @@ namespace xo { obj cmpeq_pm() const; /** polymorphic inequality comparison. Use to implement infix op!= **/ obj cmpne_pm() const; - /** polymorphich less-than comparison. Use to implement infix op< **/ + /** polymorphic less-than comparison. Use to implement infix op< **/ obj cmplt_pm() const; - /** polymorphich less-or-equal comparison. Use to implement infix op<= **/ + /** polymorphic less-or-equal comparison. Use to implement infix op<= **/ obj cmple_pm() const; + /** polymorphic greater-or-equal comparison. Use to implement infix op>= **/ + obj cmpge_pm() const; /** true iff state machine is currently idle (at top-level) **/ bool is_at_toplevel() const noexcept; @@ -421,6 +423,7 @@ namespace xo { Binding cmpne_binding_; Binding cmplt_binding_; Binding cmple_binding_; + Binding cmpge_binding_; /** current output from parser **/ ParserResult result_; diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index dc263b75..bcbd5c60 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -159,7 +159,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index ba7c1a01..4634e0a2 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -534,7 +534,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: diff --git a/src/reader2/DDeftypeSsm.cpp b/src/reader2/DDeftypeSsm.cpp index ca0baf7f..865ed436 100644 --- a/src/reader2/DDeftypeSsm.cpp +++ b/src/reader2/DDeftypeSsm.cpp @@ -139,7 +139,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_assign: diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index ae7a0cb6..7dcc1d06 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -180,7 +180,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index e20a935c..b8c5f425 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -123,7 +123,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 65adb978..d68beef5 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -154,7 +154,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_doublecolon: case tokentype::tk_assign: diff --git a/src/reader2/DExpectListTypeSsm.cpp b/src/reader2/DExpectListTypeSsm.cpp index f99810f3..36723a6a 100644 --- a/src/reader2/DExpectListTypeSsm.cpp +++ b/src/reader2/DExpectListTypeSsm.cpp @@ -115,7 +115,7 @@ namespace xo { case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: diff --git a/src/reader2/DExpectQArraySsm.cpp b/src/reader2/DExpectQArraySsm.cpp index aee31dbc..a86bcdae 100644 --- a/src/reader2/DExpectQArraySsm.cpp +++ b/src/reader2/DExpectQArraySsm.cpp @@ -111,7 +111,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_doublecolon: case tokentype::tk_assign: diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp index 731dec1c..50cde338 100644 --- a/src/reader2/DExpectQListSsm.cpp +++ b/src/reader2/DExpectQListSsm.cpp @@ -111,7 +111,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_doublecolon: case tokentype::tk_assign: diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index 73b7efd5..89e79b85 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -129,7 +129,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_doublecolon: case tokentype::tk_assign: diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 0437417d..b1754e33 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -89,7 +89,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index cbe73dae..4af50bea 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -92,7 +92,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_colon: diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index 0a49bf38..e599f6ad 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -174,7 +174,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 8503e4e9..f8d0fa13 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -152,7 +152,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index 3eeb1f5e..5fc33059 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -120,7 +120,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index d52a98c0..80b7bb26 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -138,7 +138,7 @@ namespace xo { return optype::op_less_equal; case tokentype::tk_rightangle: return optype::op_great; - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: // [>=] return optype::op_great_equal; default: assert(false); @@ -291,7 +291,6 @@ namespace xo { case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: case tokentype::tk_rightangle: - case tokentype::tk_greatequal: case tokentype::tk_dot: case tokentype::tk_doublecolon: case tokentype::tk_assign: @@ -306,6 +305,7 @@ namespace xo { case tokentype::tk_cmpne: case tokentype::tk_leftangle: case tokentype::tk_cmple: + case tokentype::tk_cmpge: this->on_operator_token(tk, p_psm); return; @@ -1170,10 +1170,16 @@ namespace xo { lhs_, rhs_); case optype::op_great: - case optype::op_great_equal: assert(false); break; + case optype::op_great_equal: + return assemble_numeric_expr_aux + (p_psm->expr_alloc(), + TypeRef::prefix_type::from_chars("_cmpge_gco"), + p_psm->cmpge_pm(), + lhs_, rhs_); + case optype::op_multiply: return assemble_numeric_expr_aux (p_psm->expr_alloc(), diff --git a/src/reader2/DQuoteSsm.cpp b/src/reader2/DQuoteSsm.cpp index 2e335064..6d885e0b 100644 --- a/src/reader2/DQuoteSsm.cpp +++ b/src/reader2/DQuoteSsm.cpp @@ -121,7 +121,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index 6311a2ae..c2a07966 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -102,7 +102,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_doublecolon: diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index 193ea42c..113ec235 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -175,7 +175,7 @@ namespace xo { case tokentype::tk_leftangle: case tokentype::tk_rightangle: case tokentype::tk_cmple: - case tokentype::tk_greatequal: + case tokentype::tk_cmpge: case tokentype::tk_dot: case tokentype::tk_comma: case tokentype::tk_colon: diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 71c52791..1bc9066f 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -150,6 +150,12 @@ namespace xo { assert(name); this->cmple_binding_ = global_symtab_->lookup_binding(name); } + + { + const DUniqueString * name = stringtable_.lookup("_cmpge"); + assert(name); + this->cmpge_binding_ = global_symtab_->lookup_binding(name); + } } ParserStateMachine::~ParserStateMachine() @@ -235,6 +241,15 @@ namespace xo { return retval; } + obj + ParserStateMachine::cmpge_pm() const + { + obj retval = global_env_->lookup_value(cmpge_binding_); + assert(retval); + + return retval; + } + bool ParserStateMachine::is_at_toplevel() const noexcept { From 4e7b58e3c95d0726d777f5310fd4eca5f5f93b76 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 23:41:21 -0500 Subject: [PATCH 294/342] xo-reader2: + op>= support --- include/xo/tokenizer2/tokentype.hpp | 2 +- src/tokenizer2/Tokenizer.cpp | 2 +- src/tokenizer2/tokentype.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xo/tokenizer2/tokentype.hpp b/include/xo/tokenizer2/tokentype.hpp index 18857af9..a5538131 100644 --- a/include/xo/tokenizer2/tokentype.hpp +++ b/include/xo/tokenizer2/tokentype.hpp @@ -95,7 +95,7 @@ namespace xo { tk_cmple, /** great-equal @c '>=' **/ - tk_greatequal, + tk_cmpge, /** dot @c '.' **/ tk_dot, diff --git a/src/tokenizer2/Tokenizer.cpp b/src/tokenizer2/Tokenizer.cpp index 76881e7f..88f03755 100644 --- a/src/tokenizer2/Tokenizer.cpp +++ b/src/tokenizer2/Tokenizer.cpp @@ -500,7 +500,7 @@ namespace xo { log && log("rightangle or greatequal token"); if (*(ix + 1) == '=') { - tk_type = tokentype::tk_greatequal; + tk_type = tokentype::tk_cmpge; ++ix; ++ix; } else { diff --git a/src/tokenizer2/tokentype.cpp b/src/tokenizer2/tokentype.cpp index e704b38d..c9749a34 100644 --- a/src/tokenizer2/tokentype.cpp +++ b/src/tokenizer2/tokentype.cpp @@ -30,7 +30,7 @@ namespace xo { CASE(tk_rightangle); CASE(tk_cmple); - CASE(tk_greatequal); + CASE(tk_cmpge); CASE(tk_dot); CASE(tk_comma); CASE(tk_colon); From 4c9771126bd8d205f98ef939c4d60194ee29798b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Mar 2026 00:15:29 -0500 Subject: [PATCH 295/342] xo-reader2: + op> support --- include/xo/reader2/ParserStateMachine.hpp | 3 + src/reader2/DProgressSsm.cpp | 163 ++-------------------- src/reader2/ParserStateMachine.cpp | 15 ++ 3 files changed, 27 insertions(+), 154 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 3ae647dc..4f14f72a 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -108,6 +108,8 @@ namespace xo { obj cmplt_pm() const; /** polymorphic less-or-equal comparison. Use to implement infix op<= **/ obj cmple_pm() const; + /** polymorphic greater comparison. Use to implement infix op> **/ + obj cmpgt_pm() const; /** polymorphic greater-or-equal comparison. Use to implement infix op>= **/ obj cmpge_pm() const; @@ -423,6 +425,7 @@ namespace xo { Binding cmpne_binding_; Binding cmplt_binding_; Binding cmple_binding_; + Binding cmpgt_binding_; Binding cmpge_binding_; /** current output from parser **/ diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 80b7bb26..90fb5d16 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -136,7 +136,7 @@ namespace xo { return optype::op_less; case tokentype::tk_cmple: // [<=] return optype::op_less_equal; - case tokentype::tk_rightangle: + case tokentype::tk_rightangle: // [>] return optype::op_great; case tokentype::tk_cmpge: // [>=] return optype::op_great_equal; @@ -290,7 +290,6 @@ namespace xo { case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: - case tokentype::tk_rightangle: case tokentype::tk_dot: case tokentype::tk_doublecolon: case tokentype::tk_assign: @@ -304,6 +303,7 @@ namespace xo { case tokentype::tk_cmpeq: case tokentype::tk_cmpne: case tokentype::tk_leftangle: + case tokentype::tk_rightangle: case tokentype::tk_cmple: case tokentype::tk_cmpge: this->on_operator_token(tk, p_psm); @@ -1170,7 +1170,11 @@ namespace xo { lhs_, rhs_); case optype::op_great: - assert(false); + return assemble_numeric_expr_aux + (p_psm->expr_alloc(), + TypeRef::prefix_type::from_chars("_cmpgt_gco"), + p_psm->cmpgt_pm(), + lhs_, rhs_); break; case optype::op_great_equal: @@ -1184,14 +1188,14 @@ namespace xo { return assemble_numeric_expr_aux (p_psm->expr_alloc(), TypeRef::prefix_type::from_chars("_mul_gco"), - p_psm->multiply_pm(), //&NumericPrimitives::s_mul_gco_gco_pm + p_psm->multiply_pm(), lhs_, rhs_); case optype::op_divide: return assemble_numeric_expr_aux (p_psm->expr_alloc(), TypeRef::prefix_type::from_chars("_div_gco"), - p_psm->divide_pm(), // &NumericPrimitives::s_div_gco_gco_pm + p_psm->divide_pm(), lhs_, rhs_); case optype::op_add: @@ -1200,39 +1204,6 @@ namespace xo { TypeRef::prefix_type::from_chars("_add_gco"), p_psm->add_pm(), lhs_, rhs_); -#ifdef OBSOLETE - { - auto pm_obj = (with_facet::mkobj - (&NumericPrimitives::s_add_gco_gco_pm)); - auto fn_expr = (DConstant::make - (p_psm->expr_alloc(), pm_obj)); - - /* note: - * 1. don't assume we know lhs_ / rhs_ value types yet. - * perhaps have expression like - * f(..) * g(..) - * where f is the function that contains current ssm. - * - * 2. consequence: we need representation for - * polymorphic multiply on unknown numeric arguments. - * - * 3. TypeRef::dwim(..) is a placeholder. - * Plan to later provide abstract interpreter - * (ie compiler pass :) to drive type inference/unification - * - * 4. Alternatively could supply type-annotation syntax - * so human can assist inference; context here is we want - * to automate the boring stuff - */ - - TypeRef tref = TypeRef::dwim - (TypeRef::prefix_type::from_chars("_add_gco"), - nullptr); - - return DApplyExpr::make2(p_psm->expr_alloc(), - tref, fn_expr, lhs_, rhs_); - } -#endif break; @@ -1260,122 +1231,6 @@ case optype::op_assign: this->rhs_); } -case optype::op_equal: - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_eq_i64(lhs_, rhs_); - } else { - - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - -case optype::op_not_equal: - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_ne_i64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - -case optype::op_less: - // TODO: floating-point less-than - - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_lt_i64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - -case optype::op_less_equal: - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_le_i64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - -case optype::op_great: - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_gt_i64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - -case optype::op_great_equal: - // TODO: upconvert integer->double - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_cmp_ge_i64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - - assert(false); - -case optype::op_add: - // TODO: upconvert integer->double - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_add2_i64(lhs_, rhs_); - } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { - return Apply::make_add2_f64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; -case optype::op_subtract: - // TODO: upconvert integer->double - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_sub2_i64(lhs_, rhs_); - } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { - return Apply::make_sub2_f64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; - -case optype::op_multiply: - // TODO: upconvert integer->double - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_mul2_i64(lhs_, rhs_); - } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { - return Apply::make_mul2_f64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - - break; - -case optype::op_divide: - // TODO: upconvert integer->double - if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) { - return Apply::make_div2_i64(lhs_, rhs_); - } else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) { - return Apply::make_div2_f64(lhs_, rhs_); - } else { - this->apply_type_error(c_self_name, - op_type_, lhs_, rhs_, p_psm); - return nullptr; - } - break; #endif case optype::n_optype: diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 1bc9066f..0634a564 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -151,6 +151,12 @@ namespace xo { this->cmple_binding_ = global_symtab_->lookup_binding(name); } + { + const DUniqueString * name = stringtable_.lookup("_cmpgt"); + assert(name); + this->cmpgt_binding_ = global_symtab_->lookup_binding(name); + } + { const DUniqueString * name = stringtable_.lookup("_cmpge"); assert(name); @@ -241,6 +247,15 @@ namespace xo { return retval; } + obj + ParserStateMachine::cmpgt_pm() const + { + obj retval = global_env_->lookup_value(cmpgt_binding_); + assert(retval); + + return retval; + } + obj ParserStateMachine::cmpge_pm() const { From e67117c815da605b6a44258a811028511e0c2de8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Mar 2026 09:47:14 -0500 Subject: [PATCH 296/342] xo-interpreter2 stack: modularize nth() primitive setup/install --- include/xo/reader2/ParserStateMachine.hpp | 1 + include/xo/reader2/SchematikaParser.hpp | 1 + include/xo/reader2/SchematikaReader.hpp | 3 +++ src/reader2/ParserStateMachine.cpp | 10 +++++----- src/reader2/SchematikaParser.cpp | 6 ++++++ src/reader2/SchematikaReader.cpp | 6 ++++++ 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 4f14f72a..a7726c35 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -90,6 +90,7 @@ namespace xo { obj expr_alloc() const noexcept { return expr_alloc_; } DGlobalSymtab * global_symtab() const noexcept { return global_symtab_.data(); } DLocalSymtab * local_symtab() const noexcept { return local_symtab_; } + DGlobalEnv * global_env() const noexcept { return global_env_.data(); } const ParserResult & result() const noexcept { return result_; } /** polymoprhihc multiply primitive. Use to implement infix op* **/ diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index ce7b3335..dd6ae341 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -184,6 +184,7 @@ namespace xo { ///@{ DGlobalSymtab * global_symtab() const noexcept; + DGlobalEnv * global_env() const noexcept; bool debug_flag() const { return debug_flag_; } diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index 5d20226e..0761b6e3 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -57,6 +57,9 @@ namespace xo { /** top-level symbol table **/ DGlobalSymtab * global_symtab() const noexcept; + /** top-level global environment (e.g. contains built-in primitives) **/ + DGlobalEnv * global_env() const noexcept; + /** visit reader-owned memory pools; call visitor(info) for each. * Specifically exclude expr_alloc, since we don't consider * that reader-owned diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 0634a564..5e6b4164 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -41,19 +41,17 @@ namespace xo { DGlobalSymtab * global_symtab, InstallFlags pm_install_flags) { + scope log(XO_DEBUG(true)); + DGlobalEnv * env = DGlobalEnv::_make(mm, global_symtab); - InstallSink sink = ([env, mm, &stringtable] + InstallSink sink = ([env, mm, &stringtable, &log] (std::string_view name, TypeDescr fn_td, obj pm, InstallFlags flags) { - scope log(XO_DEBUG(false)); - - log && log(xtag("name", name)); - (void)flags; obj pm_gco = pm.to_facet(); @@ -61,6 +59,8 @@ namespace xo { const DUniqueString * sym = stringtable.intern(name); + log && log("upsert", xtag("sym", std::string_view(*sym))); + env->_upsert_value(mm, sym, fn_td, diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index acfbeaa1..7d27e41c 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -42,6 +42,12 @@ namespace xo { return psm_.global_symtab(); } + DGlobalEnv * + SchematikaParser::global_env() const noexcept + { + return psm_.global_env(); + } + bool SchematikaParser::is_at_toplevel() const { diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index 98ef2292..de815f97 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -32,6 +32,12 @@ namespace xo { return parser_.global_symtab(); } + DGlobalEnv * + SchematikaReader::global_env() const noexcept + { + return parser_.global_env(); + } + void SchematikaReader::visit_pools(const MemorySizeVisitor & visitor) const { From 7b8e864668c0fa6c40cde7f4ca18cdbab3e99817 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Mar 2026 01:27:25 -0500 Subject: [PATCH 297/342] xo-interpreter2 stack: + stringtable() in RuntimeContext api --- include/xo/reader2/ParserStateMachine.hpp | 1 + include/xo/reader2/SchematikaParser.hpp | 1 + include/xo/reader2/SchematikaReader.hpp | 3 +++ src/reader2/SchematikaReader.cpp | 6 ++++++ 4 files changed, 11 insertions(+) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index a7726c35..2ea90466 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -88,6 +88,7 @@ namespace xo { bool debug_flag() const noexcept { return debug_flag_; } ParserStack * stack() const noexcept { return stack_; } obj expr_alloc() const noexcept { return expr_alloc_; } + StringTable * stringtable() noexcept { return &stringtable_; } DGlobalSymtab * global_symtab() const noexcept { return global_symtab_.data(); } DLocalSymtab * local_symtab() const noexcept { return local_symtab_; } DGlobalEnv * global_env() const noexcept { return global_env_.data(); } diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index dd6ae341..ce83dd8a 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -185,6 +185,7 @@ namespace xo { DGlobalSymtab * global_symtab() const noexcept; DGlobalEnv * global_env() const noexcept; + StringTable * stringtable() noexcept { return psm_.stringtable(); } bool debug_flag() const { return debug_flag_; } diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index 0761b6e3..8b24f775 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -60,6 +60,9 @@ namespace xo { /** top-level global environment (e.g. contains built-in primitives) **/ DGlobalEnv * global_env() const noexcept; + /** global unique-string table **/ + StringTable * stringtable() noexcept; + /** visit reader-owned memory pools; call visitor(info) for each. * Specifically exclude expr_alloc, since we don't consider * that reader-owned diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index de815f97..388c5266 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -38,6 +38,12 @@ namespace xo { return parser_.global_env(); } + StringTable * + SchematikaReader::stringtable() noexcept + { + return parser_.stringtable(); + } + void SchematikaReader::visit_pools(const MemorySizeVisitor & visitor) const { From 956a64df5cde382122b671c01b7e81f67d4d4563 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Mar 2026 09:03:24 -0500 Subject: [PATCH 298/342] xo-interpreter2 stack: + dict type + pop more pm types --- src/reader2/ParserStateMachine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 5e6b4164..6ab2097b 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -71,6 +71,7 @@ namespace xo { PrimitiveRegistry::instance() .install_primitives(mm, + &stringtable, sink, pm_install_flags); From 14bcd9dec63d30c6402bd856c6efe2b9d0bd0926 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Mar 2026 14:09:03 -0500 Subject: [PATCH 299/342] xo-interpreter2 stack: use RuntimeContext to streamline setup --- src/reader2/ParserStateMachine.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 6ab2097b..16871d22 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -9,6 +9,7 @@ #include "ToplevelSeqSsm.hpp" #include "DefineSsm.hpp" #include +#include #include #include #include @@ -26,6 +27,7 @@ namespace xo { using xo::print::APrintable; using xo::reflect::TypeDescr; using xo::facet::FacetRegistry; + using xo::facet::with_facet; namespace scm { namespace { @@ -46,7 +48,9 @@ namespace xo { DGlobalEnv * env = DGlobalEnv::_make(mm, global_symtab); - InstallSink sink = ([env, mm, &stringtable, &log] + DSimpleRcx rcx(mm, &stringtable); + + InstallSink sink = ([env, rcx, &log] (std::string_view name, TypeDescr fn_td, obj pm, @@ -57,11 +61,11 @@ namespace xo { obj pm_gco = pm.to_facet(); const DUniqueString * sym - = stringtable.intern(name); + = rcx.stringtable()->intern(name); log && log("upsert", xtag("sym", std::string_view(*sym))); - env->_upsert_value(mm, + env->_upsert_value(rcx.allocator(), sym, fn_td, pm_gco); @@ -70,8 +74,7 @@ namespace xo { }); PrimitiveRegistry::instance() - .install_primitives(mm, - &stringtable, + .install_primitives(with_facet::mkobj(&rcx), sink, pm_install_flags); From f4532235c09a9b595480dd70f0e9ab5ef249dfa7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Mar 2026 19:21:09 -0500 Subject: [PATCH 300/342] xo-reader2: streamline setup --- include/xo/reader2/SetupReader2.hpp | 25 +++++++++++++++ .../xo/reader2/reader2_register_facets.hpp | 15 --------- include/xo/reader2/reader2_register_types.hpp | 17 ---------- src/reader2/CMakeLists.txt | 3 +- ...2_register_facets.cpp => SetupReader2.cpp} | 22 ++++++++++--- src/reader2/init_reader2.cpp | 10 +++--- src/reader2/reader2_register_types.cpp | 32 ------------------- 7 files changed, 48 insertions(+), 76 deletions(-) create mode 100644 include/xo/reader2/SetupReader2.hpp delete mode 100644 include/xo/reader2/reader2_register_facets.hpp delete mode 100644 include/xo/reader2/reader2_register_types.hpp rename src/reader2/{reader2_register_facets.cpp => SetupReader2.cpp} (93%) delete mode 100644 src/reader2/reader2_register_types.cpp diff --git a/include/xo/reader2/SetupReader2.hpp b/include/xo/reader2/SetupReader2.hpp new file mode 100644 index 00000000..574bc296 --- /dev/null +++ b/include/xo/reader2/SetupReader2.hpp @@ -0,0 +1,25 @@ +/** @file SetupReader2.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include + +namespace xo { + namespace scm { + struct SetupReader2 { + public: + using ACollector = xo::mm::ACollector; + + public: + /** Register reader2 (facet,impl) combinations with FacetRegistry **/ + static bool register_facets(); + /** Register object types with @p gc **/ + static bool register_types(obj gc); + }; + } +} + +/* end SetupReader2.hpp */ diff --git a/include/xo/reader2/reader2_register_facets.hpp b/include/xo/reader2/reader2_register_facets.hpp deleted file mode 100644 index 6e606e40..00000000 --- a/include/xo/reader2/reader2_register_facets.hpp +++ /dev/null @@ -1,15 +0,0 @@ -/** @file reader2_register_facets.hpp - * - * @author Roland Conybeare, Jan 2026 - **/ - -#pragma once - -namespace xo { - namespace scm { - /** Register reader2 (facet,impl) combinations with FacetRegistry **/ - bool reader2_register_facets(); - } -} - -/* end reader2_register_facets.hpp */ diff --git a/include/xo/reader2/reader2_register_types.hpp b/include/xo/reader2/reader2_register_types.hpp deleted file mode 100644 index 1d8fea34..00000000 --- a/include/xo/reader2/reader2_register_types.hpp +++ /dev/null @@ -1,17 +0,0 @@ -/** @file reader2_register_types.hpp - * - * @author Roland Conybeare, Jan 2026 - **/ - -#pragma once - -#include - -namespace xo { - namespace scm { - /** Register reader2 gc-aware types with collector **/ - bool reader2_register_types(obj gc); - } -} - -/* end reader2_register_types.hpp */ diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index bb49efb8..3cbe3984 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -3,8 +3,7 @@ set(SELF_LIB xo_reader2) set(SELF_SRCS init_reader2.cpp - reader2_register_facets.cpp - reader2_register_types.cpp + SetupReader2.cpp SchematikaReader.cpp ReaderConfig.cpp diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/SetupReader2.cpp similarity index 93% rename from src/reader2/reader2_register_facets.cpp rename to src/reader2/SetupReader2.cpp index ccabe3a9..eef64bab 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/SetupReader2.cpp @@ -1,9 +1,9 @@ -/** @file reader2_register_facets.cpp +/** @file SetupReader2.cpp * * @author Roland Conybeare, Jan 2026 **/ -#include "reader2_register_facets.hpp" +#include "SetupReader2.hpp" #include "SchematikaParser.hpp" #include "ToplevelSeqSsm.hpp" @@ -33,14 +33,16 @@ namespace xo { using xo::print::APrintable; + using xo::mm::ACollector; using xo::mm::AGCObject; using xo::facet::FacetRegistry; using xo::facet::TypeRegistry; using xo::facet::typeseq; + using xo::facet::impl_for; namespace scm { bool - reader2_register_facets() + SetupReader2::register_facets() { scope log(XO_DEBUG(true)); @@ -135,7 +137,19 @@ namespace xo { return true; } + + bool + SetupReader2::register_types(obj gc) + { + scope log(XO_DEBUG(true)); + + bool ok = true; + + ok &= gc.install_type(impl_for()); + + return ok; + } } /*namespace scm*/ } /*namespace xo*/ -/* end reader2_register_facets.cpp */ +/* end SetupReader2.cpp */ diff --git a/src/reader2/init_reader2.cpp b/src/reader2/init_reader2.cpp index df0de7c0..46b4de00 100644 --- a/src/reader2/init_reader2.cpp +++ b/src/reader2/init_reader2.cpp @@ -4,24 +4,22 @@ **/ #include "init_reader2.hpp" -#include "reader2_register_facets.hpp" -#include "reader2_register_types.hpp" +#include "SetupReader2.hpp" #include #include #include namespace xo { - using xo::scm::reader2_register_facets; - using xo::scm::reader2_register_types; + using xo::scm::SetupReader2; using xo::mm::CollectorTypeRegistry; void InitSubsys::init() { - reader2_register_facets(); + SetupReader2::register_facets(); - CollectorTypeRegistry::instance().register_types(&reader2_register_types); + CollectorTypeRegistry::instance().register_types(&SetupReader2::register_types); } InitEvidence diff --git a/src/reader2/reader2_register_types.cpp b/src/reader2/reader2_register_types.cpp deleted file mode 100644 index 3d6a0fe0..00000000 --- a/src/reader2/reader2_register_types.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/** @file reader2_register_types.cpp - * - * @author Roland Conybeare, Jan 2026 - **/ - -#include "reader2_register_types.hpp" -#include "GlobalEnv.hpp" - -#include - -namespace xo { - using xo::mm::ACollector; - using xo::mm::AGCObject; - using xo::facet::impl_for; - using xo::scope; - - namespace scm { - bool - reader2_register_types(obj gc) - { - scope log(XO_DEBUG(true)); - - bool ok = true; - - ok &= gc.install_type(impl_for()); - - return ok; - } - } -} /*namespace xo*/ - -/* end reader2_register_types.cpp */ From a3a5311250e4cab8c2d042d06169007930cd16e8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 17 Mar 2026 12:49:35 -0400 Subject: [PATCH 301/342] xo-reader2: bugfix genfacet paths + move DParenSsm --- idl/IGCObject_DGlobalEnv.json5 | 2 +- idl/IPrintable_DGlobalEnv.json5 | 4 ++-- idl/IPrintable_DParenSsm.json5 | 2 +- idl/ISyntaxStateMachine_DParenSsm.json5 | 2 +- include/xo/reader2/ParenSsm.hpp | 2 +- include/xo/reader2/{ => paren}/DParenSsm.hpp | 0 include/xo/reader2/{ssm => paren}/IPrintable_DParenSsm.hpp | 0 .../reader2/{ssm => paren}/ISyntaxStateMachine_DParenSsm.hpp | 0 src/reader2/IPrintable_DParenSsm.cpp | 2 +- src/reader2/ISyntaxStateMachine_DParenSsm.cpp | 2 +- 10 files changed, 8 insertions(+), 8 deletions(-) rename include/xo/reader2/{ => paren}/DParenSsm.hpp (100%) rename include/xo/reader2/{ssm => paren}/IPrintable_DParenSsm.hpp (100%) rename include/xo/reader2/{ssm => paren}/ISyntaxStateMachine_DParenSsm.hpp (100%) diff --git a/idl/IGCObject_DGlobalEnv.json5 b/idl/IGCObject_DGlobalEnv.json5 index 1a590527..c3d666dd 100644 --- a/idl/IGCObject_DGlobalEnv.json5 +++ b/idl/IGCObject_DGlobalEnv.json5 @@ -1,7 +1,7 @@ { mode: "implementation", output_cpp_dir: "src/reader2/facet", - output_hpp_dir: "include/xo/interpreter2", + output_hpp_dir: "include/xo/reader2", output_impl_subdir: "env", includes: [ "", diff --git a/idl/IPrintable_DGlobalEnv.json5 b/idl/IPrintable_DGlobalEnv.json5 index 0a05eb62..9e48847e 100644 --- a/idl/IPrintable_DGlobalEnv.json5 +++ b/idl/IPrintable_DGlobalEnv.json5 @@ -1,7 +1,7 @@ { mode: "implementation", - output_cpp_dir: "src/interpreter2/facet", - output_hpp_dir: "include/xo/interpreter2", + output_cpp_dir: "src/reader2/facet", + output_hpp_dir: "include/xo/reader2", output_impl_subdir: "env", includes: [ "", "" ], diff --git a/idl/IPrintable_DParenSsm.json5 b/idl/IPrintable_DParenSsm.json5 index 9750cb31..6735436c 100644 --- a/idl/IPrintable_DParenSsm.json5 +++ b/idl/IPrintable_DParenSsm.json5 @@ -2,7 +2,7 @@ mode: "implementation", output_cpp_dir: "src/reader2", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "paren", includes: [ "", "" ], local_types: [], diff --git a/idl/ISyntaxStateMachine_DParenSsm.json5 b/idl/ISyntaxStateMachine_DParenSsm.json5 index 7ea19fc0..dcdb298c 100644 --- a/idl/ISyntaxStateMachine_DParenSsm.json5 +++ b/idl/ISyntaxStateMachine_DParenSsm.json5 @@ -2,7 +2,7 @@ mode: "implementation", output_cpp_dir: "src/reader2", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "paren", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/include/xo/reader2/ParenSsm.hpp b/include/xo/reader2/ParenSsm.hpp index a9a786fd..30dc4ee5 100644 --- a/include/xo/reader2/ParenSsm.hpp +++ b/include/xo/reader2/ParenSsm.hpp @@ -5,7 +5,7 @@ #pragma once -#include "DParenSsm.hpp" +#include "paren/DParenSsm.hpp" #include "ssm/ISyntaxStateMachine_DParenSsm.hpp" #include "ssm/IPrintable_DParenSsm.hpp" diff --git a/include/xo/reader2/DParenSsm.hpp b/include/xo/reader2/paren/DParenSsm.hpp similarity index 100% rename from include/xo/reader2/DParenSsm.hpp rename to include/xo/reader2/paren/DParenSsm.hpp diff --git a/include/xo/reader2/ssm/IPrintable_DParenSsm.hpp b/include/xo/reader2/paren/IPrintable_DParenSsm.hpp similarity index 100% rename from include/xo/reader2/ssm/IPrintable_DParenSsm.hpp rename to include/xo/reader2/paren/IPrintable_DParenSsm.hpp diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp b/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp similarity index 100% rename from include/xo/reader2/ssm/ISyntaxStateMachine_DParenSsm.hpp rename to include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp diff --git a/src/reader2/IPrintable_DParenSsm.cpp b/src/reader2/IPrintable_DParenSsm.cpp index b2228f7f..7cda341b 100644 --- a/src/reader2/IPrintable_DParenSsm.cpp +++ b/src/reader2/IPrintable_DParenSsm.cpp @@ -11,7 +11,7 @@ * [idl/IPrintable_DParenSsm.json5] **/ -#include "ssm/IPrintable_DParenSsm.hpp" +#include "paren/IPrintable_DParenSsm.hpp" namespace xo { namespace scm { diff --git a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp index 05f5d4cc..555ae683 100644 --- a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp @@ -11,7 +11,7 @@ * [idl/ISyntaxStateMachine_DParenSsm.json5] **/ -#include "ssm/ISyntaxStateMachine_DParenSsm.hpp" +#include "paren/ISyntaxStateMachine_DParenSsm.hpp" namespace xo { namespace scm { From ed3b5bfb4e443697e945df744f62a6f6e337dbde Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 17 Mar 2026 12:50:22 -0400 Subject: [PATCH 302/342] xo-reader2: bugfix: ParenSsm include paths --- include/xo/reader2/ParenSsm.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/xo/reader2/ParenSsm.hpp b/include/xo/reader2/ParenSsm.hpp index 30dc4ee5..ff03da9b 100644 --- a/include/xo/reader2/ParenSsm.hpp +++ b/include/xo/reader2/ParenSsm.hpp @@ -6,7 +6,7 @@ #pragma once #include "paren/DParenSsm.hpp" -#include "ssm/ISyntaxStateMachine_DParenSsm.hpp" -#include "ssm/IPrintable_DParenSsm.hpp" +#include "paren/ISyntaxStateMachine_DParenSsm.hpp" +#include "paren/IPrintable_DParenSsm.hpp" /* end ParenSsm.hpp */ From f4514fc6676beef3ed6256c4bea41d0f6287cfc0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 17 Mar 2026 12:57:41 -0400 Subject: [PATCH 303/342] xo-reader2: refactor: move ExpectFormalArgSsm support -> subdir --- idl/IPrintable_DExpectFormalArgSsm.json5 | 4 ++-- idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 | 4 ++-- include/xo/reader2/ExpectFormalArgSsm.hpp | 6 +++--- .../{ => expect_formal_arg}/DExpectFormalArgSsm.hpp | 0 .../IPrintable_DExpectFormalArgSsm.hpp | 0 .../ISyntaxStateMachine_DExpectFormalArgSsm.hpp | 0 src/reader2/CMakeLists.txt | 4 ++-- src/reader2/DExpectFormalArgSsm.cpp | 13 +++---------- src/reader2/DExpectFormalArglistSsm.cpp | 8 ++++---- .../{ => facet}/IPrintable_DExpectFormalArgSsm.cpp | 2 +- .../ISyntaxStateMachine_DExpectFormalArgSsm.cpp | 2 +- 11 files changed, 18 insertions(+), 25 deletions(-) rename include/xo/reader2/{ => expect_formal_arg}/DExpectFormalArgSsm.hpp (100%) rename include/xo/reader2/{ssm => expect_formal_arg}/IPrintable_DExpectFormalArgSsm.hpp (100%) rename include/xo/reader2/{ssm => expect_formal_arg}/ISyntaxStateMachine_DExpectFormalArgSsm.hpp (100%) rename src/reader2/{ => facet}/IPrintable_DExpectFormalArgSsm.cpp (91%) rename src/reader2/{ => facet}/ISyntaxStateMachine_DExpectFormalArgSsm.cpp (97%) diff --git a/idl/IPrintable_DExpectFormalArgSsm.json5 b/idl/IPrintable_DExpectFormalArgSsm.json5 index 73389166..2c2dbaab 100644 --- a/idl/IPrintable_DExpectFormalArgSsm.json5 +++ b/idl/IPrintable_DExpectFormalArgSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "expect_formal_arg", includes: [ "", "" ], local_types: [], diff --git a/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 b/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 index e3486759..e3ae1ac5 100644 --- a/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 +++ b/idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "expect_formal_arg", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/include/xo/reader2/ExpectFormalArgSsm.hpp b/include/xo/reader2/ExpectFormalArgSsm.hpp index f0aaa9ed..fc3dbe52 100644 --- a/include/xo/reader2/ExpectFormalArgSsm.hpp +++ b/include/xo/reader2/ExpectFormalArgSsm.hpp @@ -5,8 +5,8 @@ #pragma once -#include "DExpectFormalArgSsm.hpp" -#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" -#include "ssm/IPrintable_DExpectFormalArgSsm.hpp" +#include "expect_formal_arg/DExpectFormalArgSsm.hpp" +#include "expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" +#include "expect_formal_arg/IPrintable_DExpectFormalArgSsm.hpp" /* end ExpectFormalArgSsm.hpp */ diff --git a/include/xo/reader2/DExpectFormalArgSsm.hpp b/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp similarity index 100% rename from include/xo/reader2/DExpectFormalArgSsm.hpp rename to include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp diff --git a/include/xo/reader2/ssm/IPrintable_DExpectFormalArgSsm.hpp b/include/xo/reader2/expect_formal_arg/IPrintable_DExpectFormalArgSsm.hpp similarity index 100% rename from include/xo/reader2/ssm/IPrintable_DExpectFormalArgSsm.hpp rename to include/xo/reader2/expect_formal_arg/IPrintable_DExpectFormalArgSsm.hpp diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp similarity index 100% rename from include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp rename to include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 3cbe3984..dd88bbd6 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -57,8 +57,8 @@ set(SELF_SRCS IPrintable_DExpectFormalArglistSsm.cpp DExpectFormalArgSsm.cpp - ISyntaxStateMachine_DExpectFormalArgSsm.cpp - IPrintable_DExpectFormalArgSsm.cpp + facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp + facet/IPrintable_DExpectFormalArgSsm.cpp DExpectSymbolSsm.cpp ISyntaxStateMachine_DExpectSymbolSsm.cpp diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index b8c5f425..eeecdc54 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -3,16 +3,9 @@ * @author Roland Conybeare, Jan 2026 **/ -#include "DExpectFormalArgSsm.hpp" -#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" -#include "DExpectSymbolSsm.hpp" -#include "ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp" -#include "DExpectTypeSsm.hpp" -#include "ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp" - -#ifdef NOT_YET -#include "xo/expression/Variable.hpp" -#endif +#include "ExpectFormalArgSsm.hpp" +#include "ExpectSymbolSsm.hpp" +#include "ExpectTypeSsm.hpp" namespace xo { using xo::scm::DVariable; diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index d68beef5..0c367547 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -3,10 +3,10 @@ * @author Roland Conybeare, Jan 2026 */ -#include "DExpectFormalArglistSsm.hpp" -#include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" -#include "DExpectFormalArgSsm.hpp" -#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" +#include "ExpectFormalArglistSsm.hpp" +//#include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" +#include "ExpectFormalArgSsm.hpp" +//#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" #include #include #include diff --git a/src/reader2/IPrintable_DExpectFormalArgSsm.cpp b/src/reader2/facet/IPrintable_DExpectFormalArgSsm.cpp similarity index 91% rename from src/reader2/IPrintable_DExpectFormalArgSsm.cpp rename to src/reader2/facet/IPrintable_DExpectFormalArgSsm.cpp index 13164b15..bdcf6a61 100644 --- a/src/reader2/IPrintable_DExpectFormalArgSsm.cpp +++ b/src/reader2/facet/IPrintable_DExpectFormalArgSsm.cpp @@ -11,7 +11,7 @@ * [idl/IPrintable_DExpectFormalArgSsm.json5] **/ -#include "ssm/IPrintable_DExpectFormalArgSsm.hpp" +#include "expect_formal_arg/IPrintable_DExpectFormalArgSsm.hpp" namespace xo { namespace scm { diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp similarity index 97% rename from src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp rename to src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp index 1089d5ee..96a7fb29 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArgSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp @@ -11,7 +11,7 @@ * [idl/ISyntaxStateMachine_DExpectFormalArgSsm.json5] **/ -#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" +#include "expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" namespace xo { namespace scm { From 90c4819ef9cdc49730e53a52e59b71ce93c08e8a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 17 Mar 2026 21:02:37 -0400 Subject: [PATCH 304/342] delete unused typo file --- src/reader2/DExepctQListSsm.cpp | 255 -------------------------------- 1 file changed, 255 deletions(-) delete mode 100644 src/reader2/DExepctQListSsm.cpp diff --git a/src/reader2/DExepctQListSsm.cpp b/src/reader2/DExepctQListSsm.cpp deleted file mode 100644 index 44393451..00000000 --- a/src/reader2/DExepctQListSsm.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* @file DExpectQListSsm.cpp - * - * @author Roland Conybeare, Mar 2026 - */ - -#include "ExpectQLiteralSsm.hpp" -#include -//#include "DExpectFormalArgSsm.hpp" -//#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" -//#include -//#include -//#include -//#include -//#include -#include - -namespace xo { -// using xo::print::APrintable; -// using xo::print::ppstate; -// using xo::print::ppindentinfo; - using xo::mm::AGCObject; -// using xo::mm::AAllocator; -// using xo::facet::FacetRegistry; -// using xo::reflect::typeseq; - - namespace scm { -#ifdef NOT_USING - const char * - formalarglstatetype_descr(formalarglstatetype x) { - switch (x) { - case formalarglstatetype::invalid: - return "invalid"; - case formalarglstatetype::argl_0: - return "argl_0"; - case formalarglstatetype::argl_1a: - return "argl_1a"; - case formalarglstatetype::argl_1b: - return "argl_1b"; - case formalarglstatetype::n_formalarglstatetype: - break; - } - - return "?formalarglstatetype"; - } -#endif - - DExpectQListSsm::DExpectQListSsm() - {} - - DExpectQListSsm * - DExpectQListSsm::_make(DArena & arena) - { - /* out-of-order so argl follows ssm in arena, - * consistent with any subsequent arglist realloc. - * Not a load-bearing choice however - */ - - void * mem = arena.alloc_for(); - - return new (mem) DExpectQListSsm(); - } - - obj - DExpectQListSsm::make(DArena & arena) - { - obj retval(_make(arena)); - - return retval; - } - - void - DExpectQListSsm::start(ParserStateMachine * p_psm) - { - DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); - - p_psm->push_ssm(ckp, DExpectQListSsm::make(p_psm->parser_alloc())); - } - - syntaxstatetype - DExpectQListSsm::ssm_type() const noexcept { - return syntaxstatetype::expect_qliteral; - } - - std::string_view - DExpectQListSsm::get_expect_str() const - { - return "leftparen|leftbracket|leftbrace|string|f64|i64|bool"; - } - - void - DExpectQListSsm::on_token(const Token & tk, - ParserStateMachine * p_psm) - { - switch (tk.tk_type()) { - case tokentype::tk_f64: - this->on_f64_token(tk, p_psm); - return; - - case tokentype::tk_leftparen: - case tokentype::tk_comma: - case tokentype::tk_rightparen: - case tokentype::tk_lambda: - case tokentype::tk_def: - case tokentype::tk_if: - case tokentype::tk_symbol: - case tokentype::tk_colon: - case tokentype::tk_singleassign: - case tokentype::tk_string: - case tokentype::tk_i64: - case tokentype::tk_bool: - case tokentype::tk_semicolon: - case tokentype::tk_invalid: - case tokentype::tk_quote: - case tokentype::tk_leftbracket: - case tokentype::tk_rightbracket: - case tokentype::tk_leftbrace: - case tokentype::tk_rightbrace: - case tokentype::tk_leftangle: - case tokentype::tk_rightangle: - case tokentype::tk_lessequal: - case tokentype::tk_greatequal: - case tokentype::tk_dot: - case tokentype::tk_doublecolon: - case tokentype::tk_assign: - case tokentype::tk_yields: - case tokentype::tk_plus: - case tokentype::tk_minus: - case tokentype::tk_star: - case tokentype::tk_slash: - case tokentype::tk_cmpeq: - case tokentype::tk_cmpne: - case tokentype::tk_type: - case tokentype::tk_then: - case tokentype::tk_else: - case tokentype::tk_let: - case tokentype::tk_in: - case tokentype::tk_end: - case tokentype::N: - break; - } - - Super::on_token(tk, p_psm); - } - - void - DExpectQListSsm::on_f64_token(const Token & tk, - ParserStateMachine * p_psm) - { - auto literal = DFloat::box(p_psm->expr_alloc(), - tk.f64_value()); - - p_psm->pop_ssm(); - p_psm->on_quoted_literal(literal); - } - -#ifdef NOT_YET - void - DExpectQListSsm::_accept_formal(obj expr_alloc, - DArena & parser_alloc, - const DUniqueString * param_name, - TypeDescr param_type) - { - /* note: param_type can be nullptr */ - TypeRef typeref - = TypeRef::dwim(TypeRef::prefix_type::from_chars("formal"), param_type); - - DVariable * var = DVariable::make(expr_alloc, - param_name, - typeref); - - // need AGCObject facet to use DArray here. - // May want to have gc feature that allows it to use - // FacetRegistry on memory that stores obj - // - // In this case doesn't matter since DExpectQListSsm not actually collected! - - obj var_o(var); - - if (argl_->size() == argl_->capacity()) { - // need to expand argl_ capacity. - // If DArena were to allow it (i.e. offer a realloc() feature, - // could do this in place since this SSM is at the top of the parser stack. - - obj mm(&parser_alloc); - DArray * argl_2x = DArray::empty(mm, 2 * argl_->capacity()); - - for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { - // TODO: prefer non-bounds-checked access here - argl_2x->push_back(argl_->at(i)); - } - - // update in place - this->argl_ = argl_2x; - } - - this->argl_->push_back(var_o); - } -#endif - -#ifdef NOT_YET - void - DExpectQListSsm::on_leftparen_token(const Token & tk, - ParserStateMachine * p_psm) - { - if (fastate_ == formalarglstatetype::argl_0) { - this->fastate_ = formalarglstatetype::argl_1a; - - DExpectFormalArgSsm::start(p_psm); - return; - } - - Super::on_token(tk, p_psm); - } - - void - DExpectQListSsm::on_comma_token(const Token & tk, - ParserStateMachine * p_psm) - { - if (fastate_ == formalarglstatetype::argl_1b) { - this->fastate_ = formalarglstatetype::argl_1a; - - DExpectFormalArgSsm::start(p_psm); - return; - } - - Super::on_token(tk, p_psm); - } - - void - DExpectQListSsm::on_rightparen_token(const Token & tk, - ParserStateMachine * p_psm) - { - if (fastate_ == formalarglstatetype::argl_1b) { - DArray * args = argl_; - - p_psm->pop_ssm(); - p_psm->on_parsed_formal_arglist(args); - return; - } - - Super::on_token(tk, p_psm); - } -#endif - - bool - DExpectQListSsm::pretty(const ppindentinfo & ppii) const - { - return ppii.pps()->pretty_struct(ppii, - "DExpectQListSsm", - refrtag("expect", this->get_expect_str())); - } - } /*namespace scm*/ -} /*namespace xo*/ - -/* end DExpectQListSsm.cpp */ From 25fd378c78bbc616e4805340b157d72d456371a0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 17 Mar 2026 21:04:08 -0400 Subject: [PATCH 305/342] xo-reader2: #q supports literal dictionaries --- CMakeLists.txt | 16 ++ idl/IPrintable_DExpectQDictSsm.json5 | 16 ++ idl/ISyntaxStateMachine_DExpectQDictSsm.json5 | 16 ++ include/xo/reader2/DExpectQListSsm.hpp | 8 +- include/xo/reader2/DExpectQLiteralSsm.hpp | 20 +- include/xo/reader2/ExpectQDictSsm.hpp | 12 + .../reader2/expect_qdict/DExpectQDictSsm.hpp | 178 ++++++++++++ .../IPrintable_DExpectQDictSsm.hpp | 62 ++++ .../ISyntaxStateMachine_DExpectQDictSsm.hpp | 84 ++++++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 6 +- src/reader2/DExpectQDictSsm.cpp | 270 ++++++++++++++++++ src/reader2/DExpectQListSsm.cpp | 2 + src/reader2/DExpectQLiteralSsm.cpp | 74 ++--- src/reader2/SetupReader2.cpp | 5 + .../facet/IPrintable_DExpectQDictSsm.cpp | 28 ++ .../ISyntaxStateMachine_DExpectQDictSsm.cpp | 84 ++++++ src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 90 ++++++ 19 files changed, 919 insertions(+), 57 deletions(-) create mode 100644 idl/IPrintable_DExpectQDictSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DExpectQDictSsm.json5 create mode 100644 include/xo/reader2/ExpectQDictSsm.hpp create mode 100644 include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp create mode 100644 include/xo/reader2/expect_qdict/IPrintable_DExpectQDictSsm.hpp create mode 100644 include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp create mode 100644 src/reader2/DExpectQDictSsm.cpp create mode 100644 src/reader2/facet/IPrintable_DExpectQDictSsm.cpp create mode 100644 src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a88c83e0..9c009aab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -321,6 +321,22 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqdictssm + FACET_PKG xo_reader2 + INPUT idl/ISyntaxStateMachine_DExpectQDictSsm.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expectqdictssm + FACET_PKG xo_printable2 + INPUT idl/IPrintable_DExpectQDictSsm.json5 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqarrayssm diff --git a/idl/IPrintable_DExpectQDictSsm.json5 b/idl/IPrintable_DExpectQDictSsm.json5 new file mode 100644 index 00000000..0569712d --- /dev/null +++ b/idl/IPrintable_DExpectQDictSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2/facet", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "expect_qdict", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectQDictSsm", + using_doxygen: true, + repr: "DExpectQDictSsm", + doc: [ "implement APrintable for DExpectQDictSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DExpectQDictSsm.json5 b/idl/ISyntaxStateMachine_DExpectQDictSsm.json5 new file mode 100644 index 00000000..ee440bcd --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectQDictSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2/facet", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "expect_qdict", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectQDictSsm", + using_doxygen: true, + repr: "DExpectQDictSsm", + doc: [ "implement ASyntaxStateMachine for DExpectQDictSsm" ], +} diff --git a/include/xo/reader2/DExpectQListSsm.hpp b/include/xo/reader2/DExpectQListSsm.hpp index 1ccd0bbe..770821bc 100644 --- a/include/xo/reader2/DExpectQListSsm.hpp +++ b/include/xo/reader2/DExpectQListSsm.hpp @@ -7,7 +7,6 @@ #include "DSyntaxStateMachine.hpp" #include -//#include #include namespace xo { @@ -16,13 +15,14 @@ namespace xo { * Already in quoted-literal context * * ( quote-expr ... ) - * ^ ^ ^ - * | qlist_1a qlist_2(done) - * qlist_0 + * ^ ^ ^ ^ + * | qlist_1a | qlist_2(done) + * qlist_0 qlist_1a * * qlist_0 --on_leftparen_token()--> qlist_1a [push ExpectQLiteralSsm] * qlist_1a --on_quoted_literal()--> qlist_1a [append literal] * qlist_1a --on_rightparen_token()--> qlist_2(done) [report quoted list] + * qlist_2 end state **/ class QListXst { public: diff --git a/include/xo/reader2/DExpectQLiteralSsm.hpp b/include/xo/reader2/DExpectQLiteralSsm.hpp index 7073283a..6beb3430 100644 --- a/include/xo/reader2/DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/DExpectQLiteralSsm.hpp @@ -6,8 +6,6 @@ #pragma once #include "DSyntaxStateMachine.hpp" -//#include -//#include namespace xo { namespace scm { @@ -46,17 +44,23 @@ namespace xo { static const char * ssm_classname() { return "DExpectQLiteralSsm"; } /** update state for f64 token @p tk, with overall parser state in @p p_psm. - * delegates to parent ssm via @ref on_quoted_literal + * completes syntax + delegates to parent ssm via @ref on_quoted_literal **/ void on_f64_token(const Token & tk, ParserStateMachine * p_psm); /** update state for i64 token @p tk, with overall parser state in @p p_psm. - * delegates to parent ssm via @ref on_quoted_literal + * completes syntax + delegates to parent ssm via @ref on_quoted_literal **/ void on_i64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for string token @p tk, with overall parser state in @p p_psm. + * completes syntax + delegates to parent ssm via @ref on_quoted_literal + **/ + void on_string_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state on incoming token @p tk, * with overall parser state in @p p_psm. * @@ -89,6 +93,14 @@ namespace xo { void on_rightbracket_token(const Token & tk, ParserStateMachine * p_psm); + /** update state on incoming leftbrace token @p tk, + * with overall parser state in @p p_psm. + * + * Forward in-place to ExpectQDictSsm + **/ + void on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expectformalarglistssm-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/include/xo/reader2/ExpectQDictSsm.hpp b/include/xo/reader2/ExpectQDictSsm.hpp new file mode 100644 index 00000000..447e5cc7 --- /dev/null +++ b/include/xo/reader2/ExpectQDictSsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectQDictSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "expect_qdict/DExpectQDictSsm.hpp" +#include "expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp" +#include "expect_qdict/IPrintable_DExpectQDictSsm.hpp" + +/* end ExpectQDictSsm.hpp */ diff --git a/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp new file mode 100644 index 00000000..c03b2414 --- /dev/null +++ b/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp @@ -0,0 +1,178 @@ +/** @file DExpectQDictSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +#include +#include + +namespace xo { + namespace scm { + /** + * When this syntax is active, parser is already in a quoted-literal context + * + * { key(1) : value(1) ; ... ; } + * ^ ^ ^ ^ ^ ^ ^ ^ + * | | | qdict_1c | | | qdict_2(done) + * | | qdict_1b | | qdict_1d + * | qdict_1a | qdict_1a + * qdict_0 qdict_1d + * + * qdict_0 --on_leftbrace_token()--> qdict_1a [push ExpectSymbolSsm] + * qdict_1a --on_parsed_symbol()--> qdict_1b [remember key] + * qdict_1a --onrightbace_token()--> qdictZ(done) + * qdict_1b --on_colon_token()--> qdict_1c [push ExpectQLiteralSsm] + * qdict_1c --on_quoted_literal()--> qdict_1d [remember value] + * qdict_1d --on_semicolon_token()--> qdict_1a [loop] + * qdict_1d --on_rightbrace_token()--> qdict_2(done) + **/ + class QDictXst { + public: + enum class code { + invalid = -1, + + qdict_0, + qdict_1a, + qdict_1b, + qdict_1c, + qdict_1d, + qdict_2, + + N + }; + + explicit QDictXst(code x) : code_{x} {} + + /** @return string representation for enum @p x **/ + static const char * _descr(code x); + + code code() const noexcept { return code_; } + + enum code code_; + }; + + inline std::ostream & + operator<< (std::ostream & os, QDictXst x) { + os << QDictXst::_descr(x.code_); + return os; + } + + class DExpectQDictSsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; + + public: + /** @defgroup scm-expectqdictssm-ctors constructors **/ + ///@{ + + DExpectQDictSsm(); + + /** create instance using memory from @parser_mm **/ + static obj make(DArena & parser_mm); + /** create instance using memory from @parser_mm **/ + static DExpectQDictSsm * _make(DArena & parser_mm); + + /** start nested syntax for a quoted dictionary **/ + static void start(ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqdictssm-methods general methods **/ + ///@{ + + static const char * ssm_classname() { return "DExpectQDictSsm"; } + + /** update state on incoming leftbrace token @p tk, + * with overall parser state in @p p_psm + * + * in qdict_0 advance state to qdict_1a; otherwise error + **/ + void on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on parsed symbol @p sym emitted by nested ssm, + * with overall parser state in @p p_psm + * + * in qdict_1a capture key string + advance to qdict_1b; otherwise error + **/ + void on_symbol_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on incoming colon token @p tk, + * with overall parser state in @p p_psm + * + * in qdict_1b advance to qdict_1c + push ExpectQLiteralSsm; otherwise error + **/ + void on_colon_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state in on incoming semicolon token @p tk, + * with overall parser state in @p p_psm. + * + * in qdict_1d advance to qdict_1a (ready for another (key,value) pair); otherwise error + **/ + void on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on incoming rightbrace token @p tk, + * with overall parser state in @p p_psm + * + * in qdict_1a complete syntax + report literal to parent ssm; otherwise error + **/ + void on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqdictssm-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** mnemonic *for expected input (for this ssm) in current state **/ + std::string_view get_expect_str() const; + + /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on quoted literal @p lit, with overall parser state in @p p_psm + * + * in qdict_1c capture (key,value) pair into dictionary + advance to qdict_1d; otherwise error + **/ + void on_quoted_literal(obj lit, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqdictssm-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + /** @defgroup ssm-expectqdictssm-member-vars **/ + ///@{ + + /** iddentifies qdict parsing state **/ + QDictXst state_; + + /** captured key in next (key,value) pair; + * expect to include in @ref dict_ + **/ + const DString * key_ = nullptr; + + /** literal dictionary (assembled incrementally) **/ + DDictionary * dict_ = nullptr; + + ///@} + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectQDictSsm.hpp */ diff --git a/include/xo/reader2/expect_qdict/IPrintable_DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/IPrintable_DExpectQDictSsm.hpp new file mode 100644 index 00000000..b5bb39d9 --- /dev/null +++ b/include/xo/reader2/expect_qdict/IPrintable_DExpectQDictSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectQDictSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQDictSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQDictSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectQDictSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectQDictSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectQDictSsm + **/ + class IPrintable_DExpectQDictSsm { + public: + /** @defgroup scm-printable-dexpectqdictssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpectqdictssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectQDictSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp new file mode 100644 index 00000000..5c46cdd9 --- /dev/null +++ b/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp @@ -0,0 +1,84 @@ +/** @file ISyntaxStateMachine_DExpectQDictSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQDictSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQDictSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectQDictSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectQDictSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectQDictSsm + **/ + class ISyntaxStateMachine_DExpectQDictSsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpectqdictssm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexpectqdictssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectQDictSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectQDictSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectQDictSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectQDictSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectQDictSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DExpectQDictSsm & self, obj type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectQDictSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DExpectQDictSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExpectQDictSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for nested parsed expression @p expr **/ + static void on_parsed_expression(DExpectQDictSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExpectQDictSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectQDictSsm & self, obj lit, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index dd34054a..c1dbfae6 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -75,6 +75,9 @@ namespace xo { /** expecting a quoted array. See @ref DExpectQArraySsm **/ expect_qarray, + /** expecting a quoted dictionary. See @ref DExpectQDictSsm **/ + expect_qdict, + /** comes last, counts number of valid enums **/ N }; diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index dd88bbd6..73e9ea37 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -88,6 +88,10 @@ set(SELF_SRCS ISyntaxStateMachine_DExpectQArraySsm.cpp IPrintable_DExpectQArraySsm.cpp + DExpectQDictSsm.cpp + facet/ISyntaxStateMachine_DExpectQDictSsm.cpp + facet/IPrintable_DExpectQDictSsm.cpp + DProgressSsm.cpp ISyntaxStateMachine_DProgressSsm.cpp IPrintable_DProgressSsm.cpp @@ -107,8 +111,6 @@ xo_dependency(${SELF_LIB} xo_type) xo_dependency(${SELF_LIB} xo_tokenizer2) xo_dependency(${SELF_LIB} xo_expression2) #xo_dependency(${SELF_LIB} reflect) -#xo_dependency(${SELF_LIB} xo_object2) -#xo_dependency(${SELF_LIB} xo_printable2) #xo_dependency(${SELF_LIB} xo_flatstring) xo_dependency(${SELF_LIB} subsys) #xo_dependency(${SELF_LIB} indentlog) diff --git a/src/reader2/DExpectQDictSsm.cpp b/src/reader2/DExpectQDictSsm.cpp new file mode 100644 index 00000000..7566c130 --- /dev/null +++ b/src/reader2/DExpectQDictSsm.cpp @@ -0,0 +1,270 @@ +/** @file DExpectQDictSsm.cpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#include "ExpectQDictSsm.hpp" +#include "ExpectQLiteralSsm.hpp" + +namespace xo { + using xo::print::APrintable; + + namespace scm { + + const char * + QDictXst::_descr(enum code x) + { + switch (x) { + case code::invalid: break; + case code::qdict_0: return "qdict_0"; + case code::qdict_1a: return "qdict_1a"; + case code::qdict_1b: return "qdict_1b"; + case code::qdict_1c: return "qdict_1c"; + case code::qdict_1d: return "qdict_1d"; + case code::qdict_2: return "qdict_2"; + case code::N: break; + } + + return "?QDictXst"; + } + + DExpectQDictSsm::DExpectQDictSsm() : state_{QDictXst::code::qdict_0} {} + + obj + DExpectQDictSsm::make(DArena & parser_mm) + { + return obj(_make(parser_mm)); + } + + DExpectQDictSsm * + DExpectQDictSsm::_make(DArena & parser_mm) + { + void * mem = parser_mm.alloc_for(); + + return new (mem) DExpectQDictSsm(); + } + + void + DExpectQDictSsm::start(ParserStateMachine * p_psm) + { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DExpectQDictSsm::make(p_psm->parser_alloc())); + } + + syntaxstatetype + DExpectQDictSsm::ssm_type() const noexcept { + return syntaxstatetype::expect_qdict; + } + + std::string_view + DExpectQDictSsm::get_expect_str() const { + switch (state_.code()) { + case QDictXst::code::qdict_0: + return "leftbrace"; + case QDictXst::code::qdict_1a: + return "symbol|rightbrace"; + case QDictXst::code::qdict_1b: + return "colon"; + case QDictXst::code::qdict_1c: + return "literal"; + case QDictXst::code::qdict_1d: + return "semicolon|rightbrace"; + case QDictXst::code::qdict_2: + return "(done)"; + case QDictXst::code::invalid: + case QDictXst::code::N: + break; + } + + return "?DExpectQDictSsm"; + } + + void + DExpectQDictSsm::on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QDictXst::code::qdict_0) { + constexpr DDictionary::size_type hint_cap = 8; + + this->state_ = QDictXst(QDictXst::code::qdict_1a); + this->dict_ = DDictionary::empty(p_psm->expr_alloc(), hint_cap); + + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + if ((state_.code() == QDictXst::code::qdict_1a) + || (state_.code() == QDictXst::code::qdict_1d)) + { + + this->state_ = QDictXst(QDictXst::code::qdict_2); + + obj lit = obj(dict_); + + p_psm->pop_ssm(); + p_psm->on_quoted_literal(lit); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_symbol_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QDictXst::code::qdict_1a) { + this->state_ = QDictXst(QDictXst::code::qdict_1b); + this->key_ = DString::from_view(p_psm->expr_alloc(), std::string_view(tk.text())); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_colon_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QDictXst::code::qdict_1b) { + this->state_ = QDictXst(QDictXst::code::qdict_1c); + + DExpectQLiteralSsm::start(p_psm, + false /*!cxl_on_rightparen*/); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QDictXst::code::qdict_1d) { + this->state_ = QDictXst(QDictXst::code::qdict_1a); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch(tk.tk_type()) + { + case tokentype::tk_leftbrace: + this->on_leftbrace_token(tk, p_psm); + return; + + case tokentype::tk_symbol: + this->on_symbol_token(tk, p_psm); + return; + + case tokentype::tk_rightbrace: + this->on_rightbrace_token(tk, p_psm); + return; + + case tokentype::tk_colon: + this->on_colon_token(tk, p_psm); + return; + + case tokentype::tk_semicolon: + this->on_semicolon_token(tk, p_psm); + return; + + case tokentype::tk_rightparen: + case tokentype::tk_comma: + case tokentype::tk_lambda: + case tokentype::tk_def: + case tokentype::tk_deftype: + case tokentype::tk_if: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_invalid: + case tokentype::tk_quote: + case tokentype::tk_leftparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_cmple: + case tokentype::tk_cmpge: + case tokentype::tk_dot: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_nil: + case tokentype::tk_type: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_quoted_literal(obj lit, + ParserStateMachine * p_psm) + { + if (state_.code() == QDictXst::code::qdict_1c) { + // adjoin (key,value) pair into dictionary + + this->state_ = QDictXst(QDictXst::code::qdict_1d); + + assert(dict_); + + bool ok = dict_->upsert(p_psm->expr_alloc(), DDictionary::pair_type(key_, lit)); + + this->key_ = nullptr; + + assert(ok); + + return; + } + + Super::illegal_quoted_literal(lit, p_psm); + } + + bool + DExpectQDictSsm::pretty(const ppindentinfo & ppii) const + { + obj dict(dict_); + obj dict_pr(dict_); + + return ppii.pps()->pretty_struct(ppii, + "DExpectQDictSsm", + refrtag("state", state_), + refrtag("expect", this->get_expect_str()), + refrtag("key", key_, key_), + refrtag("dict", dict_pr)); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectQDictSsm.cpp */ diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp index 50cde338..b767f939 100644 --- a/src/reader2/DExpectQListSsm.cpp +++ b/src/reader2/DExpectQListSsm.cpp @@ -132,6 +132,8 @@ namespace xo { case tokentype::N: break; } + + Super::illegal_token(tk, p_psm); } void diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index 89e79b85..a1b7b2ce 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -6,14 +6,10 @@ #include "ExpectQLiteralSsm.hpp" #include "ExpectQListSsm.hpp" #include "ExpectQArraySsm.hpp" +#include "ExpectQDictSsm.hpp" #include #include -//#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" -//#include -//#include -//#include -//#include -//#include +#include #include namespace xo { @@ -95,6 +91,10 @@ namespace xo { this->on_i64_token(tk, p_psm); return; + case tokentype::tk_string: + this->on_string_token(tk, p_psm); + return; + case tokentype::tk_leftparen: this->on_leftparen_token(tk, p_psm); return; @@ -111,6 +111,10 @@ namespace xo { this->on_rightbracket_token(tk, p_psm); return; + case tokentype::tk_leftbrace: + this->on_leftbrace_token(tk, p_psm); + return; + case tokentype::tk_comma: case tokentype::tk_lambda: case tokentype::tk_def: @@ -119,12 +123,10 @@ namespace xo { case tokentype::tk_symbol: case tokentype::tk_colon: case tokentype::tk_singleassign: - case tokentype::tk_string: case tokentype::tk_bool: case tokentype::tk_semicolon: case tokentype::tk_invalid: case tokentype::tk_quote: - case tokentype::tk_leftbrace: case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: @@ -176,49 +178,16 @@ namespace xo { p_psm->on_quoted_literal(literal); } -#ifdef NOT_YET void - DExpectQLiteralSsm::_accept_formal(obj expr_alloc, - DArena & parser_alloc, - const DUniqueString * param_name, - TypeDescr param_type) + DExpectQLiteralSsm::on_string_token(const Token & tk, + ParserStateMachine * p_psm) { - /* note: param_type can be nullptr */ - TypeRef typeref - = TypeRef::dwim(TypeRef::prefix_type::from_chars("formal"), param_type); + auto literal = obj(DString::from_view(p_psm->expr_alloc(), + std::string_view(tk.text()))); - DVariable * var = DVariable::make(expr_alloc, - param_name, - typeref); - - // need AGCObject facet to use DArray here. - // May want to have gc feature that allows it to use - // FacetRegistry on memory that stores obj - // - // In this case doesn't matter since DExpectQLiteralSsm not actually collected! - - obj var_o(var); - - if (argl_->size() == argl_->capacity()) { - // need to expand argl_ capacity. - // If DArena were to allow it (i.e. offer a realloc() feature, - // could do this in place since this SSM is at the top of the parser stack. - - obj mm(&parser_alloc); - DArray * argl_2x = DArray::empty(mm, 2 * argl_->capacity()); - - for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { - // TODO: prefer non-bounds-checked access here - argl_2x->push_back(argl_->at(i)); - } - - // update in place - this->argl_ = argl_2x; - } - - this->argl_->push_back(var_o); + p_psm->pop_ssm(); + p_psm->on_quoted_literal(literal); } -#endif void DExpectQLiteralSsm::on_leftparen_token(const Token & tk, @@ -268,6 +237,17 @@ namespace xo { Super::illegal_token(tk, p_psm); } + void + DExpectQLiteralSsm::on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + // replace self with specialized version for parsing a literal dict + + p_psm->pop_ssm(); + DExpectQDictSsm::start(p_psm); + p_psm->on_token(tk); + } + bool DExpectQLiteralSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/SetupReader2.cpp b/src/reader2/SetupReader2.cpp index eef64bab..62536329 100644 --- a/src/reader2/SetupReader2.cpp +++ b/src/reader2/SetupReader2.cpp @@ -25,6 +25,7 @@ #include "ExpectExprSsm.hpp" #include "ExpectQLiteralSsm.hpp" #include "ExpectQListSsm.hpp" +#include "ExpectQDictSsm.hpp" #include "ExpectQArraySsm.hpp" #include @@ -107,6 +108,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); @@ -128,6 +132,7 @@ namespace xo { log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); log && log(xtag("DExpectQLiteralSsm.tseq", typeseq::id())); log && log(xtag("DExpectQListSsm.tseq", typeseq::id())); + log && log(xtag("DExpectQDictSsm.tseq", typeseq::id())); log && log(xtag("DExpectQArraySsm.tseq", typeseq::id())); log && log(xtag("DProgressSsm.tseq", typeseq::id())); diff --git a/src/reader2/facet/IPrintable_DExpectQDictSsm.cpp b/src/reader2/facet/IPrintable_DExpectQDictSsm.cpp new file mode 100644 index 00000000..ae6f4423 --- /dev/null +++ b/src/reader2/facet/IPrintable_DExpectQDictSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectQDictSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQDictSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQDictSsm.json5] +**/ + +#include "expect_qdict/IPrintable_DExpectQDictSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectQDictSsm::pretty(const DExpectQDictSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectQDictSsm.cpp */ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp new file mode 100644 index 00000000..60ec4af4 --- /dev/null +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp @@ -0,0 +1,84 @@ +/** @file ISyntaxStateMachine_DExpectQDictSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQDictSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQDictSsm.json5] +**/ + +#include "expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectQDictSsm::ssm_type(const DExpectQDictSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectQDictSsm::get_expect_str(const DExpectQDictSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectQDictSsm::on_token(DExpectQDictSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_symbol(DExpectQDictSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_typedescr(DExpectQDictSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_type(DExpectQDictSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_formal(DExpectQDictSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_formal_with_token(DExpectQDictSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_formal_arglist(DExpectQDictSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_expression(DExpectQDictSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_expression_with_token(DExpectQDictSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_quoted_literal(DExpectQDictSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectQDictSsm.cpp */ diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index 5968b1bb..8ca07af2 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -51,6 +51,8 @@ namespace xo { return "expect-qlist"; case syntaxstatetype::expect_qarray: return "expect-qarray"; + case syntaxstatetype::expect_qdict: + return "expect-qdict"; case syntaxstatetype::N: break; } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 4d3f943b..23821872 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1609,6 +1609,96 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-batch-qdict0", "[reader2][SchematikaParser]") + { + // top-level recursive function definition + + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * #q{ {} }; + * ^ ^ ^^ ^^ + * 0 1 2| 4| + * 3 5 + **/ + + std::vector tk_v{ + /* [ 0] */ Token::quote_token(), + /* [ 1] */ Token::leftbrace_token(), + + /* [ 2] */ Token::leftbrace_token(), + /* [ 3] */ Token::rightbrace_token(), + + /* [ 4] */ Token::rightbrace_token(), + /* [ 5] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); + } + + TEST_CASE("SchematikaParser-batch-qdict1", "[reader2][SchematikaParser]") + { + // top-level recursive function definition + + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * #q{ {name: "kobold"; alignment: "chaotic evil"; hp: 15} }; + * ^ ^ ^^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^^ + * 0 1 2| 4 5 6 7 8 9 a b c d e f| + * 3 g + **/ + + std::vector tk_v{ + /* [ 0] */ Token::quote_token(), + /* [ 1] */ Token::leftbrace_token(), + + /* [ 2] */ Token::leftbrace_token(), + + /* [ 3] */ Token::symbol_token("name"), + /* [ 4] */ Token::colon_token(), + /* [ 5] */ Token::string_token("kobold"), + /* [ 6] */ Token::semicolon_token(), + + /* [ 7] */ Token::symbol_token("alignment"), + /* [ 8] */ Token::colon_token(), + /* [ 9] */ Token::string_token("chaotic evil"), + /* [ a] */ Token::semicolon_token(), + + /* [ b] */ Token::symbol_token("hp"), + /* [ c] */ Token::colon_token(), + /* [ d] */ Token::i64_token("15"), + + /* [ e] */ Token::rightbrace_token(), + /* [ f] */ Token::rightbrace_token(), + /* [ g] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); + } + } /*namespace ut*/ } /*namespace xo*/ From ed3e26e718e8e7853de30e2dc8e006d9db1544de Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 24 Mar 2026 17:35:26 -0400 Subject: [PATCH 306/342] nix: use clang-tools (for emacs+lsp) --- .../{SchematikaParser.hpp => parser/DSchematikaParser.hpp} | 0 src/reader2/{SchematikaParser.cpp => DSchematikaParser.cpp} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename include/xo/reader2/{SchematikaParser.hpp => parser/DSchematikaParser.hpp} (100%) rename src/reader2/{SchematikaParser.cpp => DSchematikaParser.cpp} (100%) diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/parser/DSchematikaParser.hpp similarity index 100% rename from include/xo/reader2/SchematikaParser.hpp rename to include/xo/reader2/parser/DSchematikaParser.hpp diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/DSchematikaParser.cpp similarity index 100% rename from src/reader2/SchematikaParser.cpp rename to src/reader2/DSchematikaParser.cpp From 3af72fec64904f0861a3d5b6656776fe7a044a07 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 24 Mar 2026 17:43:45 -0400 Subject: [PATCH 307/342] xo-reader2: + SyntaxStateMachine.forward_children method Support gc traversal with goal of making ParserStateMachine a gc root --- DESIGN.md | 9 +++ idl/SyntaxStateMachine.json5 | 12 +++- include/xo/reader2/DDefineSsm.hpp | 8 +++ include/xo/reader2/DExpectExprSsm.hpp | 8 +++ .../xo/reader2/DExpectFormalArglistSsm.hpp | 8 +++ include/xo/reader2/DExpectQArraySsm.hpp | 8 +++ include/xo/reader2/DExpectQListSsm.hpp | 8 +++ include/xo/reader2/DExpectQLiteralSsm.hpp | 8 +++ include/xo/reader2/DExpectSymbolSsm.hpp | 8 +++ include/xo/reader2/DExpectTypeSsm.hpp | 8 +++ include/xo/reader2/DProgressSsm.hpp | 8 +++ include/xo/reader2/DQuoteSsm.hpp | 7 ++ include/xo/reader2/DSequenceSsm.hpp | 12 +++- include/xo/reader2/DToplevelSeqSsm.hpp | 8 +++ include/xo/reader2/ParserResult.hpp | 4 ++ include/xo/reader2/ParserStack.hpp | 5 ++ include/xo/reader2/ParserStateMachine.hpp | 53 ++++++++++++-- include/xo/reader2/apply/DApplySsm.hpp | 8 +++ .../apply/ISyntaxStateMachine_DApplySsm.hpp | 3 + include/xo/reader2/deftype/DDeftypeSsm.hpp | 8 +++ .../ISyntaxStateMachine_DDeftypeSsm.hpp | 3 + .../expect_formal_arg/DExpectFormalArgSsm.hpp | 8 +++ ...SyntaxStateMachine_DExpectFormalArgSsm.hpp | 3 + .../expect_listtype/DExpectListTypeSsm.hpp | 8 +++ ...ISyntaxStateMachine_DExpectListTypeSsm.hpp | 3 + .../reader2/expect_qdict/DExpectQDictSsm.hpp | 8 +++ .../ISyntaxStateMachine_DExpectQDictSsm.hpp | 3 + include/xo/reader2/ifelse/DIfElseSsm.hpp | 8 +++ .../ifelse/ISyntaxStateMachine_DIfElseSsm.hpp | 3 + include/xo/reader2/lambda/DLambdaSsm.hpp | 8 +++ .../lambda/ISyntaxStateMachine_DLambdaSsm.hpp | 3 + include/xo/reader2/paren/DParenSsm.hpp | 8 +++ .../paren/ISyntaxStateMachine_DParenSsm.hpp | 3 + .../xo/reader2/parser/DSchematikaParser.hpp | 70 +++++++++++++++---- .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 12 +++- .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 2 + .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 3 + .../ISyntaxStateMachine_DExpectExprSsm.hpp | 3 + ...axStateMachine_DExpectFormalArglistSsm.hpp | 3 + .../ISyntaxStateMachine_DExpectQArraySsm.hpp | 3 + .../ISyntaxStateMachine_DExpectQListSsm.hpp | 3 + ...ISyntaxStateMachine_DExpectQLiteralSsm.hpp | 3 + .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 3 + .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 3 + .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 3 + .../ssm/ISyntaxStateMachine_DQuoteSsm.hpp | 3 + .../ssm/ISyntaxStateMachine_DSequenceSsm.hpp | 3 + .../ISyntaxStateMachine_DToplevelSeqSsm.hpp | 3 + .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 5 ++ .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 4 ++ src/reader2/DApplySsm.cpp | 11 ++- src/reader2/DDefineSsm.cpp | 10 ++- src/reader2/DDeftypeSsm.cpp | 6 ++ src/reader2/DExpectExprSsm.cpp | 6 ++ src/reader2/DExpectFormalArgSsm.cpp | 6 ++ src/reader2/DExpectFormalArglistSsm.cpp | 22 +++--- src/reader2/DExpectListTypeSsm.cpp | 7 ++ src/reader2/DExpectQArraySsm.cpp | 7 ++ src/reader2/DExpectQDictSsm.cpp | 9 +++ src/reader2/DExpectQListSsm.cpp | 8 +++ src/reader2/DExpectQLiteralSsm.cpp | 6 ++ src/reader2/DExpectSymbolSsm.cpp | 6 ++ src/reader2/DExpectTypeSsm.cpp | 6 ++ src/reader2/DIfElseSsm.cpp | 6 ++ src/reader2/DLambdaSsm.cpp | 9 +++ src/reader2/DParenSsm.cpp | 6 ++ src/reader2/DProgressSsm.cpp | 8 +++ src/reader2/DQuoteSsm.cpp | 6 ++ src/reader2/DSequenceSsm.cpp | 9 ++- src/reader2/DToplevelSeqSsm.cpp | 6 ++ src/reader2/ISyntaxStateMachine_Any.cpp | 6 ++ .../ISyntaxStateMachine_DDefineSsm.cpp | 5 ++ .../ISyntaxStateMachine_DExpectExprSsm.cpp | 5 ++ ...axStateMachine_DExpectFormalArglistSsm.cpp | 5 ++ .../ISyntaxStateMachine_DExpectQArraySsm.cpp | 5 ++ .../ISyntaxStateMachine_DExpectQListSsm.cpp | 5 ++ ...ISyntaxStateMachine_DExpectQLiteralSsm.cpp | 5 ++ .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 5 ++ .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 5 ++ src/reader2/ISyntaxStateMachine_DParenSsm.cpp | 5 ++ .../ISyntaxStateMachine_DProgressSsm.cpp | 5 ++ src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp | 5 ++ .../ISyntaxStateMachine_DSequenceSsm.cpp | 5 ++ .../ISyntaxStateMachine_DToplevelSeqSsm.cpp | 5 ++ .../facet/ISyntaxStateMachine_DApplySsm.cpp | 5 ++ .../facet/ISyntaxStateMachine_DDeftypeSsm.cpp | 5 ++ ...SyntaxStateMachine_DExpectFormalArgSsm.cpp | 5 ++ ...ISyntaxStateMachine_DExpectListTypeSsm.cpp | 5 ++ .../ISyntaxStateMachine_DExpectQDictSsm.cpp | 5 ++ .../facet/ISyntaxStateMachine_DIfElseSsm.cpp | 5 ++ .../facet/ISyntaxStateMachine_DLambdaSsm.cpp | 5 ++ 91 files changed, 626 insertions(+), 39 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index 73e863e3..11a8a6ef 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -2,6 +2,15 @@ Uses arena allocators for fast+efficient parsing. Composition of nested state machines. +## SchematikaParser + +Parser to convert schematika text to expressions. + +### Details + +Partial GCObject facet support, so a SchmeatikaParser instance can +be a gc root. + ## SyntaxStateMachine a state machine dedicated to some particular Schematika syntax. diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 0238749c..8450b02b 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -10,13 +10,14 @@ "", "", "", + "" ], // extra includes in SyntaxStateMachine.hpp, if any user_hpp_includes: [], namespace1: "xo", namespace2: "scm", // text after includes, before ASyntaxStateMachine - pretext: ["// {pretex} here"], + pretext: ["// {pretext} here"], facet: "SyntaxStateMachine", detail_subdir: "ssm", brief: "specialized state machine for parsing some particular schematika syntax", @@ -26,6 +27,7 @@ ], types: [ { name: "TypeDescr", doc: [ "reflected c++ type" ], definition: "xo::reflect::TypeDescr" }, + { name: "ACollector", doc: [ "gc interface" ], definition: "xo::mm::ACollector" }, { name: "AGCObject", doc: [ "gc-aware object" ], definition: "xo::mm::AGCObject" }, // { name: string, doc: [ string ], definition: string }, ], @@ -143,6 +145,14 @@ {type: "obj", name: "lit"}, {type: "ParserStateMachine *", name: "p_psm"}, ], + }, + { + name: "forward_children", + doc: ["gc support: move immediate children to to-space and sub forwarding pointer"], + return_type: "void", + args: [ + {type: "obj", name: "gc"}, + ], } ], router_facet_explicit_content: [ ], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 6380a233..e372e299 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -73,6 +73,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -195,6 +196,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-define-gc-support **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc); + + ///@} private: /** @defgroup scm-definessm-member-vars **/ diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 66189754..a1ba1c69 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -18,6 +18,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -190,6 +191,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-expectexprssm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** if true: allow a define-expression here; otherwise reject **/ diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index 3129f0dc..f28cbac1 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -55,6 +55,7 @@ namespace xo { class DExpectFormalArglistSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -125,6 +126,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-expectformalarglistssm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** @defgroup scm-expectformalarglistssm-impl-methods **/ diff --git a/include/xo/reader2/DExpectQArraySsm.hpp b/include/xo/reader2/DExpectQArraySsm.hpp index 929460dc..068a5b93 100644 --- a/include/xo/reader2/DExpectQArraySsm.hpp +++ b/include/xo/reader2/DExpectQArraySsm.hpp @@ -58,6 +58,7 @@ namespace xo { class DExpectQArraySsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -119,6 +120,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-expectqarrayssm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** @defgroup scm-expectqarrayssm-member-vars **/ diff --git a/include/xo/reader2/DExpectQListSsm.hpp b/include/xo/reader2/DExpectQListSsm.hpp index 770821bc..c2119c8b 100644 --- a/include/xo/reader2/DExpectQListSsm.hpp +++ b/include/xo/reader2/DExpectQListSsm.hpp @@ -58,6 +58,7 @@ namespace xo { class DExpectQListSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -119,6 +120,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-expectqlistssm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** @defgroup scm-expectqlistssm-member-vars **/ diff --git a/include/xo/reader2/DExpectQLiteralSsm.hpp b/include/xo/reader2/DExpectQLiteralSsm.hpp index 6beb3430..f037c7d8 100644 --- a/include/xo/reader2/DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/DExpectQLiteralSsm.hpp @@ -15,6 +15,7 @@ namespace xo { class DExpectQLiteralSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -124,6 +125,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-expectqliteralssm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** @defgroup scm-expectformalarglistssm-impl-methods **/ diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index b621985b..9ca3e1a0 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -21,6 +21,7 @@ namespace xo { class DExpectSymbolSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; + using ACollector = xo::mm::ACollector; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; using ppindentinfo = xo::print::ppindentinfo; @@ -74,6 +75,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; + ///@} + /** @defgroup scm-expectsymbolssm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + ///@} }; } /*namespace scm*/ diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 2901c95a..7fae992d 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -28,6 +28,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -82,6 +83,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-expecttypessm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** temporary shim. diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index cc0eb0c5..487ba141 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -90,6 +90,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -214,6 +215,13 @@ namespace xo { void print(std::ostream & os) const override; #endif + /** @defgroup scm-progressssm-gc-support gc support methods **/ + ///@{ + + void forward_children(obj gc) noexcept; + + ///@} + private: /** populate an expression here, may be followed by an operator **/ obj lhs_; diff --git a/include/xo/reader2/DQuoteSsm.hpp b/include/xo/reader2/DQuoteSsm.hpp index 26079e8e..fa598f83 100644 --- a/include/xo/reader2/DQuoteSsm.hpp +++ b/include/xo/reader2/DQuoteSsm.hpp @@ -65,6 +65,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -145,7 +146,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-quotessm-gc-support gc support methods */ + ///@{ + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** @defgroup scm-parenssm-member-vars **/ ///@{ diff --git a/include/xo/reader2/DSequenceSsm.hpp b/include/xo/reader2/DSequenceSsm.hpp index 486187fc..e3c699c3 100644 --- a/include/xo/reader2/DSequenceSsm.hpp +++ b/include/xo/reader2/DSequenceSsm.hpp @@ -29,8 +29,7 @@ namespace xo { class DSequenceSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; - //using Sequence = xo::scm::Sequence; - //using Lambda = xo::scm::Lambda; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -87,13 +86,20 @@ namespace xo { ParserStateMachine * p_psm); ///@} - /** @defgroup scm-sequencessm-printable-facet printable facet **/ + /** @defgroup scm-sequencessm-printable-facet printable facet methods **/ ///@{ /** pretty printing support **/ bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-sequencessm-gcobject-facet gcobject facet methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: explicit DSequenceSsm(DSequenceExpr * seq_expr); diff --git a/include/xo/reader2/DToplevelSeqSsm.hpp b/include/xo/reader2/DToplevelSeqSsm.hpp index 2466ed1e..b33707e4 100644 --- a/include/xo/reader2/DToplevelSeqSsm.hpp +++ b/include/xo/reader2/DToplevelSeqSsm.hpp @@ -40,6 +40,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -156,6 +157,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-toplevelseqssm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** sequence type. accept rvalue expressions when diff --git a/include/xo/reader2/ParserResult.hpp b/include/xo/reader2/ParserResult.hpp index 9cdf1424..73ab38c6 100644 --- a/include/xo/reader2/ParserResult.hpp +++ b/include/xo/reader2/ParserResult.hpp @@ -32,6 +32,7 @@ namespace xo { class ParserResult { public: + using ACollector = xo::mm::ACollector; using ppindentinfo = xo::print::ppindentinfo; public: @@ -67,6 +68,9 @@ namespace xo { /** pretty-printing support **/ bool pretty(const ppindentinfo & ppii) const; + /** gc support: forward gc-eligible children **/ + void forward_children(obj gc) noexcept; + public: /** none|expression|error_description * diff --git a/include/xo/reader2/ParserStack.hpp b/include/xo/reader2/ParserStack.hpp index ef5705e9..80049a07 100644 --- a/include/xo/reader2/ParserStack.hpp +++ b/include/xo/reader2/ParserStack.hpp @@ -21,6 +21,7 @@ namespace xo { **/ class ParserStack { public: + using ACollector = xo::mm::ACollector; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -42,6 +43,8 @@ namespace xo { static ParserStack * pop(ParserStack * stack, DArena & mm); + static constexpr bool is_gc_eligible() { return false; } + DArena::Checkpoint ckp() const noexcept { return ckp_; } obj top() const noexcept { return ssm_; } ParserStack * parent() const noexcept { return parent_; } @@ -51,6 +54,8 @@ namespace xo { /** pretty-printer support **/ bool pretty(const ppindentinfo & ppii) const; + void forward_children(obj gc) noexcept; + private: /** stack pointer: top of stack just before this instance created **/ DArena::Checkpoint ckp_; diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 2ea90466..f5001faa 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -7,8 +7,8 @@ #include "ParserResult.hpp" #include "GlobalEnv.hpp" -#include -#include +#include +#include #include #include #include @@ -38,6 +38,7 @@ namespace xo { class ParserStateMachine { public: using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using ArenaConfig = xo::mm::ArenaConfig; using AGCObject = xo::mm::AGCObject; @@ -66,6 +67,13 @@ namespace xo { * (e.g. DArenaHashMap for global symtable). * If not using X1Collector, this can be the * same as @p expr_alloc. + * + * NOTE: + * When @p expr_alloc supports the Collector facet: + * ParserStateMachine isn't itself in gc-space + * (i.e. isn't expected to belong to @p expr_alloc). + * To update pointers to gc-owned objects, must have forward_children() + * called as part of @p expr_alloc's gc cycle. **/ ParserStateMachine(const ArenaConfig & config, const ArenaHashMapConfig & symtab_var_config, @@ -81,6 +89,8 @@ namespace xo { /** non-trivial dtor for @ref global_symtab_ **/ ~ParserStateMachine(); + static constexpr bool is_gc_eligible() { return false; } + ///@} /** @defgroup scm-parserstatemachine-accessors accessor methods **/ ///@{ @@ -90,7 +100,7 @@ namespace xo { obj expr_alloc() const noexcept { return expr_alloc_; } StringTable * stringtable() noexcept { return &stringtable_; } DGlobalSymtab * global_symtab() const noexcept { return global_symtab_.data(); } - DLocalSymtab * local_symtab() const noexcept { return local_symtab_; } + DLocalSymtab * local_symtab() const noexcept { return local_symtab_.data(); } DGlobalEnv * global_env() const noexcept { return global_env_.data(); } const ParserResult & result() const noexcept { return result_; } @@ -175,7 +185,6 @@ namespace xo { void clear_error_reset(); ///@} - /** @defgroup scm-parserstatemachine-inputmethods input methods **/ ///@{ @@ -339,8 +348,37 @@ namespace xo { std::string_view sym); ///@} + /** @defgroup scm-parserstatemachine-gcobject-facet gc support **/ + ///@{ + +#ifdef OBSOLETE + std::size_t shallow_size() const noexcept; + /** NOTE: + * ParserStateMachine only eligible to be a GC root. + * It's not eligible to reside in gc-owned space + **/ + ParserStateMachine * shallow_copy(obj mm) const noexcept; + std::size_t forward_children(obj gc) noexcept; +#endif + /** update gc-aware exit pointers from this ParserStateMachine **/ + void forward_children(obj gc) noexcept; + + ///@} private: +#ifdef OBSOLETE + /** @defgroup scm-parserstatemachine-impl-methods implementation methods **/ + ///@{ + + /** record gc-mutable state vars so they're updated when gc runs **/ + void _add_gc_roots(); + + ///@} +#endif + + private: + /** @defgroup scm-parserstatemachine-instance-vars instance variables **/ + ///@{ /** Table containing interned strings + symbols. **/ @@ -348,6 +386,7 @@ namespace xo { /** Arena for internal parsing stack. * Must be owned exclusively because destructively + * modified as parser completes parsing of each sub-expression * * Contents will be a stack of ExprState instances @@ -403,7 +442,7 @@ namespace xo { * if so, along with stringtable_. * maybe new struct ParserState? **/ - dp global_symtab_; + obj global_symtab_; /** symbol table with local bindings. * non-null during parsing of lambda expressions. @@ -411,7 +450,7 @@ namespace xo { * Push local symbol table here to remember local params * during the body of a lambda expression. **/ - DLocalSymtab * local_symtab_ = nullptr; + obj local_symtab_; /** global variable bindings (builtin primitives) **/ obj global_env_; @@ -435,6 +474,8 @@ namespace xo { /** true to enable debug output **/ bool debug_flag_ = false; + + ///@} }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/apply/DApplySsm.hpp b/include/xo/reader2/apply/DApplySsm.hpp index 9357fc39..64513f0c 100644 --- a/include/xo/reader2/apply/DApplySsm.hpp +++ b/include/xo/reader2/apply/DApplySsm.hpp @@ -65,6 +65,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -185,6 +186,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-applyssm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** @defgroup ssm-applyssm-impl-methods **/ diff --git a/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp b/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp index 0b0f6972..04c7bddb 100644 --- a/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp +++ b/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dapplyssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DApplySsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DApplySsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DApplySsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/deftype/DDeftypeSsm.hpp b/include/xo/reader2/deftype/DDeftypeSsm.hpp index 29a1d691..a3e4c6cb 100644 --- a/include/xo/reader2/deftype/DDeftypeSsm.hpp +++ b/include/xo/reader2/deftype/DDeftypeSsm.hpp @@ -66,6 +66,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -167,6 +168,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-deftypessm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** @defgroup scm-deftypessm-member-vars **/ diff --git a/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp b/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp index 114f2dab..f3776f18 100644 --- a/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp +++ b/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-ddeftypessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DDeftypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DDeftypeSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DDeftypeSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp b/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp index f1bd7867..318e340a 100644 --- a/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp @@ -48,6 +48,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -121,6 +122,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-expectformalargssm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} #ifdef PROBABLY_NOT virtual void on_rightparen_token(const token_type & tk, diff --git a/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp index 2c6da502..7e100e40 100644 --- a/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectformalargssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectFormalArgSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectFormalArgSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DExpectFormalArgSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp b/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp index 38f04ca1..6e7c80b4 100644 --- a/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp +++ b/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp @@ -62,6 +62,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -129,6 +130,13 @@ namespace xo { /** pretty-printing support **/ bool pretty(const ppindentinfo & ppii) const; + ///@} + /** @defgroup scm-expectlisttypessm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + ///@} private: /** @defgroup scm-expectlisttypessm-instance-vars instance variables **/ diff --git a/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp b/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp index 37a653f9..153c47a4 100644 --- a/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp +++ b/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectlisttypessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectListTypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectListTypeSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DExpectListTypeSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp index c03b2414..31aa2be3 100644 --- a/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp +++ b/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp @@ -63,6 +63,7 @@ namespace xo { class DExpectQDictSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; + using ACollector = xo::mm::ACollector; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -154,6 +155,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-expectqdictssm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** @defgroup ssm-expectqdictssm-member-vars **/ diff --git a/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp index 5c46cdd9..7014238f 100644 --- a/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp +++ b/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectqdictssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectQDictSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQDictSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DExpectQDictSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ifelse/DIfElseSsm.hpp b/include/xo/reader2/ifelse/DIfElseSsm.hpp index cded3e6f..27043bdf 100644 --- a/include/xo/reader2/ifelse/DIfElseSsm.hpp +++ b/include/xo/reader2/ifelse/DIfElseSsm.hpp @@ -55,6 +55,7 @@ namespace xo { class DIfElseSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -167,6 +168,13 @@ namespace xo { parserstatemachine * p_psm) override; #endif + /** @defgroup scm-ifelsessm-gc-support gc support methods **/ + ///@{ + + void forward_children(obj gc) noexcept; + + ///@} + private: #ifdef NOT_YET static std::unique_ptr make(); diff --git a/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp index 6b9dd33f..8a3991fb 100644 --- a/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp +++ b/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-difelsessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DIfElseSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DIfElseSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DIfElseSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/lambda/DLambdaSsm.hpp b/include/xo/reader2/lambda/DLambdaSsm.hpp index 5ecbecd2..1fa1eac9 100644 --- a/include/xo/reader2/lambda/DLambdaSsm.hpp +++ b/include/xo/reader2/lambda/DLambdaSsm.hpp @@ -59,6 +59,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using DLocalSymtab = xo::scm::DLocalSymtab; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -184,6 +185,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-lambdassm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + + ///@} private: diff --git a/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp index 8ba94c58..f10f376e 100644 --- a/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp +++ b/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dlambdassm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DLambdaSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DLambdaSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DLambdaSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/paren/DParenSsm.hpp b/include/xo/reader2/paren/DParenSsm.hpp index 05c3926b..af9daa91 100644 --- a/include/xo/reader2/paren/DParenSsm.hpp +++ b/include/xo/reader2/paren/DParenSsm.hpp @@ -50,6 +50,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -131,6 +132,13 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-parenssm-gc-support gc support methods **/ + ///@{ + + /** gc support: visit immediate gc-aware children **/ + void forward_children(obj gc) noexcept; + + ///@} private: /** @defgroup scm-parenssm-member-vars **/ diff --git a/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp b/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp index ef74a525..c2bbcc21 100644 --- a/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp +++ b/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dparenssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DParenSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DParenSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DParenSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/parser/DSchematikaParser.hpp b/include/xo/reader2/parser/DSchematikaParser.hpp index ce83dd8a..18e7989c 100644 --- a/include/xo/reader2/parser/DSchematikaParser.hpp +++ b/include/xo/reader2/parser/DSchematikaParser.hpp @@ -1,4 +1,4 @@ -/** @file SchematikaParser.hpp +/** @file DSchematikaParser.hpp * * @author Roland Conybeare, Jan 2026 **/ @@ -151,13 +151,21 @@ namespace xo { * | => * | > * + * ---------------------------------------------------------------- + * NOTES: + * - SchematikaParser partially supports the gcobject facet so it can be a collector root node. + * It's not actually moveable (since its ParserStateMachine member isn't moveable), + * Only the forward_children method is load-bearing. + * **/ - class SchematikaParser { + class DSchematikaParser { public: using token_type = Token; using ArenaHashMapConfig = xo::map::ArenaHashMapConfig; using ArenaConfig = xo::mm::ArenaConfig; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; + using AGCObject = xo::mm::AGCObject; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using ppindentinfo = xo::print::ppindentinfo; using size_type = std::size_t; @@ -173,12 +181,36 @@ namespace xo { * with lifetime bounded by this * SchematikeParser itself **/ - SchematikaParser(const ParserConfig & config, - obj expr_alloc, - obj aux_alloc); + DSchematikaParser(const ParserConfig & config, + obj expr_alloc, + obj aux_alloc); /** non-trivial dtor because of @ref psm_ **/ - ~SchematikaParser() = default; + ~DSchematikaParser() = default; + + /** create parser in initial state. + * + * @p mm allocate SchematikaParser instance from here. + * (likely the same as aux_alloc) + * @p config parser configuration + * @p expr_alloc allocator for schematika expressions. + * Probably shared with execution. + * @p aux_alloc aux allocator for non-copyable memory + * with lifetime bounded by this + * SchematikeParser itself + **/ + static DSchematikaParser * _make(obj mm, + const ParserConfig & config, + obj expr_alloc, + obj aux_alloc); + + /** like _make(mm,config,expr_alloc,aux_alloc), + * but as fop + **/ + static obj make(obj mm, + const ParserConfig & config, + obj expr_alloc, + obj aux_alloc); /** scm-schematikaparser-access-methods **/ ///@{ @@ -248,7 +280,7 @@ namespace xo { void reset_to_idle_toplevel(); ///@} - /** scm-schematikaparser-pretty-methods **/ + /** @defgroup scm-schematikaparser-pretty-methods **/ ///@{ /** print human-readable representation on stream @p os **/ @@ -257,18 +289,32 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; ///@} + /** @defgroup scm-schematikaparser-gcobject-methods **/ + ///@{ + std::size_t shallow_size() const noexcept; + /** not implemented (SchematikaParser not designed to be copyable) **/ + DSchematikaParser * shallow_copy(obj mm) const noexcept; + /** forward gc-aware children **/ + std::size_t forward_children(obj gc) noexcept; + + ///@} private: + /** @defgroup scm-schematikaparser-member-variables member variables **/ + ///@{ + /** state machine **/ ParserStateMachine psm_; /** debug flag (also stored in psm_) **/ bool debug_flag_ = false; - }; /*SchematikaParser*/ + + ///@} + }; /*DSchematikaParser*/ inline std::ostream & operator<< (std::ostream & os, - const SchematikaParser * x) { + const DSchematikaParser * x) { if (x) { x->print(os); } else { @@ -284,8 +330,8 @@ namespace xo { * to handle ParserResult instances **/ template <> - struct ppdetail { - static inline bool print_pretty(const ppindentinfo & ppii, const xo::scm::SchematikaParser* p) { + struct ppdetail { + static inline bool print_pretty(const ppindentinfo & ppii, const xo::scm::DSchematikaParser* p) { if (p) return p->pretty(ppii); else @@ -295,4 +341,4 @@ namespace xo { } } /*namespace xo*/ -/* end SchematikaParser.hpp */ +/* end DSchematikaParser.hpp */ diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index a010421d..ead25e24 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -19,11 +19,12 @@ #include #include #include +#include #include #include #include -// {pretex} here +// {pretext} here namespace xo { namespace scm { @@ -45,6 +46,8 @@ public: using Opaque = void *; /** reflected c++ type **/ using TypeDescr = xo::reflect::TypeDescr; + /** gc interface **/ + using ACollector = xo::mm::ACollector; /** gc-aware object **/ using AGCObject = xo::mm::AGCObject; ///@} @@ -52,6 +55,11 @@ public: /** @defgroup scm-syntaxstatemachine-methods **/ ///@{ // const methods + /** An uninitialized ASyntaxStateMachine instance will have zero vtable pointer (per {linux,osx} abi). + * Use case for this is narrow. We go to some lengths to avoid null vtable pointers. For example + * obj will have non-null vtable (via IFacet_Any) with all methods terminating. + **/ + bool _has_null_vptr() const noexcept { return *reinterpret_cast(this) == nullptr; } /** RTTI: unique id# for actual runtime data representation **/ virtual typeseq _typeseq() const noexcept = 0; /** destroy instance @p d; calls c++ dtor only for actual runtime type; does not recover memory **/ @@ -82,6 +90,8 @@ public: virtual void on_parsed_expression_with_token(Opaque data, obj expr, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for nested quoted literal @p lit **/ virtual void on_quoted_literal(Opaque data, obj lit, ParserStateMachine * p_psm) = 0; + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + virtual void forward_children(Opaque data, obj gc) = 0; ///@} }; /*ASyntaxStateMachine*/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 2f00d0a4..d1077f2a 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -45,6 +45,7 @@ namespace scm { /** integer identifying a type **/ using typeseq = xo::facet::typeseq; using TypeDescr = ASyntaxStateMachine::TypeDescr; + using ACollector = ASyntaxStateMachine::ACollector; using AGCObject = ASyntaxStateMachine::AGCObject; ///@} @@ -74,6 +75,7 @@ namespace scm { [[noreturn]] void on_parsed_expression(Opaque, obj, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression_with_token(Opaque, obj, const Token &, ParserStateMachine *) override; [[noreturn]] void on_quoted_literal(Opaque, obj, ParserStateMachine *) override; + [[noreturn]] void forward_children(Opaque, obj) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp index d8b28de8..3487a328 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-ddefinessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DDefineSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DDefineSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DDefineSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 1cde9c14..79801c00 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectexprssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectExprSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectExprSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DExpectExprSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp index 78e7db56..68151e22 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectformalarglistssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectFormalArglistSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectFormalArglistSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DExpectFormalArglistSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp index c77c635d..cf6ae53d 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectqarrayssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectQArraySsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQArraySsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DExpectQArraySsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp index 14ff3627..38a33d20 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectqlistssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectQListSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQListSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DExpectQListSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp index b19181a8..4cd123f7 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectqliteralssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectQLiteralSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQLiteralSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DExpectQLiteralSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 431cba69..0ed37f25 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectsymbolssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectSymbolSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectSymbolSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DExpectSymbolSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index f43f83c7..ea084f51 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpecttypessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectTypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectTypeSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DExpectTypeSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index c5e91891..24269888 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dprogressssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DProgressSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DProgressSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DProgressSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp index 7f776ca0..811119c5 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dquotessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DQuoteSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DQuoteSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DQuoteSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp index 361922ef..f19601b5 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dsequencessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DSequenceSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DSequenceSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DSequenceSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp index fbb45bef..b36cbfc6 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp @@ -42,6 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dtoplevelseqssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -75,6 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DToplevelSeqSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DToplevelSeqSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DToplevelSeqSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 67b187cf..13b6d1b7 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace xo { namespace scm { @@ -33,6 +34,7 @@ namespace scm { /** integer identifying a type **/ using typeseq = ASyntaxStateMachine::typeseq; using TypeDescr = ASyntaxStateMachine::TypeDescr; + using ACollector = ASyntaxStateMachine::ACollector; using AGCObject = ASyntaxStateMachine::AGCObject; ///@} @@ -87,6 +89,9 @@ namespace scm { void on_quoted_literal(Opaque data, obj lit, ParserStateMachine * p_psm) override { return I::on_quoted_literal(_dcast(data), lit, p_psm); } + void forward_children(Opaque data, obj gc) override { + return I::forward_children(_dcast(data), gc); + } ///@} diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 4ac4c791..57cc885e 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -32,6 +32,7 @@ public: using DataPtr = Object::DataPtr; using typeseq = xo::reflect::typeseq; using TypeDescr = ASyntaxStateMachine::TypeDescr; + using ACollector = ASyntaxStateMachine::ACollector; using AGCObject = ASyntaxStateMachine::AGCObject; ///@} @@ -92,6 +93,9 @@ public: void on_quoted_literal(obj lit, ParserStateMachine * p_psm) { return O::iface()->on_quoted_literal(O::data(), lit, p_psm); } + void forward_children(obj gc) { + return O::iface()->forward_children(O::data(), gc); + } ///@} /** @defgroup scm-syntaxstatemachine-member-vars **/ diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index bcbd5c60..c465ce1a 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -5,8 +5,10 @@ #include "ApplySsm.hpp" #include "ExpectExprSsm.hpp" -#include +#include +#include #include +#include #include //#include "parserstatemachine.hpp" @@ -394,6 +396,13 @@ namespace xo { refrtag("fn_expr", fn_expr, fn_expr_present)); } + void + DApplySsm::forward_children(obj gc) noexcept + { + gc.forward_pivot_inplace(&fn_expr_); + gc.forward_inplace(&args_expr_v_); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 4634e0a2..5e6b57ea 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -9,7 +9,7 @@ #include "DExpectExprSsm.hpp" #include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" #include "ssm/IPrintable_DDefineSsm.hpp" -#include +#include #include #include @@ -689,6 +689,14 @@ namespace xo { refrtag("expect", this->get_expect_str()), refrtag("def_expr", expr)); } + + // ----- gc support ----- + + void + DDefineSsm::forward_children(obj gc) + { + gc.forward_inplace(&def_expr_.data_); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DDeftypeSsm.cpp b/src/reader2/DDeftypeSsm.cpp index 865ed436..3f377113 100644 --- a/src/reader2/DDeftypeSsm.cpp +++ b/src/reader2/DDeftypeSsm.cpp @@ -270,6 +270,12 @@ namespace xo { refrtag("deftypestate", deftype_xst_), refrtag("expect", this->get_expect_str())); } + void + DDeftypeSsm::forward_children(obj /*gc*/) noexcept + { + static_assert(!DUniqueString::is_gc_eligible()); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 7dcc1d06..6a9d08e7 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -624,6 +624,12 @@ namespace xo { } #endif + void + DExpectExprSsm::forward_children(obj /*gc*/) noexcept + { + // all members POD, skip + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index eeecdc54..d7e903d8 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -264,6 +264,12 @@ namespace xo { } } + void + DExpectFormalArgSsm::forward_children(obj /*gc*/) noexcept + { + static_assert(!DUniqueString::is_gc_eligible()); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 0c367547..ab7d19ee 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -4,25 +4,15 @@ */ #include "ExpectFormalArglistSsm.hpp" -//#include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" #include "ExpectFormalArgSsm.hpp" -//#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" -#include -#include +#include +#include #include +#include #include #include #include -#ifdef NOT_YET -#include "parserstatemachine.hpp" -#include "exprstatestack.hpp" -#include "expect_formal_xs.hpp" -#include "expect_symbol_xs.hpp" -#include "xo/expression/Variable.hpp" -#include "xo/indentlog/print/vector.hpp" -#endif - namespace xo { using xo::print::APrintable; using xo::print::ppstate; @@ -367,6 +357,12 @@ namespace xo { } } + void + DExpectFormalArglistSsm::forward_children(obj gc) noexcept + { + gc.forward_inplace(&argl_); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectListTypeSsm.cpp b/src/reader2/DExpectListTypeSsm.cpp index 36723a6a..921c562e 100644 --- a/src/reader2/DExpectListTypeSsm.cpp +++ b/src/reader2/DExpectListTypeSsm.cpp @@ -7,6 +7,7 @@ #include "ExpectTypeSsm.hpp" #include "syntaxstatetype.hpp" #include +#include #include namespace xo { @@ -202,6 +203,12 @@ namespace xo { "DExpectListTypeSsm"); } + void + DExpectListTypeSsm::forward_children(obj gc) noexcept + { + gc.forward_pivot_inplace(&elt_type_); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectQArraySsm.cpp b/src/reader2/DExpectQArraySsm.cpp index a86bcdae..3d373783 100644 --- a/src/reader2/DExpectQArraySsm.cpp +++ b/src/reader2/DExpectQArraySsm.cpp @@ -6,6 +6,7 @@ #include "ExpectQArraySsm.hpp" #include "ExpectQLiteralSsm.hpp" #include +#include #include #include @@ -218,6 +219,12 @@ namespace xo { refrtag("expect", this->get_expect_str()), refrtag("array", array_pr)); } + void + DExpectQArraySsm::forward_children(obj gc) noexcept + { + gc.forward_inplace(&array_); + } + } } diff --git a/src/reader2/DExpectQDictSsm.cpp b/src/reader2/DExpectQDictSsm.cpp index 7566c130..b57887cb 100644 --- a/src/reader2/DExpectQDictSsm.cpp +++ b/src/reader2/DExpectQDictSsm.cpp @@ -5,6 +5,8 @@ #include "ExpectQDictSsm.hpp" #include "ExpectQLiteralSsm.hpp" +#include +#include namespace xo { using xo::print::APrintable; @@ -264,6 +266,13 @@ namespace xo { } + void + DExpectQDictSsm::forward_children(obj gc) noexcept + { + gc.forward_inplace(const_cast(&key_)); + gc.forward_inplace(&dict_); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp index b767f939..59df8c2c 100644 --- a/src/reader2/DExpectQListSsm.cpp +++ b/src/reader2/DExpectQListSsm.cpp @@ -6,6 +6,7 @@ #include "ExpectQListSsm.hpp" #include "ExpectQLiteralSsm.hpp" #include +#include #include #include @@ -213,6 +214,13 @@ namespace xo { refrtag("expect", this->get_expect_str()), refrtag("list", list_pr)); } + void + DExpectQListSsm::forward_children(obj gc) noexcept + { + gc.forward_inplace(&start_); + gc.forward_inplace(&end_); + } + } } diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index a1b7b2ce..b87eff24 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -255,6 +255,12 @@ namespace xo { "DExpectQLiteralSsm", refrtag("expect", this->get_expect_str())); } + void + DExpectQLiteralSsm::forward_children(obj /*gc*/) noexcept + { + // cxl_on_rightparen_, cxl_on_rightbracket_: POD, skip + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index b1754e33..0875a044 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -145,6 +145,12 @@ namespace xo { //refrtag("member", member_) ); } + void + DExpectSymbolSsm::forward_children(obj /*gc*/) noexcept + { + // no gc-aware members + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 4af50bea..b25c9380 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -197,6 +197,12 @@ namespace xo { "DExpectTypeSsm"); } + void + DExpectTypeSsm::forward_children(obj /*gc*/) noexcept + { + // corrected_: POD, skip + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index e599f6ad..2be7f71c 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -9,6 +9,7 @@ #include "DExpectExprSsm.hpp" #include #include +#include #include namespace xo { @@ -507,5 +508,10 @@ namespace xo { refrtag("if_expr", expr)); } + void + DIfElseSsm::forward_children(obj gc) noexcept + { + gc.forward_pivot_inplace(&if_expr_); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index f8d0fa13..8f5a0bc3 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -16,6 +16,7 @@ //#include //#include #include +#include #include #include @@ -472,6 +473,14 @@ namespace xo { } } + void + DLambdaSsm::forward_children(obj gc) noexcept + { + gc.forward_inplace(&local_symtab_); + gc.forward_pivot_inplace(&body_); + gc.forward_pivot_inplace(&parent_symtab_); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index 5fc33059..13fb728a 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -6,6 +6,7 @@ #include "ParenSsm.hpp" #include "ExpectExprSsm.hpp" #include "syntaxstatetype.hpp" +#include #include namespace xo { @@ -457,6 +458,11 @@ namespace xo { refrtag("expect", this->get_expect_str())); } + void + DParenSsm::forward_children(obj gc) noexcept + { + gc.forward_pivot_inplace(&expr_); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 90fb5d16..345ba5fd 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -22,6 +22,7 @@ #include // for xo::scm::Primitives #include +#include #include #include #include @@ -1242,6 +1243,13 @@ case optype::op_assign: return obj(); } + void + DProgressSsm::forward_children(obj gc) noexcept + { + gc.forward_pivot_inplace(&lhs_); + gc.forward_pivot_inplace(&rhs_); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DQuoteSsm.cpp b/src/reader2/DQuoteSsm.cpp index 6d885e0b..3a665eb5 100644 --- a/src/reader2/DQuoteSsm.cpp +++ b/src/reader2/DQuoteSsm.cpp @@ -211,6 +211,12 @@ namespace xo { refrtag("expect", this->get_expect_str())); } + void + DQuoteSsm::forward_children(obj gc) noexcept + { + gc.forward_pivot_inplace(&expr_); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index c2a07966..f6caeb06 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -3,12 +3,13 @@ #include "DSequenceSsm.hpp" #include "ssm/ISyntaxStateMachine_DSequenceSsm.hpp" #include "DExpectExprSsm.hpp" +#include +#include #ifdef NOT_YET #include "expect_expr_xs.hpp" #include "let1_xs.hpp" #include "xo/expression/DefineExpr.hpp" -#include "xo/expression/Sequence.hpp" #include "xo/expression/pretty_expression.hpp" #endif @@ -256,6 +257,12 @@ namespace xo { refrtag("expect", this->get_expect_str())); } + void + DSequenceSsm::forward_children(obj gc) noexcept + { + gc.forward_inplace(&seq_expr_); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index 113ec235..9252c700 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -517,6 +517,12 @@ namespace xo { "DToplevelSeqSsm", refrtag("seqtype", seqtype_)); } + void + DToplevelSeqSsm::forward_children(obj /*gc*/) noexcept + { + // seqtype_: POD, skip + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 7d401163..7d174c5b 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -95,6 +95,12 @@ ISyntaxStateMachine_Any::on_quoted_literal(Opaque, obj, ParserStateMa _fatal(); } +auto +ISyntaxStateMachine_Any::forward_children(Opaque, obj) -> void +{ + _fatal(); +} + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp index e038fac3..139a3314 100644 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DDefineSsm::forward_children(DDefineSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index 911ec4d5..75464bcc 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DExpectExprSsm::forward_children(DExpectExprSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp index b92e9655..61b219f0 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DExpectFormalArglistSsm::forward_children(DExpectFormalArglistSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp index e205409f..b938f1e7 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DExpectQArraySsm::forward_children(DExpectQArraySsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp index 0f64936e..19df0dff 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DExpectQListSsm::forward_children(DExpectQListSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp index bde94b6b..e6f338fc 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DExpectQLiteralSsm::forward_children(DExpectQLiteralSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index ebeaafe7..b8e8fed0 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DExpectSymbolSsm::forward_children(DExpectSymbolSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 267810e2..011edc4f 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DExpectTypeSsm::forward_children(DExpectTypeSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp index 555ae683..6ee6902b 100644 --- a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DParenSsm::forward_children(DParenSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index f1c0e2cf..01e1e754 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DProgressSsm::forward_children(DProgressSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp b/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp index 233819be..c219db80 100644 --- a/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DQuoteSsm::forward_children(DQuoteSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp index 714a04f8..30e164d8 100644 --- a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DSequenceSsm::forward_children(DSequenceSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp index e78c78c7..73f23da0 100644 --- a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DToplevelSeqSsm::forward_children(DToplevelSeqSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp index abe625c8..daff54de 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DApplySsm::forward_children(DApplySsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp index 2491eee2..e6e54b1c 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DDeftypeSsm::forward_children(DDeftypeSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp index 96a7fb29..059fd4b2 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DExpectFormalArgSsm::forward_children(DExpectFormalArgSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp index bd8ac996..b760ac9a 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DExpectListTypeSsm::forward_children(DExpectListTypeSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp index 60ec4af4..7ee82e82 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DExpectQDictSsm::forward_children(DExpectQDictSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp index 7ebfbeca..c78464c7 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DIfElseSsm::forward_children(DIfElseSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp index 098e49c3..b54d54fc 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp @@ -77,6 +77,11 @@ namespace xo { { self.on_quoted_literal(lit, p_psm); } + auto + ISyntaxStateMachine_DLambdaSsm::forward_children(DLambdaSsm & self, obj gc) -> void + { + self.forward_children(gc); + } } /*namespace scm*/ } /*namespace xo*/ From 48d5c323b48a941b9e8a6b71cbf7f09731de741e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 24 Mar 2026 21:59:59 -0400 Subject: [PATCH 308/342] xo-reader2 stack: + ARuntimeContext.collector() access Collector API (if present) from runtime context --- CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c009aab..4675de3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,17 @@ add_definitions(${PROJECT_CXX_FLAGS}) add_subdirectory(utest) +# ---------------------------------------------------------------- + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-gcobject-schematikaparser + FACET_PKG xo_alloc2 + INPUT idl/IGCObject_DSchematikaParser.json5 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacet( TARGET xo-reader2-facet-syntaxstatemachine From 4304892a7c5d3354f8725c51a8d2c8bcfda0625a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 24 Mar 2026 22:15:08 -0400 Subject: [PATCH 309/342] xo-reader2: adopt DSchematikaParser as gc-aware object Use as virtual GC root. --- include/xo/reader2/SchematikaReader.hpp | 2 +- src/reader2/CMakeLists.txt | 4 +- src/reader2/DSchematikaParser.cpp | 86 ++- src/reader2/ParserResult.cpp | 11 + src/reader2/ParserStack.cpp | 12 + src/reader2/ParserStateMachine.cpp | 56 +- src/reader2/SchematikaReader.cpp | 2 +- src/reader2/SetupReader2.cpp | 8 +- utest/SchematikaParser.test.cpp | 673 +++++++++++++++--------- 9 files changed, 578 insertions(+), 276 deletions(-) diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index 8b24f775..58c77ec8 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -110,7 +110,7 @@ namespace xo { /** parser converts a stream of tokens * to a stream of expressions **/ - SchematikaParser parser_; + DSchematikaParser parser_; /** current output from reader **/ ReaderResult result_; diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 73e9ea37..30f11169 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -8,7 +8,9 @@ set(SELF_SRCS SchematikaReader.cpp ReaderConfig.cpp - SchematikaParser.cpp + DSchematikaParser.cpp + facet/IGCObject_DSchematikaParser.cpp + ParserStateMachine.cpp ParserStack.cpp ParserResult.cpp diff --git a/src/reader2/DSchematikaParser.cpp b/src/reader2/DSchematikaParser.cpp index 7d27e41c..a18d9735 100644 --- a/src/reader2/DSchematikaParser.cpp +++ b/src/reader2/DSchematikaParser.cpp @@ -1,4 +1,4 @@ -/** @file SchematikaParser.cpp +/** @file DSchematikaParser.cpp * * @author Roland Conybeare, Jan 2026 **/ @@ -12,7 +12,9 @@ #include namespace xo { + using xo::mm::ACollector; using xo::mm::AAllocator; + using xo::mm::AGCObject; using xo::mm::MemorySizeInfo; using xo::tostr; using xo::xtag; @@ -20,9 +22,9 @@ namespace xo { namespace scm { // ----- SchematikaParser ----- - SchematikaParser::SchematikaParser(const ParserConfig & cfg, - obj expr_alloc, - obj aux_alloc) + DSchematikaParser::DSchematikaParser(const ParserConfig & cfg, + obj expr_alloc, + obj aux_alloc) : psm_{ cfg.parser_arena_config_, cfg.symtab_var_config_, @@ -36,74 +38,94 @@ namespace xo { { } + DSchematikaParser * + DSchematikaParser::_make(obj mm, + const ParserConfig & cfg, + obj expr_alloc, + obj aux_alloc) + { + void * mem = mm.alloc_for(); + + return new (mem) DSchematikaParser(cfg, expr_alloc, aux_alloc); + } + + obj + DSchematikaParser::make(obj mm, + const ParserConfig & cfg, + obj expr_alloc, + obj aux_alloc) + { + return obj(_make(mm, cfg, expr_alloc, aux_alloc)); + } + DGlobalSymtab * - SchematikaParser::global_symtab() const noexcept + DSchematikaParser::global_symtab() const noexcept { return psm_.global_symtab(); } DGlobalEnv * - SchematikaParser::global_env() const noexcept + DSchematikaParser::global_env() const noexcept { return psm_.global_env(); } bool - SchematikaParser::is_at_toplevel() const + DSchematikaParser::is_at_toplevel() const { return psm_.is_at_toplevel(); } bool - SchematikaParser::has_incomplete_expr() const + DSchematikaParser::has_incomplete_expr() const { return psm_.has_incomplete_expr(); } obj - SchematikaParser::top_ssm() const + DSchematikaParser::top_ssm() const { return psm_.top_ssm(); } const ParserResult & - SchematikaParser::result() const + DSchematikaParser::result() const { return psm_.result(); } void - SchematikaParser::visit_pools(const MemorySizeVisitor & visitor) const + DSchematikaParser::visit_pools(const MemorySizeVisitor & visitor) const { return psm_.visit_pools(visitor); } void - SchematikaParser::begin_interactive_session() + DSchematikaParser::begin_interactive_session() { DToplevelSeqSsm::establish_interactive(psm_.parser_alloc(), &psm_); } void - SchematikaParser::begin_batch_session() + DSchematikaParser::begin_batch_session() { DToplevelSeqSsm::establish_batch(psm_.parser_alloc(), &psm_); } const DUniqueString * - SchematikaParser::intern_string(std::string_view str) + DSchematikaParser::intern_string(std::string_view str) { return psm_.intern_string(str); } const ParserResult & - SchematikaParser::on_token(const token_type & tk) + DSchematikaParser::on_token(const token_type & tk) { scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); if (psm_.stack() == nullptr) { - throw std::runtime_error(tostr("SchematikaParser::include_token", + throw std::runtime_error(tostr("DSchematikaParser::include_token", ": parser not expecting input" "(call parser.begin_translation_unit()..?)", xtag("token", tk))); @@ -120,19 +142,19 @@ namespace xo { } /*include_token*/ void - SchematikaParser::reset_result() + DSchematikaParser::reset_result() { psm_.reset_result(); } void - SchematikaParser::reset_to_idle_toplevel() + DSchematikaParser::reset_to_idle_toplevel() { psm_.clear_error_reset(); } /*reset_to_idle_toplevel*/ void - SchematikaParser::print(std::ostream & os) const { + DSchematikaParser::print(std::ostream & os) const { os << " mm) const noexcept + { + (void)mm; + + assert(false); + return nullptr; + } + + std::size_t + DSchematikaParser::forward_children(obj gc) noexcept + { + psm_.forward_children(gc); + + return this->shallow_size(); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ParserResult.cpp b/src/reader2/ParserResult.cpp index 974724d9..fa9c9591 100644 --- a/src/reader2/ParserResult.cpp +++ b/src/reader2/ParserResult.cpp @@ -4,7 +4,9 @@ **/ #include "ParserResult.hpp" +#include #include +#include #include namespace xo { @@ -102,6 +104,15 @@ namespace xo { return false; } + + void + ParserResult::forward_children(obj gc) noexcept + { + // {result_type_, error_src_fn_}: pod, ignore + + gc.forward_pivot_inplace(&result_expr_); + gc.forward_inplace(const_cast(&error_description_)); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ParserStack.cpp b/src/reader2/ParserStack.cpp index 9ab919b2..f40696b2 100644 --- a/src/reader2/ParserStack.cpp +++ b/src/reader2/ParserStack.cpp @@ -89,6 +89,18 @@ namespace xo { return false; } + void + ParserStack::forward_children(obj gc) noexcept + { + + for (ParserStack * target = this; target; target = target->parent_) { + // ParserStack::ckp: skip, POD + + if (target->ssm_) + target->ssm_.forward_children(gc); + } + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 16871d22..63c333e1 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -43,7 +43,7 @@ namespace xo { DGlobalSymtab * global_symtab, InstallFlags pm_install_flags) { - scope log(XO_DEBUG(true)); + scope log(XO_DEBUG(false)); DGlobalEnv * env = DGlobalEnv::_make(mm, global_symtab); @@ -102,10 +102,9 @@ namespace xo { pm_install_flags)}, debug_flag_{config.debug_flag_} { - obj gc = expr_alloc_.try_to_facet(); - if (gc) { - gc.add_gc_root(&global_env_); - } + // see xo-numeric/ {SetupNumeric.cpp, NumericPrimitives.cpp} + // for setup of {_mul, _div, _sub, ...} + // { const DUniqueString * name = stringtable_.lookup("_mul"); @@ -175,6 +174,8 @@ namespace xo { if (gc) { scope log(XO_DEBUG(true), "remove_gc_root not implemented"); + gc.remove_gc_root(&global_symtab_); + gc.remove_gc_root(&local_symtab_); gc.remove_gc_root(&global_env_); } } @@ -404,7 +405,7 @@ namespace xo { // if (local_symtab_) { - DLocalSymtab * symtab = local_symtab_; + DLocalSymtab * symtab = local_symtab_.data(); // count #of nested scopes to cross, to reach symbol // @@ -450,7 +451,7 @@ namespace xo { void ParserStateMachine::push_local_symtab(DLocalSymtab * symtab) { - this->local_symtab_ = symtab; + this->local_symtab_ = obj(symtab); } void @@ -458,7 +459,7 @@ namespace xo { { assert(local_symtab_); - this->local_symtab_ = local_symtab_->parent(); + this->local_symtab_ = obj(local_symtab_->parent()); } void @@ -879,6 +880,45 @@ namespace xo { this->capture_error(ssm_name, errmsg); } + // ----- gc support ----- + +#ifdef OBSOLETE + std::size_t + ParserStateMachine::shallow_size() const noexcept + { + return sizeof(ParserStateMachine); + } + + ParserStateMachine * + ParserStateMachine::shallow_copy(obj mm) const noexcept + { + (void)mm; + + assert(false); + return nullptr; + } +#endif + + void + ParserStateMachine::forward_children(obj gc) noexcept + { + static_assert(!stringtable_.is_gc_eligible()); + static_assert(!parser_alloc_.is_gc_eligible()); + + if (stack_) { + stack_->forward_children(gc); + } + + // static_assert(!expr_alloc_.is_gc_eligible()); + // static_assert(!aux_alloc_.is_gc_eligible()); + + gc.forward_inplace(&global_symtab_); + gc.forward_inplace(&local_symtab_); + gc.forward_inplace(&global_env_); + + result_.forward_children(gc); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index 388c5266..0db3f337 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -1,5 +1,5 @@ /** @file SchematikaReader.cpp -* + * * @author Roland Conybeare, Jan 2026 **/ diff --git a/src/reader2/SetupReader2.cpp b/src/reader2/SetupReader2.cpp index 62536329..3dca4ac8 100644 --- a/src/reader2/SetupReader2.cpp +++ b/src/reader2/SetupReader2.cpp @@ -47,6 +47,10 @@ namespace xo { { scope log(XO_DEBUG(true)); + // SchematikParser + + FacetRegistry::register_impl(); + // GlobalEnv FacetRegistry::register_impl(); @@ -114,11 +118,11 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); - // misc types showing up in aux arena - TypeRegistry::register_type(); // misc types showing up in parser stack arena TypeRegistry::register_type(); + log && log(xtag("DSchematikaParser.tseq", typeseq::id())); + log && log(xtag("DGlobalEnv.tseq", typeseq::id())); log && log(xtag("DToplevelSeqSsm.tseq", typeseq::id())); log && log(xtag("DDefineSsm.tseq", typeseq::id())); diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 23821872..7b9a2a26 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -19,17 +19,16 @@ #include #include #include -#include +#include +#include +#include +#include #include #include namespace xo { using xo::scm::ParserConfig; - using xo::scm::SchematikaParser; -// using xo::scm::ASyntaxStateMachine; -// using xo::scm::syntaxstatetype; -// using xo::scm::DDefineSsm; -// using xo::scm::DExpectExprSsm; + using xo::scm::DSchematikaParser; using xo::scm::AExpression; using xo::scm::DDefineExpr; @@ -38,9 +37,7 @@ namespace xo { using xo::scm::DVarRef; using xo::scm::DConstant; - //using xo::scm::ParserResult; using xo::scm::Token; - using xo::mm::AGCObject; using xo::scm::DPrimitive_gco_2_gco_gco; using xo::scm::DList; using xo::scm::DString; @@ -51,67 +48,129 @@ namespace xo { using xo::mm::ArenaConfig; using xo::mm::AAllocator; + using xo::mm::ACollector; + using xo::mm::AGCObject; using xo::mm::DArena; + using xo::mm::DX1Collector; + using xo::mm::generation; + using xo::mm::X1CollectorConfig; + using xo::mm::CollectorTypeRegistry; using xo::mm::MemorySizeInfo; -// using xo::facet::with_facet; - static InitEvidence s_init = (InitSubsys::require()); + static InitEvidence s_init = (InitSubsys::require() + ^ InitSubsys::require()); namespace ut { struct ParserFixture { - ParserFixture(const std::string & testname, bool debug_flag) + ParserFixture(const std::string & testname, + bool gc_flag, + bool debug_flag) { this->aux_arena_ = std::move(DArena(ArenaConfig() .with_name(testname) - .with_size(4 * 1024) + .with_size(64 * 1024) .with_store_header_flag(true))); obj aux_mm(&aux_arena_); - this->expr_arena_ - = dp::make(aux_mm, - (ArenaConfig() - .with_name("expr") - .with_size(16 * 1024) - .with_store_header_flag(true))); - obj expr_mm(expr_arena_.data()); + if (gc_flag) { + X1CollectorConfig x1_config + = (X1CollectorConfig() + .with_name("gc") + .with_size(32 * 1024) + .with_debug_flag(true) + .with_sanitize_flag(true)); + + dp expr_x1_dp + = dp::make(aux_mm, x1_config); + + this->expr_mm_ + = obj(expr_x1_dp.release()); + + obj gc = expr_mm_.to_facet(); + + CollectorTypeRegistry::instance().install_types(gc); + } else { + ArenaConfig arena_config + = (ArenaConfig().with_name("expr") + .with_size(16 * 1024) + .with_store_header_flag(true)); + + dp expr_arena_dp + = dp::make(aux_mm, arena_config); + + this->expr_mm_ + = obj(expr_arena_dp.release()); + + } ParserConfig cfg; - cfg.parser_arena_config_.size_ = 16 * 1024; - /* editor bait: symbol table */ - cfg.symtab_var_config_.hint_max_capacity_ = 128; - cfg.symtab_types_config_.hint_max_capacity_ = 64; - cfg.max_stringtable_capacity_ = 512; - cfg.debug_flag_ = false; + { + cfg.parser_arena_config_.size_ = 16 * 1024; + /* editor bait: symbol table */ + cfg.symtab_var_config_.hint_max_capacity_ = 128; + cfg.symtab_types_config_.hint_max_capacity_ = 64; + cfg.max_stringtable_capacity_ = 512; + cfg.debug_flag_ = false; + } this->parser_ - = dp::make(aux_mm, cfg, expr_mm, aux_mm); + = DSchematikaParser::make(aux_mm, cfg, expr_mm_, aux_mm); + this->parser_gco_ = parser_; + + if (gc_flag) { + obj gc = expr_mm_.to_facet(); + + if (gc) { + gc.add_gc_root_poly(&parser_gco_); + } + + // Also add parser itself as a global. + // SchematikaParser is a snowflake GCObject: + // it only supports the AGCObject forward_children() method + // + } + + this->gc_flag_ = gc_flag; + this->debug_flag_ = debug_flag; } ParserFixture(const ParserFixture & other) = delete; ParserFixture(const ParserFixture && other) = delete; + ~ParserFixture() { + // destroy allocator + expr_mm_._drop(); + // destroy parser (reminder: was allocated from aux_arena_) + parser_._drop(); + } + bool log_memory_layout(scope * p_log) { using xo::facet::TypeRegistry; using xo::mm::MemorySizeDetail; - auto visitor = [p_log](const MemorySizeInfo & info) { + auto visitor = [this, p_log](const MemorySizeInfo & info) { *p_log && (*p_log)(xtag("name", info.resource_name_), xtag("used", info.used_), xtag("alloc", info.allocated_), xtag("commit", info.committed_), xtag("resv", info.reserved_)); - if (*p_log && info.detail_) { + + if (*p_log && debug_mm_detail_ && info.detail_) { (*p_log)("detail", xtag("n", (*info.detail_)[0].n_alloc_), xtag("z", (*info.detail_)[0].z_alloc_)); + for (size_t i = 1; i < info.detail_->size(); ++i) { const MemorySizeDetail & d = (*info.detail_)[i]; if (d.tseq_.is_sentinel()) break; - (*p_log)("[",i,"]", + char buf[40]; + snprintf(buf, sizeof(buf), "[%lu]", i); + + (*p_log)(buf, xtag("tseq",d.tseq_), xtag("type", TypeRegistry::id2name(d.tseq_)), xtag("n", d.n_alloc_), @@ -123,47 +182,68 @@ namespace xo { aux_arena_.visit_pools(visitor); FacetRegistry::instance().visit_pools(visitor); TypeRegistry::instance().visit_pools(visitor); - expr_arena_->visit_pools(visitor); + expr_mm_.visit_pools(visitor); parser_->visit_pools(visitor); return true; } DArena aux_arena_; - dp expr_arena_; - dp parser_; + /** allocator for parsed schematika expressions **/ + obj expr_mm_; + obj parser_; + /** parser_ as variant gco, to sastify Collector.add_gc_root_poly() **/ + obj parser_gco_; + bool gc_flag_ = false; + bool debug_flag_ = false; + bool debug_mm_detail_ = false; }; void - utest_tokenizer_loop(SchematikaParser * parser, std::vector & tk_v, bool debug_flag) + utest_tokenizer_loop(ParserFixture * fixture, + std::vector & tk_v, + bool debug_flag) { scope log(XO_DEBUG(debug_flag)); + obj expr_gc + = fixture->expr_mm_.try_to_facet(); + size_t i_tk = 0; size_t n_tk = tk_v.size(); + for (const auto & tk : tk_v) { - INFO(tostr(xtag("i_tk", i_tk), xtag("tk", tk))); + INFO(tostr(xtag("i_tk", i_tk), + xtag("tk", tk))); - auto & result = parser->on_token(tk); + auto & result = fixture->parser_->on_token(tk); - log && log("after token", xtag("i_tk", i_tk), xtag("tk", tk)); - log && log(xtag("parser", parser)); + log && log("after token", + xtag("i_tk", i_tk), xtag("tk", tk)); + log && log(xtag("parser", fixture->parser_.data())); log && log(xtag("result", result)); if (i_tk + 1 < n_tk) { - REQUIRE(parser->has_incomplete_expr() == true); + REQUIRE(fixture->parser_->has_incomplete_expr() == true); REQUIRE(!result.is_error()); REQUIRE(result.is_incomplete()); } else { /* last token in tk_v[] */ - REQUIRE(parser->has_incomplete_expr() == false); + REQUIRE(fixture->parser_->has_incomplete_expr() == false); REQUIRE(!result.is_error()); REQUIRE(result.is_expression()); REQUIRE(result.result_expr()); } ++i_tk; + + // for this test: invoke full collection after each token + if (fixture->gc_flag_) { + REQUIRE(expr_gc); + + expr_gc.request_gc(generation(2)); + } } } @@ -174,11 +254,11 @@ namespace xo { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - REQUIRE(parser.debug_flag() == false); - REQUIRE(parser.is_at_toplevel() == true); + REQUIRE(parser->debug_flag() == false); + REQUIRE(parser->is_at_toplevel() == true); // baseline: // SchematikaParser-ctor :used 1408 @@ -205,14 +285,14 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); // after begin_interactive_session, parser has toplevel exprseq // but is still "at toplevel" in the sense of ready for input - REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(parser->has_incomplete_expr() == false); log && fixture.log_memory_layout(&log); } @@ -224,94 +304,138 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_batch_session(); + parser->begin_batch_session(); // after begin_translation_unit, parser has toplevel exprseq // but is still "at toplevel" in the sense of ready for input - REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(parser->has_incomplete_expr() == false); log && fixture.log_memory_layout(&log); } + namespace { + void + test_batch_def(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; + + parser->begin_batch_session(); + + /** Walkthrough parsing input equivalent to: + * + * def foo : f64 = 3.141593 ; + * + **/ + + std::vector tk_v{ + Token::def_token(), + Token::symbol_token("foo"), + Token::colon_token(), + Token::symbol_token("f64"), + Token::singleassign_token(), + Token::f64_token("3.141593"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); + + const auto & result = parser->result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + + log && fixture->log_memory_layout(&log); + } + + void + test_driver(const std::string & testname, + std::function test_subject, + std::array debug_flag_v) + { + scope log(XO_DEBUG(debug_flag_v[0] || debug_flag_v[1]), + xtag("test", testname)); + + /* phase=0 arena, no gc + * phase=1 x1 collector + */ + for (int phase = 0; phase < 2; ++phase) + { + log && log(xtag("phase", phase)); + + ParserFixture fixture(testname, phase == 1 /*gc*/, debug_flag_v[phase]); + + test_subject(&fixture); + } + + } + } + TEST_CASE("SchematikaParser-batch-def", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, true}}; - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + test_driver(testname, + &test_batch_def, + c_debug_flag_v); + } - parser.begin_batch_session(); - - /** Walkthrough parsing input equivalent to: - * - * def foo : f64 = 3.141593 ; - * - **/ - - std::vector tk_v{ - Token::def_token(), - Token::symbol_token("foo"), - Token::colon_token(), - Token::symbol_token("f64"), - Token::singleassign_token(), - Token::f64_token("3.141593"), - Token::semicolon_token(), - }; - - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); - - const auto & result = parser.result(); + namespace { + void + test_batch_deftype(ParserFixture * fixture) { - auto expr = obj::from(result.result_expr()); - REQUIRE(expr); - } + scope log(XO_DEBUG(fixture->debug_flag_)); - log && fixture.log_memory_layout(&log); + auto parser = fixture->parser_; + + parser->begin_batch_session(); + + /** Walkthrough parsing input equivalent to: + * + * deftype foo :: f64; + **/ + + std::vector tk_v{ + Token::deftype_token(), + Token::symbol_token("foo"), + Token::doublecolon_token(), + Token::symbol_token("f64"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); + + const auto & result = parser->result(); + { + // placeholder for form's sake. + // deftype doesn't actuallly produce any executable content + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + + log && fixture->log_memory_layout(&log); + } } TEST_CASE("SchematikaParser-batch-deftype", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, true}}; - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); - - parser.begin_batch_session(); - - /** Walkthrough parsing input equivalent to: - * - * deftype foo :: f64; - **/ - - std::vector tk_v{ - Token::deftype_token(), - Token::symbol_token("foo"), - Token::doublecolon_token(), - Token::symbol_token("f64"), - Token::semicolon_token(), - }; - - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); - - const auto & result = parser.result(); - { - // placeholder for form's sake. - // deftype doesn't actuallly produce any executable content - - auto expr = obj::from(result.result_expr()); - REQUIRE(expr); - } - - log && fixture.log_memory_layout(&log); + test_driver(testname, + &test_batch_deftype, + c_debug_flag_v); } TEST_CASE("SchematikaParser-batch-deftype-2", "[reader2][SchematikaParser]") @@ -321,10 +445,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_batch_session(); + parser->begin_batch_session(); /** Walkthrough parsing input equivalent to: * @@ -342,9 +466,9 @@ namespace xo { Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); - const auto & result = parser.result(); + const auto & result = parser->result(); { // placeholder for form's sake. // deftype doesn't actuallly produce any executable content @@ -363,10 +487,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); { /** Walkthrough parsing input equivalent to: @@ -385,15 +509,15 @@ namespace xo { Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); - const auto & result = parser.result(); + const auto & result = parser->result(); { auto expr = obj::from(result.result_expr()); REQUIRE(expr); } - parser.reset_result(); + parser->reset_result(); } { @@ -410,9 +534,9 @@ namespace xo { Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); - const auto & result = parser.result(); + const auto & result = parser->result(); { auto expr = obj::from(result.result_expr()); REQUIRE(expr); @@ -429,10 +553,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -441,25 +565,25 @@ namespace xo { **/ { - auto & result = parser.on_token(Token::i64_token("1011")); + auto & result = parser->on_token(Token::i64_token("1011")); log && log("after integer token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(parser->has_incomplete_expr() == true); REQUIRE(!result.is_error()); REQUIRE(result.is_incomplete()); } { - auto & result = parser.on_token(Token::semicolon_token()); + auto & result = parser->on_token(Token::semicolon_token()); log && log("after semicolon token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(parser->has_incomplete_expr() == false); REQUIRE(!result.is_error()); REQUIRE(result.is_expression()); REQUIRE(result.result_expr()); @@ -490,10 +614,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -502,25 +626,25 @@ namespace xo { **/ { - auto & result = parser.on_token(Token::f64_token("3.14159265")); + auto & result = parser->on_token(Token::f64_token("3.14159265")); log && log("after float token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(parser->has_incomplete_expr() == true); REQUIRE(!result.is_error()); REQUIRE(result.is_incomplete()); } { - auto & result = parser.on_token(Token::semicolon_token()); + auto & result = parser->on_token(Token::semicolon_token()); log && log("after semicolon token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(parser->has_incomplete_expr() == false); REQUIRE(!result.is_error()); REQUIRE(result.is_expression()); REQUIRE(result.result_expr()); @@ -551,10 +675,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -563,25 +687,25 @@ namespace xo { **/ { - auto & result = parser.on_token(Token::string_token("hello world")); + auto & result = parser->on_token(Token::string_token("hello world")); log && log("after string token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(parser->has_incomplete_expr() == true); REQUIRE(!result.is_error()); REQUIRE(result.is_incomplete()); } { - auto & result = parser.on_token(Token::semicolon_token()); + auto & result = parser->on_token(Token::semicolon_token()); log && log("after semicolon token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(parser->has_incomplete_expr() == false); REQUIRE(!result.is_error()); REQUIRE(result.is_expression()); REQUIRE(result.result_expr()); @@ -612,10 +736,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -624,25 +748,25 @@ namespace xo { **/ { - auto & result = parser.on_token(Token::nil_token()); + auto & result = parser->on_token(Token::nil_token()); log && log("after nil token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(parser->has_incomplete_expr() == true); REQUIRE(!result.is_error()); REQUIRE(result.is_incomplete()); } { - auto & result = parser.on_token(Token::semicolon_token()); + auto & result = parser->on_token(Token::semicolon_token()); log && log("after semicolon token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(parser->has_incomplete_expr() == false); REQUIRE(!result.is_error()); REQUIRE(result.is_expression()); REQUIRE(result.result_expr()); @@ -673,10 +797,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -691,9 +815,9 @@ namespace xo { Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); - const auto & result = parser.result(); + const auto & result = parser->result(); { auto expr = obj::from(result.result_expr()); REQUIRE(expr); @@ -732,10 +856,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -752,9 +876,9 @@ namespace xo { INFO(testname); - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); - const auto & result = parser.result(); + const auto & result = parser->result(); { auto expr = obj::from(result.result_expr()); REQUIRE(expr); @@ -793,10 +917,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -815,9 +939,9 @@ namespace xo { INFO(testname); - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); - const auto & result = parser.result(); + const auto & result = parser->result(); { auto expr = obj::from(result.result_expr()); REQUIRE(expr); @@ -863,10 +987,10 @@ namespace xo { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -885,9 +1009,9 @@ namespace xo { INFO(testname); - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); - const auto & result = parser.result(); + const auto & result = parser->result(); { auto expr = obj::from(result.result_expr()); REQUIRE(expr); @@ -933,10 +1057,10 @@ namespace xo { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -958,7 +1082,7 @@ namespace xo { utest_tokenizer_loop(&parser, tk_v, c_debug_flag); - const auto & result = parser.result(); + const auto & result = parser->result(); { auto expr = obj::from(result.result_expr()); REQUIRE(expr); @@ -998,7 +1122,8 @@ namespace xo { } #endif - TEST_CASE("SchematikaParser-interactive-cmp", "[reader2][SchematikaParser]") +#ifdef NOT_YET + TEST_CASE("SchematikaParser-interactive-cmpne", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); @@ -1006,10 +1131,72 @@ namespace xo { scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * 312 != 312 ; + * ^ ^ ^ ^ + * 0 1 2 3 + **/ + + std::vector tk_v{ + /* [0] */ Token::i64_token("312"), + /* [1] */ Token::cmpne_token(), + /* [2] */ Token::i64_token("312"), + /* [3] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + + const auto & result = parser->result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + + REQUIRE(expr->n_args() == 2); + + auto fn = obj::from(expr->fn()); + REQUIRE(fn); + + auto pm = obj::from(fn->value()); + REQUIRE(pm); + REQUIRE(pm->name() == "_cmpne"); + + auto lhs = obj::from(expr->arg(0)); + REQUIRE(lhs); + + auto lhs_i64 = obj::from(lhs->value()); + REQUIRE(lhs_i64); + REQUIRE(lhs_i64->value() == 312); + + auto rhs = obj::from(expr->arg(1)); + REQUIRE(rhs); + + auto rhs_i64 = obj::from(rhs->value()); + REQUIRE(rhs_i64); + REQUIRE(rhs_i64->value() == 312); + } + + log && fixture.log_memory_layout(&log); + } +#endif + + TEST_CASE("SchematikaParser-interactive-cmpeq", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag), + xtag("test", testname)); + + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; + + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1025,9 +1212,9 @@ namespace xo { /* [3] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); - const auto & result = parser.result(); + const auto & result = parser->result(); { auto expr = obj::from(result.result_expr()); REQUIRE(expr); @@ -1067,10 +1254,10 @@ namespace xo { scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); { /** Walkthrough parsing input equivalent to: @@ -1088,18 +1275,18 @@ namespace xo { /* [4] */ Token::semicolon_token() }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); } { - const auto & result = parser.result(); + const auto & result = parser->result(); auto expr = obj::from(result.result_expr()); REQUIRE(expr); } { - parser.reset_result(); + parser->reset_result(); /** Walkthrough parsing input equivalent to: * @@ -1125,10 +1312,10 @@ namespace xo { /* [c] */ Token::semicolon_token() }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); } - const auto & result = parser.result(); + const auto & result = parser->result(); { auto expr = obj::from(result.result_expr()); REQUIRE(expr); @@ -1144,10 +1331,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1175,7 +1362,7 @@ namespace xo { /* [ e] */ Token::rightbrace_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1187,10 +1374,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1209,7 +1396,7 @@ namespace xo { /* [6] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1221,10 +1408,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1250,7 +1437,7 @@ namespace xo { /* [ c] */ Token::rightbrace_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1262,10 +1449,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1296,7 +1483,7 @@ namespace xo { /* [ g] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1310,10 +1497,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1354,7 +1541,7 @@ namespace xo { /* [ m] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1368,10 +1555,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1412,7 +1599,7 @@ namespace xo { /* [ q] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1426,10 +1613,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1447,7 +1634,7 @@ namespace xo { /* [ 4] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1461,10 +1648,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1490,7 +1677,7 @@ namespace xo { /* [ 9] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1504,10 +1691,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1528,7 +1715,7 @@ namespace xo { /* [ 7] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1542,10 +1729,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1566,7 +1753,7 @@ namespace xo { /* [ 7] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1580,10 +1767,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1604,7 +1791,7 @@ namespace xo { /* [ 7] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1618,10 +1805,10 @@ namespace xo { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1642,7 +1829,7 @@ namespace xo { /* [ 5] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } @@ -1656,10 +1843,10 @@ namespace xo { constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - ParserFixture fixture(testname, c_debug_flag); - auto & parser = *(fixture.parser_); + ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); + auto parser = fixture.parser_; - parser.begin_interactive_session(); + parser->begin_interactive_session(); /** Walkthrough parsing input equivalent to: * @@ -1694,7 +1881,7 @@ namespace xo { /* [ g] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); log && fixture.log_memory_layout(&log); } From 0972cdada37126b7e5cedadd6ec32e45a1aa48ad Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 24 Mar 2026 22:18:37 -0400 Subject: [PATCH 310/342] xo-reader2: + gcobject facet includes for DSchematikaParser --- idl/IGCObject_DSchematikaParser.json5 | 18 +++++ include/xo/reader2/SchematikaParser.hpp | 11 +++ .../env/IGCObject_DSchematikaParser.hpp | 67 +++++++++++++++++++ .../parser/IGCObject_DSchematikaParser.hpp | 67 +++++++++++++++++++ .../facet/IGCObject_DSchematikaParser.cpp | 39 +++++++++++ 5 files changed, 202 insertions(+) create mode 100644 idl/IGCObject_DSchematikaParser.json5 create mode 100644 include/xo/reader2/SchematikaParser.hpp create mode 100644 include/xo/reader2/env/IGCObject_DSchematikaParser.hpp create mode 100644 include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp create mode 100644 src/reader2/facet/IGCObject_DSchematikaParser.cpp diff --git a/idl/IGCObject_DSchematikaParser.json5 b/idl/IGCObject_DSchematikaParser.json5 new file mode 100644 index 00000000..cbb2d09a --- /dev/null +++ b/idl/IGCObject_DSchematikaParser.json5 @@ -0,0 +1,18 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2/facet", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "parser", + includes: [ + "", + "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/GCObject.json5", + brief: "provide AGCObject interface for SchematikaParser", + using_doxygen: true, + repr: "DSchematikaParser", + doc: [ "implement AGCObject for DSchematikaParser" ], +} diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp new file mode 100644 index 00000000..c93bfb19 --- /dev/null +++ b/include/xo/reader2/SchematikaParser.hpp @@ -0,0 +1,11 @@ +/** @file SchematikaParser.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "parser/DSchematikaParser.hpp" +#include "parser/IGCObject_DSchematikaParser.hpp" + +/* end SchemtikaParser.hpp */ diff --git a/include/xo/reader2/env/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/env/IGCObject_DSchematikaParser.hpp new file mode 100644 index 00000000..afe0d6b5 --- /dev/null +++ b/include/xo/reader2/env/IGCObject_DSchematikaParser.hpp @@ -0,0 +1,67 @@ +/** @file IGCObject_DSchematikaParser.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DSchematikaParser.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DSchematikaParser.json5] + **/ + +#pragma once + +#include "GCObject.hpp" +#include +#include +#include "DSchematikaParser.hpp" + +namespace xo { namespace scm { class IGCObject_DSchematikaParser; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IGCObject_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IGCObject_DSchematikaParser + **/ + class IGCObject_DSchematikaParser { + public: + /** @defgroup scm-gcobject-dschematikaparser-type-traits **/ + ///@{ + using size_type = xo::mm::AGCObject::size_type; + using AAllocator = xo::mm::AGCObject::AAllocator; + using ACollector = xo::mm::AGCObject::ACollector; + using Copaque = xo::mm::AGCObject::Copaque; + using Opaque = xo::mm::AGCObject::Opaque; + ///@} + /** @defgroup scm-gcobject-dschematikaparser-methods **/ + ///@{ + // const methods + /** memory consumption for this instance **/ + static size_type shallow_size(const DSchematikaParser & self) noexcept; + /** copy instance using allocator **/ + static Opaque shallow_copy(const DSchematikaParser & self, obj mm) noexcept; + + // non-const methods + /** during GC: forward immdiate children **/ + static size_type forward_children(DSchematikaParser & self, obj gc) noexcept; + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp new file mode 100644 index 00000000..afe0d6b5 --- /dev/null +++ b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp @@ -0,0 +1,67 @@ +/** @file IGCObject_DSchematikaParser.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DSchematikaParser.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DSchematikaParser.json5] + **/ + +#pragma once + +#include "GCObject.hpp" +#include +#include +#include "DSchematikaParser.hpp" + +namespace xo { namespace scm { class IGCObject_DSchematikaParser; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IGCObject_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IGCObject_DSchematikaParser + **/ + class IGCObject_DSchematikaParser { + public: + /** @defgroup scm-gcobject-dschematikaparser-type-traits **/ + ///@{ + using size_type = xo::mm::AGCObject::size_type; + using AAllocator = xo::mm::AGCObject::AAllocator; + using ACollector = xo::mm::AGCObject::ACollector; + using Copaque = xo::mm::AGCObject::Copaque; + using Opaque = xo::mm::AGCObject::Opaque; + ///@} + /** @defgroup scm-gcobject-dschematikaparser-methods **/ + ///@{ + // const methods + /** memory consumption for this instance **/ + static size_type shallow_size(const DSchematikaParser & self) noexcept; + /** copy instance using allocator **/ + static Opaque shallow_copy(const DSchematikaParser & self, obj mm) noexcept; + + // non-const methods + /** during GC: forward immdiate children **/ + static size_type forward_children(DSchematikaParser & self, obj gc) noexcept; + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/src/reader2/facet/IGCObject_DSchematikaParser.cpp b/src/reader2/facet/IGCObject_DSchematikaParser.cpp new file mode 100644 index 00000000..0ac80e37 --- /dev/null +++ b/src/reader2/facet/IGCObject_DSchematikaParser.cpp @@ -0,0 +1,39 @@ +/** @file IGCObject_DSchematikaParser.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DSchematikaParser.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DSchematikaParser.json5] +**/ + +#include "parser/IGCObject_DSchematikaParser.hpp" + +namespace xo { + namespace scm { + auto + IGCObject_DSchematikaParser::shallow_size(const DSchematikaParser & self) noexcept -> size_type + { + return self.shallow_size(); + } + + auto + IGCObject_DSchematikaParser::shallow_copy(const DSchematikaParser & self, obj mm) noexcept -> Opaque + { + return self.shallow_copy(mm); + } + + auto + IGCObject_DSchematikaParser::forward_children(DSchematikaParser & self, obj gc) noexcept -> size_type + { + return self.forward_children(gc); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IGCObject_DSchematikaParser.cpp */ From 8331fa8a6be8ea4524a1240f2eac014924d40ced Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 24 Mar 2026 23:32:09 -0400 Subject: [PATCH 311/342] xo-tokenizer2: + op!= utest --- utest/SchematikaParser.test.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 7b9a2a26..e33348fc 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1122,7 +1122,6 @@ namespace xo { } #endif -#ifdef NOT_YET TEST_CASE("SchematikaParser-interactive-cmpne", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); @@ -1183,7 +1182,6 @@ namespace xo { log && fixture.log_memory_layout(&log); } -#endif TEST_CASE("SchematikaParser-interactive-cmpeq", "[reader2][SchematikaParser]") { From 1d3af64a7a09589f7b9a2be0d0ac66d737114ab0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 24 Mar 2026 23:32:09 -0400 Subject: [PATCH 312/342] xo-tokenizer2: + op!= utest --- include/xo/tokenizer2/Token.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/xo/tokenizer2/Token.hpp b/include/xo/tokenizer2/Token.hpp index 0968a9e9..f2d8eb08 100644 --- a/include/xo/tokenizer2/Token.hpp +++ b/include/xo/tokenizer2/Token.hpp @@ -133,6 +133,8 @@ namespace xo { /** token for @c "==" **/ static Token cmpeq_token() { return Token(tokentype::tk_cmpeq); } + /** token for @c "!=" **/ + static Token cmpne_token() { return Token(tokentype::tk_cmpne); } /** token representing keyword @c nil **/ static Token nil_token() { return Token(tokentype::tk_nil); } From aca798467a81eb8bcb783253bc01ad14034db97a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 24 Mar 2026 23:41:05 -0400 Subject: [PATCH 313/342] xo-reader2: move DDefineSsm generated support to spec'd subdirs --- idl/IPrintable_DDefineSsm.json5 | 4 +- idl/ISyntaxStateMachine_DDefineSsm.json5 | 4 +- include/xo/reader2/DefineSsm.hpp | 4 +- .../xo/reader2/ssm/IPrintable_DDefineSsm.hpp | 62 ------------- .../ssm/ISyntaxStateMachine_DDefineSsm.hpp | 87 ------------------ src/reader2/CMakeLists.txt | 4 +- src/reader2/DDefineSsm.cpp | 3 +- src/reader2/DIfElseSsm.cpp | 3 +- src/reader2/IPrintable_DDefineSsm.cpp | 28 ------ .../ISyntaxStateMachine_DDefineSsm.cpp | 89 ------------------- src/reader2/ParserStateMachine.cpp | 4 +- utest/SchematikaParser.test.cpp | 3 +- 12 files changed, 14 insertions(+), 281 deletions(-) delete mode 100644 include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp delete mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp delete mode 100644 src/reader2/IPrintable_DDefineSsm.cpp delete mode 100644 src/reader2/ISyntaxStateMachine_DDefineSsm.cpp diff --git a/idl/IPrintable_DDefineSsm.json5 b/idl/IPrintable_DDefineSsm.json5 index 28463e92..fbac5a89 100644 --- a/idl/IPrintable_DDefineSsm.json5 +++ b/idl/IPrintable_DDefineSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "define", includes: [ "", "" ], local_types: [], diff --git a/idl/ISyntaxStateMachine_DDefineSsm.json5 b/idl/ISyntaxStateMachine_DDefineSsm.json5 index 8b3fff2a..c4f7d357 100644 --- a/idl/ISyntaxStateMachine_DDefineSsm.json5 +++ b/idl/ISyntaxStateMachine_DDefineSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "define", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/include/xo/reader2/DefineSsm.hpp b/include/xo/reader2/DefineSsm.hpp index 4a4489a0..7ccdd2db 100644 --- a/include/xo/reader2/DefineSsm.hpp +++ b/include/xo/reader2/DefineSsm.hpp @@ -6,7 +6,7 @@ #pragma once #include "DDefineSsm.hpp" -#include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" -#include "ssm/IPrintable_DDefineSsm.hpp" +#include "define/ISyntaxStateMachine_DDefineSsm.hpp" +#include "define/IPrintable_DDefineSsm.hpp" /* end DefineSsm.hpp */ diff --git a/include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp b/include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp deleted file mode 100644 index d50b0394..00000000 --- a/include/xo/reader2/ssm/IPrintable_DDefineSsm.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/** @file IPrintable_DDefineSsm.hpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/IPrintable_DDefineSsm.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_repr.hpp.j2] - * 3. idl for facet methods - * [idl/IPrintable_DDefineSsm.json5] - **/ - -#pragma once - -#include "Printable.hpp" -#include -#include -#include "DDefineSsm.hpp" - -namespace xo { namespace scm { class IPrintable_DDefineSsm; } } - -namespace xo { - namespace facet { - template <> - struct FacetImplementation - { - using ImplType = xo::print::IPrintable_Xfer - ; - }; - } -} - -namespace xo { - namespace scm { - /** @class IPrintable_DDefineSsm - **/ - class IPrintable_DDefineSsm { - public: - /** @defgroup scm-printable-ddefinessm-type-traits **/ - ///@{ - using ppindentinfo = xo::print::APrintable::ppindentinfo; - using Copaque = xo::print::APrintable::Copaque; - using Opaque = xo::print::APrintable::Opaque; - ///@} - /** @defgroup scm-printable-ddefinessm-methods **/ - ///@{ - // const methods - /** Pretty-printing support for this object. -See [xo-indentlog/xo/indentlog/pretty.hpp] **/ - static bool pretty(const DDefineSsm & self, const ppindentinfo & ppii); - - // non-const methods - ///@} - }; - - } /*namespace scm*/ -} /*namespace xo*/ - -/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp deleted file mode 100644 index 3487a328..00000000 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/** @file ISyntaxStateMachine_DDefineSsm.hpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/ISyntaxStateMachine_DDefineSsm.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_repr.hpp.j2] - * 3. idl for facet methods - * [idl/ISyntaxStateMachine_DDefineSsm.json5] - **/ - -#pragma once - -#include "SyntaxStateMachine.hpp" -#include "SyntaxStateMachine.hpp" -#include "ssm/ISyntaxStateMachine_Xfer.hpp" -#include "DDefineSsm.hpp" - -namespace xo { namespace scm { class ISyntaxStateMachine_DDefineSsm; } } - -namespace xo { - namespace facet { - template <> - struct FacetImplementation - { - using ImplType = xo::scm::ISyntaxStateMachine_Xfer - ; - }; - } -} - -namespace xo { - namespace scm { - /** @class ISyntaxStateMachine_DDefineSsm - **/ - class ISyntaxStateMachine_DDefineSsm { - public: - /** @defgroup scm-syntaxstatemachine-ddefinessm-type-traits **/ - ///@{ - using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; - using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; - using Copaque = xo::scm::ASyntaxStateMachine::Copaque; - using Opaque = xo::scm::ASyntaxStateMachine::Opaque; - ///@} - /** @defgroup scm-syntaxstatemachine-ddefinessm-methods **/ - ///@{ - // const methods - /** identify a type of syntax state machine **/ - static syntaxstatetype ssm_type(const DDefineSsm & self) noexcept; - /** text describing expected/allowed input to this ssm in current state **/ - static std::string_view get_expect_str(const DDefineSsm & self) noexcept; - - // non-const methods - /** operate state machine for incoming token @p tk **/ - static void on_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update stat machine for incoming parsed symbol @p sym **/ - static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); - /** operate state machine for incoming type description @p td **/ - static void on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm); - /** update state machine for type emitted by nested ssm **/ - static void on_parsed_type(DDefineSsm & self, obj type, ParserStateMachine * p_psm); - /** operate state machine for formal emitted by nested ssm **/ - static void on_parsed_formal(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); - /** operate state machine for formal emitted by nested ssm **/ - static void on_parsed_formal_with_token(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); - /** consume formal arglist emitted by nested ssm **/ - static void on_parsed_formal_arglist(DDefineSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for nested parsed expression @p expr **/ - static void on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ - static void on_parsed_expression_with_token(DDefineSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for nested quoted literal @p lit **/ - static void on_quoted_literal(DDefineSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DDefineSsm & self, obj gc); - ///@} - }; - - } /*namespace scm*/ -} /*namespace xo*/ - -/* end */ \ No newline at end of file diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 30f11169..99b9a580 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -27,8 +27,8 @@ set(SELF_SRCS IPrintable_DToplevelSeqSsm.cpp DDefineSsm.cpp - ISyntaxStateMachine_DDefineSsm.cpp - IPrintable_DDefineSsm.cpp + facet/ISyntaxStateMachine_DDefineSsm.cpp + facet/IPrintable_DDefineSsm.cpp DDeftypeSsm.cpp facet/ISyntaxStateMachine_DDeftypeSsm.cpp diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 5e6b57ea..f9be0335 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -7,8 +7,7 @@ #include "DExpectSymbolSsm.hpp" #include "DExpectTypeSsm.hpp" #include "DExpectExprSsm.hpp" -#include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" -#include "ssm/IPrintable_DDefineSsm.hpp" +#include "DefineSsm.hpp" #include #include #include diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index 2be7f71c..03bd1589 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -5,7 +5,8 @@ #include "ifelse/DIfElseSsm.hpp" #include "ifelse/ISyntaxStateMachine_DIfElseSsm.hpp" -#include "ssm/IPrintable_DDefineSsm.hpp" +#include "DefineSsm.hpp" +//#include "define/IPrintable_DDefineSsm.hpp" #include "DExpectExprSsm.hpp" #include #include diff --git a/src/reader2/IPrintable_DDefineSsm.cpp b/src/reader2/IPrintable_DDefineSsm.cpp deleted file mode 100644 index dbd0bfc9..00000000 --- a/src/reader2/IPrintable_DDefineSsm.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/** @file IPrintable_DDefineSsm.cpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/IPrintable_DDefineSsm.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_any.hpp.j2] - * 3. idl for facet methods - * [idl/IPrintable_DDefineSsm.json5] -**/ - -#include "ssm/IPrintable_DDefineSsm.hpp" - -namespace xo { - namespace scm { - auto - IPrintable_DDefineSsm::pretty(const DDefineSsm & self, const ppindentinfo & ppii) -> bool - { - return self.pretty(ppii); - } - - - } /*namespace scm*/ -} /*namespace xo*/ - -/* end IPrintable_DDefineSsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp deleted file mode 100644 index 139a3314..00000000 --- a/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/** @file ISyntaxStateMachine_DDefineSsm.cpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/ISyntaxStateMachine_DDefineSsm.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_any.hpp.j2] - * 3. idl for facet methods - * [idl/ISyntaxStateMachine_DDefineSsm.json5] -**/ - -#include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" - -namespace xo { - namespace scm { - auto - ISyntaxStateMachine_DDefineSsm::ssm_type(const DDefineSsm & self) noexcept -> syntaxstatetype - { - return self.ssm_type(); - } - - auto - ISyntaxStateMachine_DDefineSsm::get_expect_str(const DDefineSsm & self) noexcept -> std::string_view - { - return self.get_expect_str(); - } - - auto - ISyntaxStateMachine_DDefineSsm::on_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_token(tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void - { - self.on_parsed_symbol(sym, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void - { - self.on_parsed_typedescr(td, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_parsed_type(DDefineSsm & self, obj type, ParserStateMachine * p_psm) -> void - { - self.on_parsed_type(type, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_parsed_formal(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void - { - self.on_parsed_formal(param_name, param_type, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_parsed_formal_with_token(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_parsed_formal_arglist(DDefineSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void - { - self.on_parsed_formal_arglist(arglist, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm) -> void - { - self.on_parsed_expression(expr, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_parsed_expression_with_token(DDefineSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void - { - self.on_parsed_expression_with_token(expr, tk, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::on_quoted_literal(DDefineSsm & self, obj lit, ParserStateMachine * p_psm) -> void - { - self.on_quoted_literal(lit, p_psm); - } - auto - ISyntaxStateMachine_DDefineSsm::forward_children(DDefineSsm & self, obj gc) -> void - { - self.forward_children(gc); - } - - } /*namespace scm*/ -} /*namespace xo*/ - -/* end ISyntaxStateMachine_DDefineSsm.cpp */ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 63c333e1..b6f69439 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -902,8 +902,8 @@ namespace xo { void ParserStateMachine::forward_children(obj gc) noexcept { - static_assert(!stringtable_.is_gc_eligible()); - static_assert(!parser_alloc_.is_gc_eligible()); + assert(!stringtable_.is_gc_eligible()); + assert(!parser_alloc_.is_gc_eligible()); if (stack_) { stack_->forward_children(gc); diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index e33348fc..57436c70 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -6,8 +6,7 @@ #include #include #include -#include -#include +#include #include #include #include From f0d4e5801040ce1d854a65d1c5a631397dedfd0b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 25 Mar 2026 17:11:46 -0400 Subject: [PATCH 314/342] xo-reader2 stack: refactor for ssm file location --- idl/IPrintable_DQuoteSsm.json5 | 4 +- idl/ISyntaxStateMachine_DQuoteSsm.json5 | 4 +- .../reader2/define/IPrintable_DDefineSsm.hpp | 62 +++++++++++++ .../define/ISyntaxStateMachine_DDefineSsm.hpp | 87 ++++++++++++++++++ .../xo/reader2/quote/IPrintable_DQuoteSsm.hpp | 62 +++++++++++++ .../quote/ISyntaxStateMachine_DQuoteSsm.hpp | 87 ++++++++++++++++++ src/reader2/CMakeLists.txt | 4 +- src/reader2/facet/IPrintable_DDefineSsm.cpp | 28 ++++++ .../{ => facet}/IPrintable_DQuoteSsm.cpp | 2 +- .../facet/ISyntaxStateMachine_DDefineSsm.cpp | 89 +++++++++++++++++++ .../ISyntaxStateMachine_DQuoteSsm.cpp | 2 +- 11 files changed, 423 insertions(+), 8 deletions(-) create mode 100644 include/xo/reader2/define/IPrintable_DDefineSsm.hpp create mode 100644 include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp create mode 100644 include/xo/reader2/quote/IPrintable_DQuoteSsm.hpp create mode 100644 include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp create mode 100644 src/reader2/facet/IPrintable_DDefineSsm.cpp rename src/reader2/{ => facet}/IPrintable_DQuoteSsm.cpp (94%) create mode 100644 src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp rename src/reader2/{ => facet}/ISyntaxStateMachine_DQuoteSsm.cpp (98%) diff --git a/idl/IPrintable_DQuoteSsm.json5 b/idl/IPrintable_DQuoteSsm.json5 index d1c28a15..d7c41b0a 100644 --- a/idl/IPrintable_DQuoteSsm.json5 +++ b/idl/IPrintable_DQuoteSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "quote", includes: [ "", "" ], local_types: [], diff --git a/idl/ISyntaxStateMachine_DQuoteSsm.json5 b/idl/ISyntaxStateMachine_DQuoteSsm.json5 index a70a4aa4..60d41730 100644 --- a/idl/ISyntaxStateMachine_DQuoteSsm.json5 +++ b/idl/ISyntaxStateMachine_DQuoteSsm.json5 @@ -1,8 +1,8 @@ { mode: "implementation", - output_cpp_dir: "src/reader2", + output_cpp_dir: "src/reader2/facet", output_hpp_dir: "include/xo/reader2", - output_impl_subdir: "ssm", + output_impl_subdir: "quote", includes: [ "\"SyntaxStateMachine.hpp\"", "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], local_types: [ ], diff --git a/include/xo/reader2/define/IPrintable_DDefineSsm.hpp b/include/xo/reader2/define/IPrintable_DDefineSsm.hpp new file mode 100644 index 00000000..d50b0394 --- /dev/null +++ b/include/xo/reader2/define/IPrintable_DDefineSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DDefineSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DDefineSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DDefineSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DDefineSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DDefineSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DDefineSsm + **/ + class IPrintable_DDefineSsm { + public: + /** @defgroup scm-printable-ddefinessm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-ddefinessm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DDefineSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp new file mode 100644 index 00000000..3487a328 --- /dev/null +++ b/include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp @@ -0,0 +1,87 @@ +/** @file ISyntaxStateMachine_DDefineSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DDefineSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DDefineSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DDefineSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DDefineSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DDefineSsm + **/ + class ISyntaxStateMachine_DDefineSsm { + public: + /** @defgroup scm-syntaxstatemachine-ddefinessm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-ddefinessm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DDefineSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DDefineSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DDefineSsm & self, obj type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DDefineSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for nested parsed expression @p expr **/ + static void on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DDefineSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DDefineSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DDefineSsm & self, obj gc); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/quote/IPrintable_DQuoteSsm.hpp b/include/xo/reader2/quote/IPrintable_DQuoteSsm.hpp new file mode 100644 index 00000000..2b969c50 --- /dev/null +++ b/include/xo/reader2/quote/IPrintable_DQuoteSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DQuoteSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DQuoteSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DQuoteSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DQuoteSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DQuoteSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DQuoteSsm + **/ + class IPrintable_DQuoteSsm { + public: + /** @defgroup scm-printable-dquotessm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dquotessm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DQuoteSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp b/include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp new file mode 100644 index 00000000..811119c5 --- /dev/null +++ b/include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp @@ -0,0 +1,87 @@ +/** @file ISyntaxStateMachine_DQuoteSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DQuoteSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DQuoteSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DQuoteSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DQuoteSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DQuoteSsm + **/ + class ISyntaxStateMachine_DQuoteSsm { + public: + /** @defgroup scm-syntaxstatemachine-dquotessm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dquotessm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DQuoteSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DQuoteSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DQuoteSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DQuoteSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DQuoteSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DQuoteSsm & self, obj type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DQuoteSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DQuoteSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DQuoteSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for nested parsed expression @p expr **/ + static void on_parsed_expression(DQuoteSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DQuoteSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DQuoteSsm & self, obj lit, ParserStateMachine * p_psm); + /** gc support: move immediate children to to-space and sub forwarding pointer **/ + static void forward_children(DQuoteSsm & self, obj gc); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index 99b9a580..c2ba12e9 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -99,8 +99,8 @@ set(SELF_SRCS IPrintable_DProgressSsm.cpp DQuoteSsm.cpp - ISyntaxStateMachine_DQuoteSsm.cpp - IPrintable_DQuoteSsm.cpp + facet/ISyntaxStateMachine_DQuoteSsm.cpp + facet/IPrintable_DQuoteSsm.cpp ) diff --git a/src/reader2/facet/IPrintable_DDefineSsm.cpp b/src/reader2/facet/IPrintable_DDefineSsm.cpp new file mode 100644 index 00000000..c63eaf7f --- /dev/null +++ b/src/reader2/facet/IPrintable_DDefineSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DDefineSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DDefineSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DDefineSsm.json5] +**/ + +#include "define/IPrintable_DDefineSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DDefineSsm::pretty(const DDefineSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DDefineSsm.cpp */ diff --git a/src/reader2/IPrintable_DQuoteSsm.cpp b/src/reader2/facet/IPrintable_DQuoteSsm.cpp similarity index 94% rename from src/reader2/IPrintable_DQuoteSsm.cpp rename to src/reader2/facet/IPrintable_DQuoteSsm.cpp index 303acefb..b190ec52 100644 --- a/src/reader2/IPrintable_DQuoteSsm.cpp +++ b/src/reader2/facet/IPrintable_DQuoteSsm.cpp @@ -11,7 +11,7 @@ * [idl/IPrintable_DQuoteSsm.json5] **/ -#include "ssm/IPrintable_DQuoteSsm.hpp" +#include "quote/IPrintable_DQuoteSsm.hpp" namespace xo { namespace scm { diff --git a/src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp new file mode 100644 index 00000000..9867898f --- /dev/null +++ b/src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp @@ -0,0 +1,89 @@ +/** @file ISyntaxStateMachine_DDefineSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DDefineSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DDefineSsm.json5] +**/ + +#include "define/ISyntaxStateMachine_DDefineSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DDefineSsm::ssm_type(const DDefineSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DDefineSsm::get_expect_str(const DDefineSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DDefineSsm::on_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_symbol(DDefineSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_typedescr(DDefineSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_type(DDefineSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_formal(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_formal_with_token(DDefineSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_formal_arglist(DDefineSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_expression(DDefineSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::on_parsed_expression_with_token(DDefineSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::on_quoted_literal(DDefineSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } + auto + ISyntaxStateMachine_DDefineSsm::forward_children(DDefineSsm & self, obj gc) -> void + { + self.forward_children(gc); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DDefineSsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp similarity index 98% rename from src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp rename to src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp index c219db80..9624c899 100644 --- a/src/reader2/ISyntaxStateMachine_DQuoteSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp @@ -11,7 +11,7 @@ * [idl/ISyntaxStateMachine_DQuoteSsm.json5] **/ -#include "ssm/ISyntaxStateMachine_DQuoteSsm.hpp" +#include "quote/ISyntaxStateMachine_DQuoteSsm.hpp" namespace xo { namespace scm { From 7be5869c9337108b251c7057d7f13a5671b57d62 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 25 Mar 2026 17:52:39 -0400 Subject: [PATCH 315/342] xo-reader2 stack: constants for operator primitive names --- src/reader2/ParserStateMachine.cpp | 31 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index b6f69439..eaff855c 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -8,6 +8,7 @@ #include "SyntaxStateMachine.hpp" #include "ToplevelSeqSsm.hpp" #include "DefineSsm.hpp" +#include #include #include #include @@ -107,61 +108,71 @@ namespace xo { // { - const DUniqueString * name = stringtable_.lookup("_mul"); + const DUniqueString * name + = stringtable_.lookup(NumericPrimitives::c_multiply_pm_name); assert(name); this->multiply_binding_ = global_symtab_->lookup_binding(name); } { - const DUniqueString * name = stringtable_.lookup("_div"); + const DUniqueString * name + = stringtable_.lookup(NumericPrimitives::c_divide_pm_name); assert(name); this->divide_binding_ = global_symtab_->lookup_binding(name); } { - const DUniqueString * name = stringtable_.lookup("_add"); + const DUniqueString * name + = stringtable_.lookup(NumericPrimitives::c_add_pm_name); assert(name); this->add_binding_ = global_symtab_->lookup_binding(name); } { - const DUniqueString * name = stringtable_.lookup("_sub"); + const DUniqueString * name + = stringtable_.lookup(NumericPrimitives::c_sub_pm_name); assert(name); this->subtract_binding_ = global_symtab_->lookup_binding(name); } { - const DUniqueString * name = stringtable_.lookup("_cmpeq"); + const DUniqueString * name + = stringtable_.lookup(NumericPrimitives::c_cmpeq_pm_name); assert(name); this->cmpeq_binding_ = global_symtab_->lookup_binding(name); } { - const DUniqueString * name = stringtable_.lookup("_cmpne"); + const DUniqueString * name + = stringtable_.lookup(NumericPrimitives::c_cmpne_pm_name); assert(name); this->cmpne_binding_ = global_symtab_->lookup_binding(name); } { - const DUniqueString * name = stringtable_.lookup("_cmplt"); + const DUniqueString * name + = stringtable_.lookup(NumericPrimitives::c_cmplt_pm_name); assert(name); this->cmplt_binding_ = global_symtab_->lookup_binding(name); } { - const DUniqueString * name = stringtable_.lookup("_cmple"); + const DUniqueString * name + = stringtable_.lookup(NumericPrimitives::c_cmple_pm_name); assert(name); this->cmple_binding_ = global_symtab_->lookup_binding(name); } { - const DUniqueString * name = stringtable_.lookup("_cmpgt"); + const DUniqueString * name + = stringtable_.lookup(NumericPrimitives::c_cmpgt_pm_name); assert(name); this->cmpgt_binding_ = global_symtab_->lookup_binding(name); } { - const DUniqueString * name = stringtable_.lookup("_cmpge"); + const DUniqueString * name + = stringtable_.lookup(NumericPrimitives::c_gmpge_pm_name); assert(name); this->cmpge_binding_ = global_symtab_->lookup_binding(name); } From f8839278c382d4e7e7c010d16ef169f38ab70de5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 25 Mar 2026 18:00:36 -0400 Subject: [PATCH 316/342] xo-interpreter2 stack: scaffold for virtual root VSM [WIP] --- include/xo/reader2/SchematikaReader.hpp | 8 ++++++++ src/reader2/SchematikaReader.cpp | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index 58c77ec8..de3da42f 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -12,10 +12,14 @@ namespace xo { namespace scm { struct ReaderResult { + using ACollector = xo::mm::ACollector; using span_type = xo::mm::span; bool is_tk_error() const { return tk_error_.is_error(); } + /** forward gc-aware pointers (called during gc cycle) **/ + void forward_children(obj gc) noexcept; + /** schematika expression parsed from input **/ obj expr_; /** unconsumed portion of input span @@ -35,6 +39,7 @@ namespace xo { **/ class SchematikaReader { public: + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using span_type = xo::mm::span; @@ -101,6 +106,9 @@ namespace xo { **/ void reset_to_idle_toplevel(); + /** update gc-aware child pointers **/ + void forward_children(obj gc) noexcept; + private: /** tokenizer converts a stream of chars * to a stream of lexical tokens diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index 0db3f337..ba681bab 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -9,6 +9,14 @@ namespace xo { using xo::mm::MemorySizeInfo; namespace scm { + void + ReaderResult::forward_children(obj gc) noexcept + { + gc.forward_pivot_inplace(&expr_); + } + + // ----- SchematikaReader ----- + SchematikaReader::SchematikaReader(const ReaderConfig & config, obj expr_alloc, obj aux_alloc) @@ -198,6 +206,16 @@ namespace xo { this->tokenizer_.discard_current_line(); this->parser_.reset_to_idle_toplevel(); } + + void + SchematikaReader::forward_children(obj gc) noexcept + { + // tokenizer doesn't contain any gc-aware pointers. + + parser_.forward_children(gc); + result_.forward_children(gc); + } + } /*namespace scm*/ } /*namespace xo*/ From 3806b46ea187bfc957589ace9452ea0247ba1972 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 25 Mar 2026 19:31:59 -0400 Subject: [PATCH 317/342] xo-interpreter2 stack: VSM as AGCObject for virtual root --- src/reader2/ParserStateMachine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index eaff855c..0b95da88 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -172,7 +172,7 @@ namespace xo { { const DUniqueString * name - = stringtable_.lookup(NumericPrimitives::c_gmpge_pm_name); + = stringtable_.lookup(NumericPrimitives::c_cmpge_pm_name); assert(name); this->cmpge_binding_ = global_symtab_->lookup_binding(name); } From af96e82c21196789265e78f248c40d7e05f757bb Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 26 Mar 2026 11:30:16 -0400 Subject: [PATCH 318/342] xo-gc: generation -> Generation + bugfix idle test --- utest/SchematikaParser.test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 57436c70..0748a1a7 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -51,7 +51,7 @@ namespace xo { using xo::mm::AGCObject; using xo::mm::DArena; using xo::mm::DX1Collector; - using xo::mm::generation; + using xo::mm::Generation; using xo::mm::X1CollectorConfig; using xo::mm::CollectorTypeRegistry; using xo::mm::MemorySizeInfo; @@ -241,7 +241,7 @@ namespace xo { if (fixture->gc_flag_) { REQUIRE(expr_gc); - expr_gc.request_gc(generation(2)); + expr_gc.request_gc(Generation(2)); } } } From ff471bbc72eb51533a03d73f6c623697e1d8e7a3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 27 Mar 2026 11:16:28 -0400 Subject: [PATCH 319/342] xo-interpreter2 stack: wrap TokenizerError as DRuntimeError Also fix _read_eval_print() to report them! --- cmake/xo_tokenizer2Config.cmake.in | 1 + include/xo/tokenizer2/TokenizerError.hpp | 6 ++++++ src/tokenizer2/CMakeLists.txt | 1 + src/tokenizer2/TokenizerError.cpp | 14 ++++++++++++++ 4 files changed, 22 insertions(+) diff --git a/cmake/xo_tokenizer2Config.cmake.in b/cmake/xo_tokenizer2Config.cmake.in index eccd2745..0c0dad0b 100644 --- a/cmake/xo_tokenizer2Config.cmake.in +++ b/cmake/xo_tokenizer2Config.cmake.in @@ -6,6 +6,7 @@ include(CMakeFindDependencyMacro) # must coordinate with xo_dependency() calls # in src/tokenizer2/CMakeLists.txt # +find_dependency(xo_stringtable2) find_dependency(xo_arena) find_dependency(indentlog) diff --git a/include/xo/tokenizer2/TokenizerError.hpp b/include/xo/tokenizer2/TokenizerError.hpp index bf7702b1..b08889bd 100644 --- a/include/xo/tokenizer2/TokenizerError.hpp +++ b/include/xo/tokenizer2/TokenizerError.hpp @@ -8,6 +8,8 @@ #include "TkInputState.hpp" #include "tokentype.hpp" #include "span.hpp" +#include +#include #include namespace xo { @@ -19,6 +21,7 @@ namespace xo { **/ class TokenizerError { public: + using AAllocator = xo::mm::AAllocator; using CharT = char; using span_type = xo::mm::span; @@ -89,6 +92,9 @@ namespace xo { /** Print human-oriented error report on @p os. **/ void report(std::ostream & os) const; + /** Similar to report, but capture as string, allocated from @p mm **/ + DString * report_to_string(obj mm) const; + ///@} private: diff --git a/src/tokenizer2/CMakeLists.txt b/src/tokenizer2/CMakeLists.txt index ccf1b551..3a748e70 100644 --- a/src/tokenizer2/CMakeLists.txt +++ b/src/tokenizer2/CMakeLists.txt @@ -11,6 +11,7 @@ set(SELF_SRCS xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) # deps must coordinate with xo-tokenizer/cmake/xo_tokenizer2Config.cmake.in +xo_dependency(${SELF_LIB} xo_stringtable2) xo_dependency(${SELF_LIB} xo_arena) xo_dependency(${SELF_LIB} indentlog) diff --git a/src/tokenizer2/TokenizerError.cpp b/src/tokenizer2/TokenizerError.cpp index ffe3c8b4..c80996d9 100644 --- a/src/tokenizer2/TokenizerError.cpp +++ b/src/tokenizer2/TokenizerError.cpp @@ -54,6 +54,20 @@ namespace xo { } } + DString * + TokenizerError::report_to_string(obj dest_mm) const + { + // FIXME: + // using heap here for scratch space. + // Would prefer to checkpoint + realloc. + + std::stringstream ss; + + this->report(ss); + + return DString::from_str(dest_mm, ss.str()); + } + } /*namespace scm*/ } /*namespace xo*/ From c715f0d8be11be3868abd05777315c856db582e0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 27 Mar 2026 22:40:44 -0400 Subject: [PATCH 320/342] xo-reader2: utest: drop DX1Collector debug --- utest/SchematikaParser.test.cpp | 90 +++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 0748a1a7..87f16e78 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -250,7 +250,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); @@ -380,7 +380,7 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); // [0] arena; [1] gc - constexpr std::array c_debug_flag_v = {{false, true}}; + constexpr std::array c_debug_flag_v = {{false, false}}; test_driver(testname, &test_batch_def, @@ -430,55 +430,67 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); // [0] arena; [1] gc - constexpr std::array c_debug_flag_v = {{false, true}}; + constexpr std::array c_debug_flag_v = {{false, false}}; test_driver(testname, &test_batch_deftype, c_debug_flag_v); } - TEST_CASE("SchematikaParser-batch-deftype-2", "[reader2][SchematikaParser]") + namespace { + void + test_batch_deftype2(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; + + parser->begin_batch_session(); + + /** Walkthrough parsing input equivalent to: + * + * deftype foo :: list; + **/ + + std::vector tk_v{ + Token::deftype_token(), + Token::symbol_token("foo"), + Token::doublecolon_token(), + Token::symbol_token("list"), + Token::leftangle_token(), + Token::symbol_token("f64"), + Token::rightangle_token(), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); + + const auto & result = parser->result(); + { + // placeholder for form's sake. + // deftype doesn't actuallly produce any executable content + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + + log && fixture->log_memory_layout(&log); + } + } + + TEST_CASE("SchematikaParser-batch-deftype2", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; - - parser->begin_batch_session(); - - /** Walkthrough parsing input equivalent to: - * - * deftype foo :: list; - **/ - - std::vector tk_v{ - Token::deftype_token(), - Token::symbol_token("foo"), - Token::doublecolon_token(), - Token::symbol_token("list"), - Token::leftangle_token(), - Token::symbol_token("f64"), - Token::rightangle_token(), - Token::semicolon_token(), - }; - - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); - - const auto & result = parser->result(); - { - // placeholder for form's sake. - // deftype doesn't actuallly produce any executable content - - auto expr = obj::from(result.result_expr()); - REQUIRE(expr); - } - - log && fixture.log_memory_layout(&log); + test_driver(testname, + &test_batch_deftype2, + c_debug_flag_v); } +#ifdef NOPE TEST_CASE("SchematikaParser-interactive-def2", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); From ce800d700c141ee543db8ba9ef6f759442c37dac Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 28 Mar 2026 09:43:43 -0400 Subject: [PATCH 321/342] xo-reader2: expand utest to run gc [WIP] --- src/reader2/DLambdaSsm.cpp | 4 + src/reader2/ParserStateMachine.cpp | 9 + utest/SchematikaParser.test.cpp | 411 ++++++++++++++++++----------- 3 files changed, 267 insertions(+), 157 deletions(-) diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 8f5a0bc3..d23f04e6 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -477,6 +477,10 @@ namespace xo { DLambdaSsm::forward_children(obj gc) noexcept { gc.forward_inplace(&local_symtab_); + + // explicit_return_td not gcobject + // lambda_td not gcobject + gc.forward_pivot_inplace(&body_); gc.forward_pivot_inplace(&parent_symtab_); } diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 0b95da88..bb5fd4c8 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -913,9 +913,12 @@ namespace xo { void ParserStateMachine::forward_children(obj gc) noexcept { + scope log(XO_DEBUG(true)); + assert(!stringtable_.is_gc_eligible()); assert(!parser_alloc_.is_gc_eligible()); + log && log("forward stack_"); if (stack_) { stack_->forward_children(gc); } @@ -923,10 +926,16 @@ namespace xo { // static_assert(!expr_alloc_.is_gc_eligible()); // static_assert(!aux_alloc_.is_gc_eligible()); + log && log("global_symtab_"); gc.forward_inplace(&global_symtab_); + + log && log("local_symtab_"); gc.forward_inplace(&local_symtab_); + + log && log("global_env_"); gc.forward_inplace(&global_env_); + log && log("result_"); result_.forward_children(gc); } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 87f16e78..df0f5e56 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -77,7 +77,7 @@ namespace xo { = (X1CollectorConfig() .with_name("gc") .with_size(32 * 1024) - .with_debug_flag(true) + .with_debug_flag(debug_flag) .with_sanitize_flag(true)); dp expr_x1_dp @@ -371,10 +371,10 @@ namespace xo { test_subject(&fixture); } - } } +#ifdef NOPE TEST_CASE("SchematikaParser-batch-def", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); @@ -490,82 +490,87 @@ namespace xo { c_debug_flag_v); } -#ifdef NOPE + namespace { + void test_interactive_def2(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; + + parser->begin_interactive_session(); + + { + /** Walkthrough parsing input equivalent to: + * + * def foo : f64 = 3.141593 ; + * + **/ + + std::vector tk_v{ + Token::def_token(), + Token::symbol_token("foo"), + Token::colon_token(), + Token::symbol_token("f64"), + Token::singleassign_token(), + Token::f64_token("3.141593"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); + + const auto & result = parser->result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + + parser->reset_result(); + } + + { + /** Walkthrough parsing input equivalent to: + * + * foo ; + * + **/ + + std::vector tk_v{ +// Token::f64_token("2.0"), +// Token::star_token(), + Token::symbol_token("foo"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); + + const auto & result = parser->result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + } + + log && fixture->log_memory_layout(&log); + } + } + TEST_CASE("SchematikaParser-interactive-def2", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; - - parser->begin_interactive_session(); - - { - /** Walkthrough parsing input equivalent to: - * - * def foo : f64 = 3.141593 ; - * - **/ - - std::vector tk_v{ - Token::def_token(), - Token::symbol_token("foo"), - Token::colon_token(), - Token::symbol_token("f64"), - Token::singleassign_token(), - Token::f64_token("3.141593"), - Token::semicolon_token(), - }; - - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); - - const auto & result = parser->result(); - { - auto expr = obj::from(result.result_expr()); - REQUIRE(expr); - } - - parser->reset_result(); - } - - { - /** Walkthrough parsing input equivalent to: - * - * foo ; - * - **/ - - std::vector tk_v{ -// Token::f64_token("2.0"), -// Token::star_token(), - Token::symbol_token("foo"), - Token::semicolon_token(), - }; - - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); - - const auto & result = parser->result(); - { - auto expr = obj::from(result.result_expr()); - REQUIRE(expr); - } - } - - log && fixture.log_memory_layout(&log); + test_driver(testname, + &test_interactive_def2, + c_debug_flag_v); } - TEST_CASE("SchematikaParser-interactive-integer", "[reader2][SchematikaParser]") + void test_interactive_integer(ParserFixture * fixture) { - const auto & testname = Catch::getResultCapture().getCurrentTestName(); + scope log(XO_DEBUG(fixture->debug_flag_)); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -615,18 +620,26 @@ namespace xo { //// illegal input on token //REQUIRE(result.error_description()); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-float", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-integer", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + test_driver(testname, + &test_interactive_integer, + c_debug_flag_v); + } + + void test_interactive_float(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -676,18 +689,26 @@ namespace xo { //// illegal input on token //REQUIRE(result.error_description()); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-string", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-float", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + test_driver(testname, + &test_interactive_float, + c_debug_flag_v); + } + + void test_interactive_string(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -737,18 +758,26 @@ namespace xo { //// illegal input on token //REQUIRE(result.error_description()); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-nil", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-string", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + test_driver(testname, + &test_interactive_string, + c_debug_flag_v); + } + + void test_interactive_nil(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -798,18 +827,26 @@ namespace xo { //// illegal input on token //REQUIRE(result.error_description()); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-arith", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-nil", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + test_driver(testname, + &test_interactive_nil, + c_debug_flag_v); + } + + void test_interactive_arith(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -826,7 +863,7 @@ namespace xo { Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); const auto & result = parser->result(); { @@ -857,18 +894,26 @@ namespace xo { REQUIRE(rhs_f64->value() == 0.5); } - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-arith2", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-arith", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + test_driver(testname, + &test_interactive_arith, + c_debug_flag_v); + } + + void test_interactive_arith2(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -885,9 +930,7 @@ namespace xo { Token::semicolon_token(), }; - INFO(testname); - - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); const auto & result = parser->result(); { @@ -918,18 +961,26 @@ namespace xo { REQUIRE(rhs_f64->value() == 10.0); } - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-arith3", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-arith2", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + test_driver(testname, + &test_interactive_arith2, + c_debug_flag_v); + } + + void test_interactive_arith3(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -948,9 +999,7 @@ namespace xo { Token::semicolon_token(), }; - INFO(testname); - - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); const auto & result = parser->result(); { @@ -988,18 +1037,26 @@ namespace xo { REQUIRE(rhs_i64->value() == 3); } - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-arith4", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-arith3", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + test_driver(testname, + &test_interactive_arith3, + c_debug_flag_v); + } + + void test_interactive_arith4(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1018,9 +1075,7 @@ namespace xo { Token::semicolon_token(), }; - INFO(testname); - - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); const auto & result = parser->result(); { @@ -1057,7 +1112,19 @@ namespace xo { REQUIRE(rhs_rhs_i64->value() == 3); } - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); + } /*test_interactive_arith4*/ + + TEST_CASE("SchematikaParser-interactive-arith4", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + + test_driver(testname, + &test_interactive_arith4, + c_debug_flag_v); } #ifdef OBSOLETE @@ -1133,16 +1200,11 @@ namespace xo { } #endif - TEST_CASE("SchematikaParser-interactive-cmpne", "[reader2][SchematikaParser]") + void test_interactive_cmpne(ParserFixture * fixture) { - const auto & testname = Catch::getResultCapture().getCurrentTestName(); + scope log(XO_DEBUG(fixture->debug_flag_)); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), - xtag("test", testname)); - - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1160,7 +1222,7 @@ namespace xo { /* [3] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); const auto & result = parser->result(); { @@ -1191,19 +1253,26 @@ namespace xo { REQUIRE(rhs_i64->value() == 312); } - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-cmpeq", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-cmpne", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), - xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + test_driver(testname, + &test_interactive_cmpne, + c_debug_flag_v); + } + + void test_interactive_cmpeq(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1221,7 +1290,7 @@ namespace xo { /* [3] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); const auto & result = parser->result(); { @@ -1252,19 +1321,26 @@ namespace xo { REQUIRE(rhs_i64->value() == 312); } - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-if1", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-cmpeq", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), - xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + test_driver(testname, + &test_interactive_cmpeq, + c_debug_flag_v); + } + + void test_interactive_if1(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1284,7 +1360,7 @@ namespace xo { /* [4] */ Token::semicolon_token() }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); } { @@ -1321,7 +1397,7 @@ namespace xo { /* [c] */ Token::semicolon_token() }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); } const auto & result = parser->result(); @@ -1330,18 +1406,27 @@ namespace xo { REQUIRE(expr); } - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-if1", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + test_driver(testname, + &test_interactive_if1, + c_debug_flag_v); + } +#endif + + void test_interactive_lambda(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1371,11 +1456,23 @@ namespace xo { /* [ e] */ Token::rightbrace_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } + TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, true}}; + test_driver(testname, + &test_interactive_lambda, + c_debug_flag_v); + } + +#ifdef NOPE TEST_CASE("SchematikaParser-interactive-if2", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); @@ -1894,7 +1991,7 @@ namespace xo { log && fixture.log_memory_layout(&log); } - +#endif } /*namespace ut*/ } /*namespace xo*/ From c982a2241e0d156a89e9d9c85128314c076183e1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 28 Mar 2026 13:58:46 -0400 Subject: [PATCH 322/342] xo-reader2: retire some ParserStateMachine logging --- src/reader2/ParserStateMachine.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index bb5fd4c8..b7f01f0d 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -913,12 +913,12 @@ namespace xo { void ParserStateMachine::forward_children(obj gc) noexcept { - scope log(XO_DEBUG(true)); + //scope log(XO_DEBUG(true)); assert(!stringtable_.is_gc_eligible()); assert(!parser_alloc_.is_gc_eligible()); - log && log("forward stack_"); + //log && log("forward stack_", xtag("addr", stack_)); if (stack_) { stack_->forward_children(gc); } @@ -926,16 +926,16 @@ namespace xo { // static_assert(!expr_alloc_.is_gc_eligible()); // static_assert(!aux_alloc_.is_gc_eligible()); - log && log("global_symtab_"); + //log && log("global_symtab_", xtag("addr", global_symtab_.data())); gc.forward_inplace(&global_symtab_); - log && log("local_symtab_"); + //log && log("local_symtab_", xtag("addr", local_symtab_.data())); gc.forward_inplace(&local_symtab_); - log && log("global_env_"); + //log && log("global_env_", xtag("addr", global_env_.data())); gc.forward_inplace(&global_env_); - log && log("result_"); + //log && log("result_"); result_.forward_children(gc); } From 1d7339f69492f89aa744f9ca5bfc6ef2e40ce00f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 28 Mar 2026 13:59:14 -0400 Subject: [PATCH 323/342] xo-reader2: utest: parser utests verify full GC behavior also --- utest/SchematikaParser.test.cpp | 277 ++++++++++++++++++++------------ 1 file changed, 177 insertions(+), 100 deletions(-) diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index df0f5e56..d2234b6f 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -374,7 +374,6 @@ namespace xo { } } -#ifdef NOPE TEST_CASE("SchematikaParser-batch-def", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); @@ -1198,8 +1197,9 @@ namespace xo { log && fixture.log_memory_layout(&log); } -#endif +#endif // OBSOLETE +#ifdef NOPE void test_interactive_cmpne(ParserFixture * fixture) { scope log(XO_DEBUG(fixture->debug_flag_)); @@ -1466,22 +1466,17 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); // [0] arena; [1] gc - constexpr std::array c_debug_flag_v = {{false, true}}; + constexpr std::array c_debug_flag_v = {{false, false}}; test_driver(testname, &test_interactive_lambda, c_debug_flag_v); } -#ifdef NOPE - TEST_CASE("SchematikaParser-interactive-if2", "[reader2][SchematikaParser]") + void test_interactive_if2(ParserFixture * fixture) { - const auto & testname = Catch::getResultCapture().getCurrentTestName(); + scope log(XO_DEBUG(fixture->debug_flag_)); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); - - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1502,20 +1497,27 @@ namespace xo { /* [6] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-lambda2", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-if2", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_interactive_if2, + c_debug_flag_v); + } - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + void test_interactive_lambda2(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1543,20 +1545,27 @@ namespace xo { /* [ c] */ Token::rightbrace_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-apply", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-lambda2", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_interactive_lambda2, + c_debug_flag_v); + } - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + void test_interactive_apply(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1589,22 +1598,27 @@ namespace xo { /* [ g] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-interactive-apply2", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-apply", "[reader2][SchematikaParser]") { - // top-level apply, with multiple arguments - const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_interactive_apply, + c_debug_flag_v); + } - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + void test_interactive_apply2(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1647,22 +1661,29 @@ namespace xo { /* [ m] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-batch-def2", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-interactive-apply2", "[reader2][SchematikaParser]") { - // top-level recursive function definition + // top-level apply, with multiple arguments const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_interactive_apply2, + c_debug_flag_v); + } - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + void test_batch_def2(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1705,22 +1726,29 @@ namespace xo { /* [ q] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-batch-qliteral1", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-batch-def2", "[reader2][SchematikaParser]") { // top-level recursive function definition const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_batch_def2, + c_debug_flag_v); + } - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + void test_batch_qliteral1(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1740,22 +1768,30 @@ namespace xo { /* [ 4] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-batch-qliteral2", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-batch-qliteral1", "[reader2][SchematikaParser]") { // top-level recursive function definition const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_batch_qliteral1, + c_debug_flag_v); - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + } + + void test_batch_qliteral2(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1783,22 +1819,30 @@ namespace xo { /* [ 9] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-batch-qlist", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-batch-qliteral2", "[reader2][SchematikaParser]") { // top-level recursive function definition const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_batch_qliteral2, + c_debug_flag_v); - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + } + + void test_batch_qlist(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1821,22 +1865,29 @@ namespace xo { /* [ 7] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-batch-qlist2", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-batch-qlist", "[reader2][SchematikaParser]") { // top-level recursive function definition const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_batch_qlist, + c_debug_flag_v); + } - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + void test_batch_qlist2(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1859,22 +1910,27 @@ namespace xo { /* [ 7] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-batch-qarray", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-batch-qlist2", "[reader2][SchematikaParser]") { - // top-level recursive function definition - const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_batch_qlist2, + c_debug_flag_v); + } - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + void test_batch_qarray(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1897,22 +1953,27 @@ namespace xo { /* [ 7] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-batch-qdict0", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-batch-qarray", "[reader2][SchematikaParser]") { - // top-level recursive function definition - const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_batch_qarray, + c_debug_flag_v); + } - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + void test_batch_qdict0(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1935,22 +1996,27 @@ namespace xo { /* [ 5] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } - TEST_CASE("SchematikaParser-batch-qdict1", "[reader2][SchematikaParser]") + TEST_CASE("SchematikaParser-batch-qdict0", "[reader2][SchematikaParser]") { - // top-level recursive function definition - const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = false; - scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_batch_qdict0, + c_debug_flag_v); + } - ParserFixture fixture(testname, false /*!gc*/, c_debug_flag); - auto parser = fixture.parser_; + void test_batch_qdict1(ParserFixture * fixture) + { + scope log(XO_DEBUG(fixture->debug_flag_)); + + auto parser = fixture->parser_; parser->begin_interactive_session(); @@ -1987,11 +2053,22 @@ namespace xo { /* [ g] */ Token::semicolon_token(), }; - utest_tokenizer_loop(&fixture, tk_v, c_debug_flag); + utest_tokenizer_loop(fixture, tk_v, fixture->debug_flag_); - log && fixture.log_memory_layout(&log); + log && fixture->log_memory_layout(&log); } -#endif + + TEST_CASE("SchematikaParser-batch-qdict1", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + // [0] arena; [1] gc + constexpr std::array c_debug_flag_v = {{false, false}}; + test_driver(testname, + &test_batch_qdict1, + c_debug_flag_v); + } + } /*namespace ut*/ } /*namespace xo*/ From 77efd433ad6f64c3e166d289a8df411131b0b1d4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 29 Mar 2026 13:44:19 -0400 Subject: [PATCH 324/342] xo-gc stack: + request-gc-statistics() primitive 1. xo-gc now depends on xo-object2. 2. use genfacet for ICollector_DX1Collector 3. moves xo-gc utest previously in xo-object2 to more natural location in xo-gc/ --- src/reader2/ParserStateMachine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index b7f01f0d..984841b5 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -49,7 +49,10 @@ namespace xo { DGlobalEnv * env = DGlobalEnv::_make(mm, global_symtab); - DSimpleRcx rcx(mm, &stringtable); + // FUDGING this for now + obj err_mm; + + DSimpleRcx rcx(mm, err_mm, &stringtable); InstallSink sink = ([env, rcx, &log] (std::string_view name, From 7e575e6214799cb7e54f57a755979f0b2db9e0a0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 4 Apr 2026 14:38:14 -0400 Subject: [PATCH 325/342] refactor: make AGCObject.shallow_copy() non-const prep for moving to ACollector interface --- include/xo/reader2/DGlobalEnv.hpp | 2 +- include/xo/reader2/env/IGCObject_DGlobalEnv.hpp | 4 ++-- include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp | 4 ++-- src/reader2/DGlobalEnv.cpp | 2 +- src/reader2/facet/IGCObject_DGlobalEnv.cpp | 3 +-- src/reader2/facet/IGCObject_DSchematikaParser.cpp | 3 +-- 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/xo/reader2/DGlobalEnv.hpp b/include/xo/reader2/DGlobalEnv.hpp index da7f8536..fa9d52f8 100644 --- a/include/xo/reader2/DGlobalEnv.hpp +++ b/include/xo/reader2/DGlobalEnv.hpp @@ -71,7 +71,7 @@ namespace xo { ///@{ std::size_t shallow_size() const noexcept; - DGlobalEnv * shallow_copy(obj mm) const noexcept; + DGlobalEnv * shallow_copy(obj mm) noexcept; std::size_t forward_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp index a2fcb5f6..e4ff328a 100644 --- a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp +++ b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp @@ -52,10 +52,10 @@ namespace xo { // const methods /** memory consumption for this instance **/ static size_type shallow_size(const DGlobalEnv & self) noexcept; - /** copy instance using allocator **/ - static Opaque shallow_copy(const DGlobalEnv & self, obj mm) noexcept; // non-const methods + /** copy instance using allocator **/ + static Opaque shallow_copy(DGlobalEnv & self, obj mm) noexcept; /** during GC: forward immdiate children **/ static size_type forward_children(DGlobalEnv & self, obj gc) noexcept; ///@} diff --git a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp index afe0d6b5..5c8e1975 100644 --- a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp +++ b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp @@ -52,10 +52,10 @@ namespace xo { // const methods /** memory consumption for this instance **/ static size_type shallow_size(const DSchematikaParser & self) noexcept; - /** copy instance using allocator **/ - static Opaque shallow_copy(const DSchematikaParser & self, obj mm) noexcept; // non-const methods + /** copy instance using allocator **/ + static Opaque shallow_copy(DSchematikaParser & self, obj mm) noexcept; /** during GC: forward immdiate children **/ static size_type forward_children(DSchematikaParser & self, obj gc) noexcept; ///@} diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp index 386db966..c404d21a 100644 --- a/src/reader2/DGlobalEnv.cpp +++ b/src/reader2/DGlobalEnv.cpp @@ -114,7 +114,7 @@ namespace xo { } DGlobalEnv * - DGlobalEnv::shallow_copy(obj mm) const noexcept + DGlobalEnv::shallow_copy(obj mm) noexcept { return mm.std_copy_for(this); } diff --git a/src/reader2/facet/IGCObject_DGlobalEnv.cpp b/src/reader2/facet/IGCObject_DGlobalEnv.cpp index 76606d6f..9a3e3e45 100644 --- a/src/reader2/facet/IGCObject_DGlobalEnv.cpp +++ b/src/reader2/facet/IGCObject_DGlobalEnv.cpp @@ -22,11 +22,10 @@ namespace xo { } auto - IGCObject_DGlobalEnv::shallow_copy(const DGlobalEnv & self, obj mm) noexcept -> Opaque + IGCObject_DGlobalEnv::shallow_copy(DGlobalEnv & self, obj mm) noexcept -> Opaque { return self.shallow_copy(mm); } - auto IGCObject_DGlobalEnv::forward_children(DGlobalEnv & self, obj gc) noexcept -> size_type { diff --git a/src/reader2/facet/IGCObject_DSchematikaParser.cpp b/src/reader2/facet/IGCObject_DSchematikaParser.cpp index 0ac80e37..582eb902 100644 --- a/src/reader2/facet/IGCObject_DSchematikaParser.cpp +++ b/src/reader2/facet/IGCObject_DSchematikaParser.cpp @@ -22,11 +22,10 @@ namespace xo { } auto - IGCObject_DSchematikaParser::shallow_copy(const DSchematikaParser & self, obj mm) noexcept -> Opaque + IGCObject_DSchematikaParser::shallow_copy(DSchematikaParser & self, obj mm) noexcept -> Opaque { return self.shallow_copy(mm); } - auto IGCObject_DSchematikaParser::forward_children(DSchematikaParser & self, obj gc) noexcept -> size_type { From 73b2561aa8f666703b20e1b2b2c025d2c81c2059 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 4 Apr 2026 15:00:53 -0400 Subject: [PATCH 326/342] refactor: rename GCObject.shallow_copy -> shallow_move resolve conflict since relying on move constructor in std_copy_for --- include/xo/reader2/DGlobalEnv.hpp | 2 +- include/xo/reader2/env/IGCObject_DGlobalEnv.hpp | 4 ++-- include/xo/reader2/env/IGCObject_DSchematikaParser.hpp | 4 ++-- include/xo/reader2/parser/DSchematikaParser.hpp | 4 ++-- include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp | 4 ++-- src/reader2/DGlobalEnv.cpp | 2 +- src/reader2/DSchematikaParser.cpp | 2 +- src/reader2/facet/IGCObject_DGlobalEnv.cpp | 4 ++-- src/reader2/facet/IGCObject_DSchematikaParser.cpp | 4 ++-- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/xo/reader2/DGlobalEnv.hpp b/include/xo/reader2/DGlobalEnv.hpp index fa9d52f8..0c1536ee 100644 --- a/include/xo/reader2/DGlobalEnv.hpp +++ b/include/xo/reader2/DGlobalEnv.hpp @@ -71,7 +71,7 @@ namespace xo { ///@{ std::size_t shallow_size() const noexcept; - DGlobalEnv * shallow_copy(obj mm) noexcept; + DGlobalEnv * shallow_move(obj mm) noexcept; std::size_t forward_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp index e4ff328a..f8ff90b7 100644 --- a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp +++ b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp @@ -54,8 +54,8 @@ namespace xo { static size_type shallow_size(const DGlobalEnv & self) noexcept; // non-const methods - /** copy instance using allocator **/ - static Opaque shallow_copy(DGlobalEnv & self, obj mm) noexcept; + /** move instance using allocator **/ + static Opaque shallow_move(DGlobalEnv & self, obj mm) noexcept; /** during GC: forward immdiate children **/ static size_type forward_children(DGlobalEnv & self, obj gc) noexcept; ///@} diff --git a/include/xo/reader2/env/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/env/IGCObject_DSchematikaParser.hpp index afe0d6b5..03832e87 100644 --- a/include/xo/reader2/env/IGCObject_DSchematikaParser.hpp +++ b/include/xo/reader2/env/IGCObject_DSchematikaParser.hpp @@ -53,7 +53,7 @@ namespace xo { /** memory consumption for this instance **/ static size_type shallow_size(const DSchematikaParser & self) noexcept; /** copy instance using allocator **/ - static Opaque shallow_copy(const DSchematikaParser & self, obj mm) noexcept; + static Opaque shallow_move(const DSchematikaParser & self, obj mm) noexcept; // non-const methods /** during GC: forward immdiate children **/ @@ -64,4 +64,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end */ \ No newline at end of file +/* end */ diff --git a/include/xo/reader2/parser/DSchematikaParser.hpp b/include/xo/reader2/parser/DSchematikaParser.hpp index 18e7989c..da6862ab 100644 --- a/include/xo/reader2/parser/DSchematikaParser.hpp +++ b/include/xo/reader2/parser/DSchematikaParser.hpp @@ -156,7 +156,7 @@ namespace xo { * - SchematikaParser partially supports the gcobject facet so it can be a collector root node. * It's not actually moveable (since its ParserStateMachine member isn't moveable), * Only the forward_children method is load-bearing. - * + * **/ class DSchematikaParser { public: @@ -294,7 +294,7 @@ namespace xo { std::size_t shallow_size() const noexcept; /** not implemented (SchematikaParser not designed to be copyable) **/ - DSchematikaParser * shallow_copy(obj mm) const noexcept; + DSchematikaParser * shallow_move(obj mm) const noexcept; /** forward gc-aware children **/ std::size_t forward_children(obj gc) noexcept; diff --git a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp index 5c8e1975..e6fc39d9 100644 --- a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp +++ b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp @@ -54,8 +54,8 @@ namespace xo { static size_type shallow_size(const DSchematikaParser & self) noexcept; // non-const methods - /** copy instance using allocator **/ - static Opaque shallow_copy(DSchematikaParser & self, obj mm) noexcept; + /** move instance using allocator **/ + static Opaque shallow_move(DSchematikaParser & self, obj mm) noexcept; /** during GC: forward immdiate children **/ static size_type forward_children(DSchematikaParser & self, obj gc) noexcept; ///@} diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp index c404d21a..17a86798 100644 --- a/src/reader2/DGlobalEnv.cpp +++ b/src/reader2/DGlobalEnv.cpp @@ -114,7 +114,7 @@ namespace xo { } DGlobalEnv * - DGlobalEnv::shallow_copy(obj mm) noexcept + DGlobalEnv::shallow_move(obj mm) noexcept { return mm.std_copy_for(this); } diff --git a/src/reader2/DSchematikaParser.cpp b/src/reader2/DSchematikaParser.cpp index a18d9735..f26fe62a 100644 --- a/src/reader2/DSchematikaParser.cpp +++ b/src/reader2/DSchematikaParser.cpp @@ -191,7 +191,7 @@ namespace xo { } DSchematikaParser * - DSchematikaParser::shallow_copy(obj mm) const noexcept + DSchematikaParser::shallow_move(obj mm) const noexcept { (void)mm; diff --git a/src/reader2/facet/IGCObject_DGlobalEnv.cpp b/src/reader2/facet/IGCObject_DGlobalEnv.cpp index 9a3e3e45..f8edbb58 100644 --- a/src/reader2/facet/IGCObject_DGlobalEnv.cpp +++ b/src/reader2/facet/IGCObject_DGlobalEnv.cpp @@ -22,9 +22,9 @@ namespace xo { } auto - IGCObject_DGlobalEnv::shallow_copy(DGlobalEnv & self, obj mm) noexcept -> Opaque + IGCObject_DGlobalEnv::shallow_move(DGlobalEnv & self, obj mm) noexcept -> Opaque { - return self.shallow_copy(mm); + return self.shallow_move(mm); } auto IGCObject_DGlobalEnv::forward_children(DGlobalEnv & self, obj gc) noexcept -> size_type diff --git a/src/reader2/facet/IGCObject_DSchematikaParser.cpp b/src/reader2/facet/IGCObject_DSchematikaParser.cpp index 582eb902..8ba2349c 100644 --- a/src/reader2/facet/IGCObject_DSchematikaParser.cpp +++ b/src/reader2/facet/IGCObject_DSchematikaParser.cpp @@ -22,9 +22,9 @@ namespace xo { } auto - IGCObject_DSchematikaParser::shallow_copy(DSchematikaParser & self, obj mm) noexcept -> Opaque + IGCObject_DSchematikaParser::shallow_move(DSchematikaParser & self, obj mm) noexcept -> Opaque { - return self.shallow_copy(mm); + return self.shallow_move(mm); } auto IGCObject_DSchematikaParser::forward_children(DSchematikaParser & self, obj gc) noexcept -> size_type From 089873302914af2368fddf4836951a6594b9f188 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 4 Apr 2026 16:33:35 -0400 Subject: [PATCH 327/342] refactor: rename shallow_copy -> shallow_move + streamline Use RCollector.std_copy_for where appropriate --- include/xo/reader2/DGlobalEnv.hpp | 2 +- include/xo/reader2/env/IGCObject_DGlobalEnv.hpp | 2 +- include/xo/reader2/parser/DSchematikaParser.hpp | 2 +- include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp | 2 +- src/reader2/DGlobalEnv.cpp | 4 ++-- src/reader2/DSchematikaParser.cpp | 7 +++++-- src/reader2/facet/IGCObject_DGlobalEnv.cpp | 4 ++-- src/reader2/facet/IGCObject_DSchematikaParser.cpp | 4 ++-- 8 files changed, 15 insertions(+), 12 deletions(-) diff --git a/include/xo/reader2/DGlobalEnv.hpp b/include/xo/reader2/DGlobalEnv.hpp index 0c1536ee..96cd5771 100644 --- a/include/xo/reader2/DGlobalEnv.hpp +++ b/include/xo/reader2/DGlobalEnv.hpp @@ -71,7 +71,7 @@ namespace xo { ///@{ std::size_t shallow_size() const noexcept; - DGlobalEnv * shallow_move(obj mm) noexcept; + DGlobalEnv * shallow_move(obj gc) noexcept; std::size_t forward_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp index f8ff90b7..6018a662 100644 --- a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp +++ b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp @@ -55,7 +55,7 @@ namespace xo { // non-const methods /** move instance using allocator **/ - static Opaque shallow_move(DGlobalEnv & self, obj mm) noexcept; + static Opaque shallow_move(DGlobalEnv & self, obj gc) noexcept; /** during GC: forward immdiate children **/ static size_type forward_children(DGlobalEnv & self, obj gc) noexcept; ///@} diff --git a/include/xo/reader2/parser/DSchematikaParser.hpp b/include/xo/reader2/parser/DSchematikaParser.hpp index da6862ab..07c85e4f 100644 --- a/include/xo/reader2/parser/DSchematikaParser.hpp +++ b/include/xo/reader2/parser/DSchematikaParser.hpp @@ -294,7 +294,7 @@ namespace xo { std::size_t shallow_size() const noexcept; /** not implemented (SchematikaParser not designed to be copyable) **/ - DSchematikaParser * shallow_move(obj mm) const noexcept; + DSchematikaParser * shallow_move(obj gc) noexcept; /** forward gc-aware children **/ std::size_t forward_children(obj gc) noexcept; diff --git a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp index e6fc39d9..f743e5cb 100644 --- a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp +++ b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp @@ -55,7 +55,7 @@ namespace xo { // non-const methods /** move instance using allocator **/ - static Opaque shallow_move(DSchematikaParser & self, obj mm) noexcept; + static Opaque shallow_move(DSchematikaParser & self, obj gc) noexcept; /** during GC: forward immdiate children **/ static size_type forward_children(DSchematikaParser & self, obj gc) noexcept; ///@} diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp index 17a86798..243fc8d6 100644 --- a/src/reader2/DGlobalEnv.cpp +++ b/src/reader2/DGlobalEnv.cpp @@ -114,9 +114,9 @@ namespace xo { } DGlobalEnv * - DGlobalEnv::shallow_move(obj mm) noexcept + DGlobalEnv::shallow_move(obj gc) noexcept { - return mm.std_copy_for(this); + return gc.std_copy_for(this); } std::size_t diff --git a/src/reader2/DSchematikaParser.cpp b/src/reader2/DSchematikaParser.cpp index f26fe62a..35edc124 100644 --- a/src/reader2/DSchematikaParser.cpp +++ b/src/reader2/DSchematikaParser.cpp @@ -191,10 +191,13 @@ namespace xo { } DSchematikaParser * - DSchematikaParser::shallow_move(obj mm) const noexcept + DSchematikaParser::shallow_move(obj gc) noexcept { - (void)mm; + (void)gc; + /** TODO: may be feasible to use gc.std_copy_for(this) + * if/when DSchematikaParser is moveable + **/ assert(false); return nullptr; } diff --git a/src/reader2/facet/IGCObject_DGlobalEnv.cpp b/src/reader2/facet/IGCObject_DGlobalEnv.cpp index f8edbb58..b31cadf6 100644 --- a/src/reader2/facet/IGCObject_DGlobalEnv.cpp +++ b/src/reader2/facet/IGCObject_DGlobalEnv.cpp @@ -22,9 +22,9 @@ namespace xo { } auto - IGCObject_DGlobalEnv::shallow_move(DGlobalEnv & self, obj mm) noexcept -> Opaque + IGCObject_DGlobalEnv::shallow_move(DGlobalEnv & self, obj gc) noexcept -> Opaque { - return self.shallow_move(mm); + return self.shallow_move(gc); } auto IGCObject_DGlobalEnv::forward_children(DGlobalEnv & self, obj gc) noexcept -> size_type diff --git a/src/reader2/facet/IGCObject_DSchematikaParser.cpp b/src/reader2/facet/IGCObject_DSchematikaParser.cpp index 8ba2349c..72c9d0e2 100644 --- a/src/reader2/facet/IGCObject_DSchematikaParser.cpp +++ b/src/reader2/facet/IGCObject_DSchematikaParser.cpp @@ -22,9 +22,9 @@ namespace xo { } auto - IGCObject_DSchematikaParser::shallow_move(DSchematikaParser & self, obj mm) noexcept -> Opaque + IGCObject_DSchematikaParser::shallow_move(DSchematikaParser & self, obj gc) noexcept -> Opaque { - return self.shallow_move(mm); + return self.shallow_move(gc); } auto IGCObject_DSchematikaParser::forward_children(DSchematikaParser & self, obj gc) noexcept -> size_type From 63bdd59fc360cfd81952bd03022ed2c5f5532cee Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 4 Apr 2026 16:37:17 -0400 Subject: [PATCH 328/342] refactor: rename RCollector.std_copy_for -> std_move_for --- src/reader2/DGlobalEnv.cpp | 2 +- src/reader2/DSchematikaParser.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp index 243fc8d6..2893beda 100644 --- a/src/reader2/DGlobalEnv.cpp +++ b/src/reader2/DGlobalEnv.cpp @@ -116,7 +116,7 @@ namespace xo { DGlobalEnv * DGlobalEnv::shallow_move(obj gc) noexcept { - return gc.std_copy_for(this); + return gc.std_move_for(this); } std::size_t diff --git a/src/reader2/DSchematikaParser.cpp b/src/reader2/DSchematikaParser.cpp index 35edc124..e25e76aa 100644 --- a/src/reader2/DSchematikaParser.cpp +++ b/src/reader2/DSchematikaParser.cpp @@ -195,7 +195,7 @@ namespace xo { { (void)gc; - /** TODO: may be feasible to use gc.std_copy_for(this) + /** TODO: may be feasible to use gc.std_move_for(this) * if/when DSchematikaParser is moveable **/ assert(false); From 6251b2bde7682b3f1e0f210234e7d9b7f39160f6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 4 Apr 2026 16:54:46 -0400 Subject: [PATCH 329/342] refactor: void return type for Collector.forward_children() --- include/xo/reader2/env/IGCObject_DGlobalEnv.hpp | 2 +- include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp | 2 +- src/reader2/facet/IGCObject_DGlobalEnv.cpp | 4 ++-- src/reader2/facet/IGCObject_DSchematikaParser.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp index 6018a662..e7b65c34 100644 --- a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp +++ b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp @@ -57,7 +57,7 @@ namespace xo { /** move instance using allocator **/ static Opaque shallow_move(DGlobalEnv & self, obj gc) noexcept; /** during GC: forward immdiate children **/ - static size_type forward_children(DGlobalEnv & self, obj gc) noexcept; + static void forward_children(DGlobalEnv & self, obj gc) noexcept; ///@} }; diff --git a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp index f743e5cb..3e382bb0 100644 --- a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp +++ b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp @@ -57,7 +57,7 @@ namespace xo { /** move instance using allocator **/ static Opaque shallow_move(DSchematikaParser & self, obj gc) noexcept; /** during GC: forward immdiate children **/ - static size_type forward_children(DSchematikaParser & self, obj gc) noexcept; + static void forward_children(DSchematikaParser & self, obj gc) noexcept; ///@} }; diff --git a/src/reader2/facet/IGCObject_DGlobalEnv.cpp b/src/reader2/facet/IGCObject_DGlobalEnv.cpp index b31cadf6..19af8f25 100644 --- a/src/reader2/facet/IGCObject_DGlobalEnv.cpp +++ b/src/reader2/facet/IGCObject_DGlobalEnv.cpp @@ -27,9 +27,9 @@ namespace xo { return self.shallow_move(gc); } auto - IGCObject_DGlobalEnv::forward_children(DGlobalEnv & self, obj gc) noexcept -> size_type + IGCObject_DGlobalEnv::forward_children(DGlobalEnv & self, obj gc) noexcept -> void { - return self.forward_children(gc); + self.forward_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/IGCObject_DSchematikaParser.cpp b/src/reader2/facet/IGCObject_DSchematikaParser.cpp index 72c9d0e2..16ce2b5e 100644 --- a/src/reader2/facet/IGCObject_DSchematikaParser.cpp +++ b/src/reader2/facet/IGCObject_DSchematikaParser.cpp @@ -27,9 +27,9 @@ namespace xo { return self.shallow_move(gc); } auto - IGCObject_DSchematikaParser::forward_children(DSchematikaParser & self, obj gc) noexcept -> size_type + IGCObject_DSchematikaParser::forward_children(DSchematikaParser & self, obj gc) noexcept -> void { - return self.forward_children(gc); + self.forward_children(gc); } } /*namespace scm*/ From 1f91e2afdc8eaaf8cc5d1acf494646fb5e2c720f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 4 Apr 2026 17:30:03 -0400 Subject: [PATCH 330/342] refactor: retire GCObject.shallow_size() Not needed. Rely on size stored in gc-owned object header --- include/xo/reader2/env/IGCObject_DGlobalEnv.hpp | 2 -- include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp | 2 -- src/reader2/facet/IGCObject_DGlobalEnv.cpp | 6 ------ src/reader2/facet/IGCObject_DSchematikaParser.cpp | 6 ------ 4 files changed, 16 deletions(-) diff --git a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp index e7b65c34..88bc11b1 100644 --- a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp +++ b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp @@ -50,8 +50,6 @@ namespace xo { /** @defgroup scm-gcobject-dglobalenv-methods **/ ///@{ // const methods - /** memory consumption for this instance **/ - static size_type shallow_size(const DGlobalEnv & self) noexcept; // non-const methods /** move instance using allocator **/ diff --git a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp index 3e382bb0..39f61b9b 100644 --- a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp +++ b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp @@ -50,8 +50,6 @@ namespace xo { /** @defgroup scm-gcobject-dschematikaparser-methods **/ ///@{ // const methods - /** memory consumption for this instance **/ - static size_type shallow_size(const DSchematikaParser & self) noexcept; // non-const methods /** move instance using allocator **/ diff --git a/src/reader2/facet/IGCObject_DGlobalEnv.cpp b/src/reader2/facet/IGCObject_DGlobalEnv.cpp index 19af8f25..5c61e9ea 100644 --- a/src/reader2/facet/IGCObject_DGlobalEnv.cpp +++ b/src/reader2/facet/IGCObject_DGlobalEnv.cpp @@ -15,12 +15,6 @@ namespace xo { namespace scm { - auto - IGCObject_DGlobalEnv::shallow_size(const DGlobalEnv & self) noexcept -> size_type - { - return self.shallow_size(); - } - auto IGCObject_DGlobalEnv::shallow_move(DGlobalEnv & self, obj gc) noexcept -> Opaque { diff --git a/src/reader2/facet/IGCObject_DSchematikaParser.cpp b/src/reader2/facet/IGCObject_DSchematikaParser.cpp index 16ce2b5e..133b3f9c 100644 --- a/src/reader2/facet/IGCObject_DSchematikaParser.cpp +++ b/src/reader2/facet/IGCObject_DSchematikaParser.cpp @@ -15,12 +15,6 @@ namespace xo { namespace scm { - auto - IGCObject_DSchematikaParser::shallow_size(const DSchematikaParser & self) noexcept -> size_type - { - return self.shallow_size(); - } - auto IGCObject_DSchematikaParser::shallow_move(DSchematikaParser & self, obj gc) noexcept -> Opaque { From bf8c3628ff21f9132d20ca447b7010e2ec8461c3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 4 Apr 2026 18:01:25 -0400 Subject: [PATCH 331/342] refactor: retire GCObject.shallow_copy() Collector gets this info from gc-owned object header --- include/xo/reader2/ParserStateMachine.hpp | 9 --------- src/reader2/ParserStateMachine.cpp | 13 +++---------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index f5001faa..cc313660 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -351,15 +351,6 @@ namespace xo { /** @defgroup scm-parserstatemachine-gcobject-facet gc support **/ ///@{ -#ifdef OBSOLETE - std::size_t shallow_size() const noexcept; - /** NOTE: - * ParserStateMachine only eligible to be a GC root. - * It's not eligible to reside in gc-owned space - **/ - ParserStateMachine * shallow_copy(obj mm) const noexcept; - std::size_t forward_children(obj gc) noexcept; -#endif /** update gc-aware exit pointers from this ParserStateMachine **/ void forward_children(obj gc) noexcept; diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 984841b5..c3d92a0c 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -897,19 +897,12 @@ namespace xo { // ----- gc support ----- #ifdef OBSOLETE - std::size_t - ParserStateMachine::shallow_size() const noexcept + void + ParserStateMachine::shallow_copy(obj gc) noexcept { - return sizeof(ParserStateMachine); - } - - ParserStateMachine * - ParserStateMachine::shallow_copy(obj mm) const noexcept - { - (void)mm; + (void)gc; assert(false); - return nullptr; } #endif From d740c944062309b56ace7b7412311f8e6c7b6bfd Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 5 Apr 2026 23:53:02 -0400 Subject: [PATCH 332/342] refactor: + narrower interface for gc pointer forwarding add AGCObjectVisitor, instead of requiring ACollector. --- idl/SyntaxStateMachine.json5 | 10 +-- include/xo/reader2/DDefineSsm.hpp | 4 +- include/xo/reader2/DExpectExprSsm.hpp | 5 +- .../xo/reader2/DExpectFormalArglistSsm.hpp | 4 +- include/xo/reader2/DExpectQArraySsm.hpp | 5 +- include/xo/reader2/DExpectQListSsm.hpp | 4 +- include/xo/reader2/DExpectQLiteralSsm.hpp | 4 +- include/xo/reader2/DExpectSymbolSsm.hpp | 4 +- include/xo/reader2/DExpectTypeSsm.hpp | 4 +- include/xo/reader2/DGlobalEnv.hpp | 7 +- include/xo/reader2/DProgressSsm.hpp | 5 +- include/xo/reader2/DQuoteSsm.hpp | 4 +- include/xo/reader2/DSequenceSsm.hpp | 4 +- include/xo/reader2/DToplevelSeqSsm.hpp | 4 +- include/xo/reader2/ParserResult.hpp | 4 +- include/xo/reader2/ParserStack.hpp | 6 +- include/xo/reader2/ParserStateMachine.hpp | 4 +- include/xo/reader2/QuoteSsm.hpp | 4 +- include/xo/reader2/SchematikaReader.hpp | 7 +- include/xo/reader2/apply/DApplySsm.hpp | 4 +- .../apply/ISyntaxStateMachine_DApplySsm.hpp | 6 +- .../define/ISyntaxStateMachine_DDefineSsm.hpp | 6 +- include/xo/reader2/deftype/DDeftypeSsm.hpp | 4 +- .../ISyntaxStateMachine_DDeftypeSsm.hpp | 6 +- .../xo/reader2/env/IGCObject_DGlobalEnv.hpp | 7 +- .../expect_formal_arg/DExpectFormalArgSsm.hpp | 4 +- ...SyntaxStateMachine_DExpectFormalArgSsm.hpp | 6 +- .../expect_listtype/DExpectListTypeSsm.hpp | 4 +- ...ISyntaxStateMachine_DExpectListTypeSsm.hpp | 6 +- .../reader2/expect_qdict/DExpectQDictSsm.hpp | 4 +- .../ISyntaxStateMachine_DExpectQDictSsm.hpp | 6 +- include/xo/reader2/ifelse/DIfElseSsm.hpp | 4 +- .../ifelse/ISyntaxStateMachine_DIfElseSsm.hpp | 6 +- include/xo/reader2/lambda/DLambdaSsm.hpp | 4 +- .../lambda/ISyntaxStateMachine_DLambdaSsm.hpp | 6 +- include/xo/reader2/paren/DParenSsm.hpp | 4 +- .../paren/ISyntaxStateMachine_DParenSsm.hpp | 6 +- .../xo/reader2/parser/DSchematikaParser.hpp | 7 +- .../parser/IGCObject_DSchematikaParser.hpp | 7 +- .../quote/ISyntaxStateMachine_DQuoteSsm.hpp | 6 +- .../xo/reader2/ssm/ASyntaxStateMachine.hpp | 10 +-- .../xo/reader2/ssm/IPrintable_DQuoteSsm.hpp | 62 ------------- .../reader2/ssm/ISyntaxStateMachine_Any.hpp | 4 +- .../ISyntaxStateMachine_DExpectExprSsm.hpp | 6 +- ...axStateMachine_DExpectFormalArglistSsm.hpp | 6 +- .../ISyntaxStateMachine_DExpectQArraySsm.hpp | 6 +- .../ISyntaxStateMachine_DExpectQListSsm.hpp | 6 +- ...ISyntaxStateMachine_DExpectQLiteralSsm.hpp | 6 +- .../ISyntaxStateMachine_DExpectSymbolSsm.hpp | 6 +- .../ISyntaxStateMachine_DExpectTypeSsm.hpp | 6 +- .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 6 +- .../ssm/ISyntaxStateMachine_DQuoteSsm.hpp | 87 ------------------- .../ssm/ISyntaxStateMachine_DSequenceSsm.hpp | 6 +- .../ISyntaxStateMachine_DToplevelSeqSsm.hpp | 6 +- .../reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 8 +- .../xo/reader2/ssm/RSyntaxStateMachine.hpp | 6 +- src/reader2/DApplySsm.cpp | 6 +- src/reader2/DDefineSsm.cpp | 4 +- src/reader2/DDeftypeSsm.cpp | 2 +- src/reader2/DExpectExprSsm.cpp | 2 +- src/reader2/DExpectFormalArgSsm.cpp | 2 +- src/reader2/DExpectFormalArglistSsm.cpp | 4 +- src/reader2/DExpectListTypeSsm.cpp | 4 +- src/reader2/DExpectQArraySsm.cpp | 4 +- src/reader2/DExpectQDictSsm.cpp | 6 +- src/reader2/DExpectQListSsm.cpp | 6 +- src/reader2/DExpectQLiteralSsm.cpp | 2 +- src/reader2/DExpectSymbolSsm.cpp | 2 +- src/reader2/DExpectTypeSsm.cpp | 2 +- src/reader2/DGlobalEnv.cpp | 16 +--- src/reader2/DIfElseSsm.cpp | 4 +- src/reader2/DLambdaSsm.cpp | 11 +-- src/reader2/DParenSsm.cpp | 4 +- src/reader2/DProgressSsm.cpp | 6 +- src/reader2/DQuoteSsm.cpp | 4 +- src/reader2/DSchematikaParser.cpp | 14 +-- src/reader2/DSequenceSsm.cpp | 4 +- src/reader2/DToplevelSeqSsm.cpp | 2 +- src/reader2/ISyntaxStateMachine_Any.cpp | 2 +- .../ISyntaxStateMachine_DExpectExprSsm.cpp | 4 +- ...axStateMachine_DExpectFormalArglistSsm.cpp | 4 +- .../ISyntaxStateMachine_DExpectQArraySsm.cpp | 4 +- .../ISyntaxStateMachine_DExpectQListSsm.cpp | 4 +- ...ISyntaxStateMachine_DExpectQLiteralSsm.cpp | 4 +- .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 4 +- .../ISyntaxStateMachine_DExpectTypeSsm.cpp | 4 +- src/reader2/ISyntaxStateMachine_DParenSsm.cpp | 4 +- .../ISyntaxStateMachine_DProgressSsm.cpp | 4 +- .../ISyntaxStateMachine_DSequenceSsm.cpp | 4 +- .../ISyntaxStateMachine_DToplevelSeqSsm.cpp | 4 +- src/reader2/ParserResult.cpp | 6 +- src/reader2/ParserStack.cpp | 4 +- src/reader2/ParserStateMachine.cpp | 12 +-- src/reader2/SchematikaReader.cpp | 10 +-- src/reader2/facet/IGCObject_DGlobalEnv.cpp | 4 +- .../facet/IGCObject_DSchematikaParser.cpp | 4 +- .../facet/ISyntaxStateMachine_DApplySsm.cpp | 4 +- .../facet/ISyntaxStateMachine_DDefineSsm.cpp | 4 +- .../facet/ISyntaxStateMachine_DDeftypeSsm.cpp | 4 +- ...SyntaxStateMachine_DExpectFormalArgSsm.cpp | 4 +- ...ISyntaxStateMachine_DExpectListTypeSsm.cpp | 4 +- .../ISyntaxStateMachine_DExpectQDictSsm.cpp | 4 +- .../facet/ISyntaxStateMachine_DIfElseSsm.cpp | 4 +- .../facet/ISyntaxStateMachine_DLambdaSsm.cpp | 4 +- .../facet/ISyntaxStateMachine_DQuoteSsm.cpp | 4 +- 105 files changed, 260 insertions(+), 416 deletions(-) delete mode 100644 include/xo/reader2/ssm/IPrintable_DQuoteSsm.hpp delete mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 8450b02b..d47656b7 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -10,7 +10,7 @@ "", "", "", - "" + "" ], // extra includes in SyntaxStateMachine.hpp, if any user_hpp_includes: [], @@ -27,7 +27,7 @@ ], types: [ { name: "TypeDescr", doc: [ "reflected c++ type" ], definition: "xo::reflect::TypeDescr" }, - { name: "ACollector", doc: [ "gc interface" ], definition: "xo::mm::ACollector" }, + { name: "AGCObjectVisitor", doc: [ "gc visitor interface" ], definition: "xo::mm::AGCObjectVisitor" }, { name: "AGCObject", doc: [ "gc-aware object" ], definition: "xo::mm::AGCObject" }, // { name: string, doc: [ string ], definition: string }, ], @@ -147,11 +147,11 @@ ], }, { - name: "forward_children", - doc: ["gc support: move immediate children to to-space and sub forwarding pointer"], + name: "visit_gco_children", + doc: ["gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each"], return_type: "void", args: [ - {type: "obj", name: "gc"}, + {type: "obj", name: "gc"}, ], } ], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index e372e299..e31c3b2a 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -73,7 +73,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -200,7 +200,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc); + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index a1ba1c69..e73e1f16 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -6,7 +6,6 @@ #pragma once #include "DSyntaxStateMachine.hpp" -//#include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" #include #include @@ -18,7 +17,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -195,7 +194,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index f28cbac1..954cdc72 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -55,7 +55,7 @@ namespace xo { class DExpectFormalArglistSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -130,7 +130,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectQArraySsm.hpp b/include/xo/reader2/DExpectQArraySsm.hpp index 068a5b93..2ec32eb4 100644 --- a/include/xo/reader2/DExpectQArraySsm.hpp +++ b/include/xo/reader2/DExpectQArraySsm.hpp @@ -7,7 +7,6 @@ #include "DSyntaxStateMachine.hpp" #include -//#include #include namespace xo { @@ -58,7 +57,7 @@ namespace xo { class DExpectQArraySsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -124,7 +123,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectQListSsm.hpp b/include/xo/reader2/DExpectQListSsm.hpp index c2119c8b..3b9ab53d 100644 --- a/include/xo/reader2/DExpectQListSsm.hpp +++ b/include/xo/reader2/DExpectQListSsm.hpp @@ -58,7 +58,7 @@ namespace xo { class DExpectQListSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -124,7 +124,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectQLiteralSsm.hpp b/include/xo/reader2/DExpectQLiteralSsm.hpp index f037c7d8..2538fb6f 100644 --- a/include/xo/reader2/DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/DExpectQLiteralSsm.hpp @@ -15,7 +15,7 @@ namespace xo { class DExpectQLiteralSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -129,7 +129,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index 9ca3e1a0..f4c3c156 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -21,7 +21,7 @@ namespace xo { class DExpectSymbolSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; using ppindentinfo = xo::print::ppindentinfo; @@ -80,7 +80,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} }; diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index 7fae992d..d405e916 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -28,7 +28,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -87,7 +87,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DGlobalEnv.hpp b/include/xo/reader2/DGlobalEnv.hpp index 96cd5771..04605c4c 100644 --- a/include/xo/reader2/DGlobalEnv.hpp +++ b/include/xo/reader2/DGlobalEnv.hpp @@ -7,6 +7,7 @@ #include #include +#include namespace xo { namespace scm { @@ -27,8 +28,9 @@ namespace xo { public: using TypeDescr = xo::reflect::TypeDescr; using ACollector = xo::mm::ACollector; - using AAllocator = xo::mm::AAllocator; using AGCObject = xo::mm::AGCObject; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using AAllocator = xo::mm::AAllocator; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using ppindentinfo = xo::print::ppindentinfo; using size_type = std::uint32_t; @@ -70,9 +72,8 @@ namespace xo { /** @defgroup scm-globalenv-gcobject-facet **/ ///@{ - std::size_t shallow_size() const noexcept; DGlobalEnv * shallow_move(obj gc) noexcept; - std::size_t forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} /** @defgroup scm-globalenv-printable-facet **/ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 487ba141..372b3af6 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -7,7 +7,6 @@ #include "DSyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" -//#include #include #ifdef NOT_YET @@ -90,7 +89,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -218,7 +217,7 @@ namespace xo { /** @defgroup scm-progressssm-gc-support gc support methods **/ ///@{ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DQuoteSsm.hpp b/include/xo/reader2/DQuoteSsm.hpp index fa598f83..542342ef 100644 --- a/include/xo/reader2/DQuoteSsm.hpp +++ b/include/xo/reader2/DQuoteSsm.hpp @@ -65,7 +65,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -150,7 +150,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} private: diff --git a/include/xo/reader2/DSequenceSsm.hpp b/include/xo/reader2/DSequenceSsm.hpp index e3c699c3..a7819048 100644 --- a/include/xo/reader2/DSequenceSsm.hpp +++ b/include/xo/reader2/DSequenceSsm.hpp @@ -29,7 +29,7 @@ namespace xo { class DSequenceSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -97,7 +97,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DToplevelSeqSsm.hpp b/include/xo/reader2/DToplevelSeqSsm.hpp index b33707e4..4103f45a 100644 --- a/include/xo/reader2/DToplevelSeqSsm.hpp +++ b/include/xo/reader2/DToplevelSeqSsm.hpp @@ -40,7 +40,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -161,7 +161,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/ParserResult.hpp b/include/xo/reader2/ParserResult.hpp index 73ab38c6..823372da 100644 --- a/include/xo/reader2/ParserResult.hpp +++ b/include/xo/reader2/ParserResult.hpp @@ -32,7 +32,7 @@ namespace xo { class ParserResult { public: - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using ppindentinfo = xo::print::ppindentinfo; public: @@ -69,7 +69,7 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; /** gc support: forward gc-eligible children **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; public: /** none|expression|error_description diff --git a/include/xo/reader2/ParserStack.hpp b/include/xo/reader2/ParserStack.hpp index 80049a07..e4b414b4 100644 --- a/include/xo/reader2/ParserStack.hpp +++ b/include/xo/reader2/ParserStack.hpp @@ -6,6 +6,7 @@ #pragma once #include "SyntaxStateMachine.hpp" +#include #include #include #include @@ -21,7 +22,8 @@ namespace xo { **/ class ParserStack { public: - using ACollector = xo::mm::ACollector; + //using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -54,7 +56,7 @@ namespace xo { /** pretty-printer support **/ bool pretty(const ppindentinfo & ppii) const; - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; private: /** stack pointer: top of stack just before this instance created **/ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index cc313660..fedd574d 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ namespace xo { public: using TypeDescr = xo::reflect::TypeDescr; using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using ArenaConfig = xo::mm::ArenaConfig; using AGCObject = xo::mm::AGCObject; @@ -352,7 +354,7 @@ namespace xo { ///@{ /** update gc-aware exit pointers from this ParserStateMachine **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/QuoteSsm.hpp b/include/xo/reader2/QuoteSsm.hpp index c0fb5429..801179e9 100644 --- a/include/xo/reader2/QuoteSsm.hpp +++ b/include/xo/reader2/QuoteSsm.hpp @@ -6,7 +6,7 @@ #pragma once #include "DQuoteSsm.hpp" -#include "ssm/ISyntaxStateMachine_DQuoteSsm.hpp" -#include "ssm/IPrintable_DQuoteSsm.hpp" +#include "quote/ISyntaxStateMachine_DQuoteSsm.hpp" +#include "quote/IPrintable_DQuoteSsm.hpp" /* end QuoteSsm.hpp */ diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index de3da42f..d70c2c04 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -8,17 +8,19 @@ #include "ReaderConfig.hpp" #include "SchematikaParser.hpp" #include +#include namespace xo { namespace scm { struct ReaderResult { using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using span_type = xo::mm::span; bool is_tk_error() const { return tk_error_.is_error(); } /** forward gc-aware pointers (called during gc cycle) **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; /** schematika expression parsed from input **/ obj expr_; @@ -40,6 +42,7 @@ namespace xo { class SchematikaReader { public: using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using span_type = xo::mm::span; @@ -107,7 +110,7 @@ namespace xo { void reset_to_idle_toplevel(); /** update gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; private: /** tokenizer converts a stream of chars diff --git a/include/xo/reader2/apply/DApplySsm.hpp b/include/xo/reader2/apply/DApplySsm.hpp index 64513f0c..f7ee1cce 100644 --- a/include/xo/reader2/apply/DApplySsm.hpp +++ b/include/xo/reader2/apply/DApplySsm.hpp @@ -65,7 +65,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -190,7 +190,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp b/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp index 04c7bddb..db3a147d 100644 --- a/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp +++ b/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dapplyssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DApplySsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DApplySsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DApplySsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DApplySsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp index 3487a328..d5338cd5 100644 --- a/include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-ddefinessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DDefineSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DDefineSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DDefineSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DDefineSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/deftype/DDeftypeSsm.hpp b/include/xo/reader2/deftype/DDeftypeSsm.hpp index a3e4c6cb..b1a6d910 100644 --- a/include/xo/reader2/deftype/DDeftypeSsm.hpp +++ b/include/xo/reader2/deftype/DDeftypeSsm.hpp @@ -66,7 +66,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -172,7 +172,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp b/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp index f3776f18..9bfdfba5 100644 --- a/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp +++ b/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-ddeftypessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DDeftypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DDeftypeSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DDeftypeSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DDeftypeSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp index 88bc11b1..8e97a792 100644 --- a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp +++ b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp @@ -44,6 +44,7 @@ namespace xo { using size_type = xo::mm::AGCObject::size_type; using AAllocator = xo::mm::AGCObject::AAllocator; using ACollector = xo::mm::AGCObject::ACollector; + using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; using Copaque = xo::mm::AGCObject::Copaque; using Opaque = xo::mm::AGCObject::Opaque; ///@} @@ -54,8 +55,10 @@ namespace xo { // non-const methods /** move instance using allocator **/ static Opaque shallow_move(DGlobalEnv & self, obj gc) noexcept; - /** during GC: forward immdiate children **/ - static void forward_children(DGlobalEnv & self, obj gc) noexcept; + /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. +Context: provides address of data pointer so it can be updated in place +when @p fn invokes garbage collector reentry point **/ + static void visit_gco_children(DGlobalEnv & self, obj fn) noexcept; ///@} }; diff --git a/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp b/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp index 318e340a..5c7e6dec 100644 --- a/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp @@ -48,7 +48,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -126,7 +126,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp index 7e100e40..a880fad3 100644 --- a/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectformalargssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectFormalArgSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectFormalArgSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DExpectFormalArgSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DExpectFormalArgSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp b/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp index 6e7c80b4..eeadd15c 100644 --- a/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp +++ b/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp @@ -62,7 +62,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -135,7 +135,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} private: diff --git a/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp b/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp index 153c47a4..9ed4214c 100644 --- a/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp +++ b/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectlisttypessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectListTypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectListTypeSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DExpectListTypeSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DExpectListTypeSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp index 31aa2be3..5ed40fab 100644 --- a/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp +++ b/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp @@ -63,7 +63,7 @@ namespace xo { class DExpectQDictSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -159,7 +159,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp index 7014238f..c629e07b 100644 --- a/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp +++ b/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectqdictssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectQDictSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQDictSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DExpectQDictSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DExpectQDictSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ifelse/DIfElseSsm.hpp b/include/xo/reader2/ifelse/DIfElseSsm.hpp index 27043bdf..fd7b8168 100644 --- a/include/xo/reader2/ifelse/DIfElseSsm.hpp +++ b/include/xo/reader2/ifelse/DIfElseSsm.hpp @@ -55,7 +55,7 @@ namespace xo { class DIfElseSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -171,7 +171,7 @@ namespace xo { /** @defgroup scm-ifelsessm-gc-support gc support methods **/ ///@{ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp index 8a3991fb..17f6b4cd 100644 --- a/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp +++ b/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-difelsessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DIfElseSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DIfElseSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DIfElseSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DIfElseSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/lambda/DLambdaSsm.hpp b/include/xo/reader2/lambda/DLambdaSsm.hpp index 1fa1eac9..7b16503b 100644 --- a/include/xo/reader2/lambda/DLambdaSsm.hpp +++ b/include/xo/reader2/lambda/DLambdaSsm.hpp @@ -59,7 +59,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using DLocalSymtab = xo::scm::DLocalSymtab; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -189,7 +189,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp index f10f376e..db67ee9a 100644 --- a/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp +++ b/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dlambdassm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DLambdaSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DLambdaSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DLambdaSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DLambdaSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/paren/DParenSsm.hpp b/include/xo/reader2/paren/DParenSsm.hpp index af9daa91..e70ba255 100644 --- a/include/xo/reader2/paren/DParenSsm.hpp +++ b/include/xo/reader2/paren/DParenSsm.hpp @@ -50,7 +50,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -136,7 +136,7 @@ namespace xo { ///@{ /** gc support: visit immediate gc-aware children **/ - void forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp b/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp index c2bbcc21..4dd7ef74 100644 --- a/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp +++ b/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dparenssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DParenSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DParenSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DParenSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DParenSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/parser/DSchematikaParser.hpp b/include/xo/reader2/parser/DSchematikaParser.hpp index 07c85e4f..c3de4930 100644 --- a/include/xo/reader2/parser/DSchematikaParser.hpp +++ b/include/xo/reader2/parser/DSchematikaParser.hpp @@ -10,6 +10,7 @@ #include "ParserResult.hpp" #include #include +#include namespace xo { namespace scm { @@ -164,8 +165,9 @@ namespace xo { using ArenaHashMapConfig = xo::map::ArenaHashMapConfig; using ArenaConfig = xo::mm::ArenaConfig; using ACollector = xo::mm::ACollector; - using AAllocator = xo::mm::AAllocator; using AGCObject = xo::mm::AGCObject; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using AAllocator = xo::mm::AAllocator; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using ppindentinfo = xo::print::ppindentinfo; using size_type = std::size_t; @@ -292,11 +294,10 @@ namespace xo { /** @defgroup scm-schematikaparser-gcobject-methods **/ ///@{ - std::size_t shallow_size() const noexcept; /** not implemented (SchematikaParser not designed to be copyable) **/ DSchematikaParser * shallow_move(obj gc) noexcept; /** forward gc-aware children **/ - std::size_t forward_children(obj gc) noexcept; + void visit_gco_children(obj gc) noexcept; ///@} private: diff --git a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp index 39f61b9b..f2ca67de 100644 --- a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp +++ b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp @@ -44,6 +44,7 @@ namespace xo { using size_type = xo::mm::AGCObject::size_type; using AAllocator = xo::mm::AGCObject::AAllocator; using ACollector = xo::mm::AGCObject::ACollector; + using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; using Copaque = xo::mm::AGCObject::Copaque; using Opaque = xo::mm::AGCObject::Opaque; ///@} @@ -54,8 +55,10 @@ namespace xo { // non-const methods /** move instance using allocator **/ static Opaque shallow_move(DSchematikaParser & self, obj gc) noexcept; - /** during GC: forward immdiate children **/ - static void forward_children(DSchematikaParser & self, obj gc) noexcept; + /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. +Context: provides address of data pointer so it can be updated in place +when @p fn invokes garbage collector reentry point **/ + static void visit_gco_children(DSchematikaParser & self, obj fn) noexcept; ///@} }; diff --git a/include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp b/include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp index 811119c5..35dc5da1 100644 --- a/include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp +++ b/include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dquotessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DQuoteSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DQuoteSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DQuoteSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DQuoteSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index ead25e24..07d992c1 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -46,8 +46,8 @@ public: using Opaque = void *; /** reflected c++ type **/ using TypeDescr = xo::reflect::TypeDescr; - /** gc interface **/ - using ACollector = xo::mm::ACollector; + /** gc visitor interface **/ + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; /** gc-aware object **/ using AGCObject = xo::mm::AGCObject; ///@} @@ -90,8 +90,8 @@ public: virtual void on_parsed_expression_with_token(Opaque data, obj expr, const Token & tk, ParserStateMachine * p_psm) = 0; /** update state machine for nested quoted literal @p lit **/ virtual void on_quoted_literal(Opaque data, obj lit, ParserStateMachine * p_psm) = 0; - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - virtual void forward_children(Opaque data, obj gc) = 0; + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + virtual void visit_gco_children(Opaque data, obj gc) = 0; ///@} }; /*ASyntaxStateMachine*/ diff --git a/include/xo/reader2/ssm/IPrintable_DQuoteSsm.hpp b/include/xo/reader2/ssm/IPrintable_DQuoteSsm.hpp deleted file mode 100644 index 2b969c50..00000000 --- a/include/xo/reader2/ssm/IPrintable_DQuoteSsm.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/** @file IPrintable_DQuoteSsm.hpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/IPrintable_DQuoteSsm.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_repr.hpp.j2] - * 3. idl for facet methods - * [idl/IPrintable_DQuoteSsm.json5] - **/ - -#pragma once - -#include "Printable.hpp" -#include -#include -#include "DQuoteSsm.hpp" - -namespace xo { namespace scm { class IPrintable_DQuoteSsm; } } - -namespace xo { - namespace facet { - template <> - struct FacetImplementation - { - using ImplType = xo::print::IPrintable_Xfer - ; - }; - } -} - -namespace xo { - namespace scm { - /** @class IPrintable_DQuoteSsm - **/ - class IPrintable_DQuoteSsm { - public: - /** @defgroup scm-printable-dquotessm-type-traits **/ - ///@{ - using ppindentinfo = xo::print::APrintable::ppindentinfo; - using Copaque = xo::print::APrintable::Copaque; - using Opaque = xo::print::APrintable::Opaque; - ///@} - /** @defgroup scm-printable-dquotessm-methods **/ - ///@{ - // const methods - /** Pretty-printing support for this object. -See [xo-indentlog/xo/indentlog/pretty.hpp] **/ - static bool pretty(const DQuoteSsm & self, const ppindentinfo & ppii); - - // non-const methods - ///@} - }; - - } /*namespace scm*/ -} /*namespace xo*/ - -/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index d1077f2a..34e7ec84 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -45,7 +45,7 @@ namespace scm { /** integer identifying a type **/ using typeseq = xo::facet::typeseq; using TypeDescr = ASyntaxStateMachine::TypeDescr; - using ACollector = ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = ASyntaxStateMachine::AGCObject; ///@} @@ -75,7 +75,7 @@ namespace scm { [[noreturn]] void on_parsed_expression(Opaque, obj, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression_with_token(Opaque, obj, const Token &, ParserStateMachine *) override; [[noreturn]] void on_quoted_literal(Opaque, obj, ParserStateMachine *) override; - [[noreturn]] void forward_children(Opaque, obj) override; + [[noreturn]] void visit_gco_children(Opaque, obj) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 79801c00..5ca9f1c0 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectexprssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectExprSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectExprSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DExpectExprSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DExpectExprSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp index 68151e22..04da69bd 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectformalarglistssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectFormalArglistSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectFormalArglistSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DExpectFormalArglistSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DExpectFormalArglistSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp index cf6ae53d..7b345008 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectqarrayssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectQArraySsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQArraySsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DExpectQArraySsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DExpectQArraySsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp index 38a33d20..ea0cb3c2 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectqlistssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectQListSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQListSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DExpectQListSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DExpectQListSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp index 4cd123f7..4a4bdbfb 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectqliteralssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectQLiteralSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQLiteralSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DExpectQLiteralSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DExpectQLiteralSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index 0ed37f25..e3cf7146 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpectsymbolssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectSymbolSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectSymbolSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DExpectSymbolSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DExpectSymbolSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index ea084f51..965212d1 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dexpecttypessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DExpectTypeSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectTypeSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DExpectTypeSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DExpectTypeSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 24269888..7c12ee39 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dprogressssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DProgressSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DProgressSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DProgressSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DProgressSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp deleted file mode 100644 index 811119c5..00000000 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DQuoteSsm.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/** @file ISyntaxStateMachine_DQuoteSsm.hpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/ISyntaxStateMachine_DQuoteSsm.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_repr.hpp.j2] - * 3. idl for facet methods - * [idl/ISyntaxStateMachine_DQuoteSsm.json5] - **/ - -#pragma once - -#include "SyntaxStateMachine.hpp" -#include "SyntaxStateMachine.hpp" -#include "ssm/ISyntaxStateMachine_Xfer.hpp" -#include "DQuoteSsm.hpp" - -namespace xo { namespace scm { class ISyntaxStateMachine_DQuoteSsm; } } - -namespace xo { - namespace facet { - template <> - struct FacetImplementation - { - using ImplType = xo::scm::ISyntaxStateMachine_Xfer - ; - }; - } -} - -namespace xo { - namespace scm { - /** @class ISyntaxStateMachine_DQuoteSsm - **/ - class ISyntaxStateMachine_DQuoteSsm { - public: - /** @defgroup scm-syntaxstatemachine-dquotessm-type-traits **/ - ///@{ - using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; - using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; - using Copaque = xo::scm::ASyntaxStateMachine::Copaque; - using Opaque = xo::scm::ASyntaxStateMachine::Opaque; - ///@} - /** @defgroup scm-syntaxstatemachine-dquotessm-methods **/ - ///@{ - // const methods - /** identify a type of syntax state machine **/ - static syntaxstatetype ssm_type(const DQuoteSsm & self) noexcept; - /** text describing expected/allowed input to this ssm in current state **/ - static std::string_view get_expect_str(const DQuoteSsm & self) noexcept; - - // non-const methods - /** operate state machine for incoming token @p tk **/ - static void on_token(DQuoteSsm & self, const Token & tk, ParserStateMachine * p_psm); - /** update stat machine for incoming parsed symbol @p sym **/ - static void on_parsed_symbol(DQuoteSsm & self, std::string_view sym, ParserStateMachine * p_psm); - /** operate state machine for incoming type description @p td **/ - static void on_parsed_typedescr(DQuoteSsm & self, TypeDescr td, ParserStateMachine * p_psm); - /** update state machine for type emitted by nested ssm **/ - static void on_parsed_type(DQuoteSsm & self, obj type, ParserStateMachine * p_psm); - /** operate state machine for formal emitted by nested ssm **/ - static void on_parsed_formal(DQuoteSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); - /** operate state machine for formal emitted by nested ssm **/ - static void on_parsed_formal_with_token(DQuoteSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); - /** consume formal arglist emitted by nested ssm **/ - static void on_parsed_formal_arglist(DQuoteSsm & self, DArray * arglist, ParserStateMachine * p_psm); - /** update state machine for nested parsed expression @p expr **/ - static void on_parsed_expression(DQuoteSsm & self, obj expr, ParserStateMachine * p_psm); - /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ - static void on_parsed_expression_with_token(DQuoteSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); - /** update state machine for nested quoted literal @p lit **/ - static void on_quoted_literal(DQuoteSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DQuoteSsm & self, obj gc); - ///@} - }; - - } /*namespace scm*/ -} /*namespace xo*/ - -/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp index f19601b5..b35d45a1 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dsequencessm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DSequenceSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DSequenceSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DSequenceSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DSequenceSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp index b36cbfc6..695da17c 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp @@ -42,7 +42,7 @@ namespace xo { /** @defgroup scm-syntaxstatemachine-dtoplevelseqssm-type-traits **/ ///@{ using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; - using ACollector = xo::scm::ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; @@ -76,8 +76,8 @@ namespace xo { static void on_parsed_expression_with_token(DToplevelSeqSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DToplevelSeqSsm & self, obj lit, ParserStateMachine * p_psm); - /** gc support: move immediate children to to-space and sub forwarding pointer **/ - static void forward_children(DToplevelSeqSsm & self, obj gc); + /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ + static void visit_gco_children(DToplevelSeqSsm & self, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 13b6d1b7..df1a87f4 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include namespace xo { namespace scm { @@ -34,7 +34,7 @@ namespace scm { /** integer identifying a type **/ using typeseq = ASyntaxStateMachine::typeseq; using TypeDescr = ASyntaxStateMachine::TypeDescr; - using ACollector = ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = ASyntaxStateMachine::AGCObject; ///@} @@ -89,8 +89,8 @@ namespace scm { void on_quoted_literal(Opaque data, obj lit, ParserStateMachine * p_psm) override { return I::on_quoted_literal(_dcast(data), lit, p_psm); } - void forward_children(Opaque data, obj gc) override { - return I::forward_children(_dcast(data), gc); + void visit_gco_children(Opaque data, obj gc) override { + return I::visit_gco_children(_dcast(data), gc); } ///@} diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 57cc885e..9c8a8274 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -32,7 +32,7 @@ public: using DataPtr = Object::DataPtr; using typeseq = xo::reflect::typeseq; using TypeDescr = ASyntaxStateMachine::TypeDescr; - using ACollector = ASyntaxStateMachine::ACollector; + using AGCObjectVisitor = ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = ASyntaxStateMachine::AGCObject; ///@} @@ -93,8 +93,8 @@ public: void on_quoted_literal(obj lit, ParserStateMachine * p_psm) { return O::iface()->on_quoted_literal(O::data(), lit, p_psm); } - void forward_children(obj gc) { - return O::iface()->forward_children(O::data(), gc); + void visit_gco_children(obj gc) { + return O::iface()->visit_gco_children(O::data(), gc); } ///@} diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index c465ce1a..1787d560 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -397,10 +397,10 @@ namespace xo { } void - DApplySsm::forward_children(obj gc) noexcept + DApplySsm::visit_gco_children(obj gc) noexcept { - gc.forward_pivot_inplace(&fn_expr_); - gc.forward_inplace(&args_expr_v_); + gc.visit_poly_child(&fn_expr_); + gc.visit_child(&args_expr_v_); } } /*namespace scm*/ diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index f9be0335..1ee8e3aa 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -692,9 +692,9 @@ namespace xo { // ----- gc support ----- void - DDefineSsm::forward_children(obj gc) + DDefineSsm::visit_gco_children(obj gc) noexcept { - gc.forward_inplace(&def_expr_.data_); + gc.visit_child(&def_expr_.data_); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DDeftypeSsm.cpp b/src/reader2/DDeftypeSsm.cpp index 3f377113..0007d940 100644 --- a/src/reader2/DDeftypeSsm.cpp +++ b/src/reader2/DDeftypeSsm.cpp @@ -271,7 +271,7 @@ namespace xo { refrtag("expect", this->get_expect_str())); } void - DDeftypeSsm::forward_children(obj /*gc*/) noexcept + DDeftypeSsm::visit_gco_children(obj) noexcept { static_assert(!DUniqueString::is_gc_eligible()); } diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 6a9d08e7..bce870f6 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -625,7 +625,7 @@ namespace xo { #endif void - DExpectExprSsm::forward_children(obj /*gc*/) noexcept + DExpectExprSsm::visit_gco_children(obj) noexcept { // all members POD, skip } diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index d7e903d8..7a529983 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -265,7 +265,7 @@ namespace xo { } void - DExpectFormalArgSsm::forward_children(obj /*gc*/) noexcept + DExpectFormalArgSsm::visit_gco_children(obj) noexcept { static_assert(!DUniqueString::is_gc_eligible()); } diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index ab7d19ee..6cbf199a 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -358,9 +358,9 @@ namespace xo { } void - DExpectFormalArglistSsm::forward_children(obj gc) noexcept + DExpectFormalArglistSsm::visit_gco_children(obj gc) noexcept { - gc.forward_inplace(&argl_); + gc.visit_child(&argl_); } } /*namespace scm*/ diff --git a/src/reader2/DExpectListTypeSsm.cpp b/src/reader2/DExpectListTypeSsm.cpp index 921c562e..001ff254 100644 --- a/src/reader2/DExpectListTypeSsm.cpp +++ b/src/reader2/DExpectListTypeSsm.cpp @@ -204,9 +204,9 @@ namespace xo { } void - DExpectListTypeSsm::forward_children(obj gc) noexcept + DExpectListTypeSsm::visit_gco_children(obj gc) noexcept { - gc.forward_pivot_inplace(&elt_type_); + gc.visit_poly_child(&elt_type_); } } /*namespace scm*/ diff --git a/src/reader2/DExpectQArraySsm.cpp b/src/reader2/DExpectQArraySsm.cpp index 3d373783..9e281f8c 100644 --- a/src/reader2/DExpectQArraySsm.cpp +++ b/src/reader2/DExpectQArraySsm.cpp @@ -220,9 +220,9 @@ namespace xo { refrtag("array", array_pr)); } void - DExpectQArraySsm::forward_children(obj gc) noexcept + DExpectQArraySsm::visit_gco_children(obj gc) noexcept { - gc.forward_inplace(&array_); + gc.visit_child(&array_); } } diff --git a/src/reader2/DExpectQDictSsm.cpp b/src/reader2/DExpectQDictSsm.cpp index b57887cb..9839ffd2 100644 --- a/src/reader2/DExpectQDictSsm.cpp +++ b/src/reader2/DExpectQDictSsm.cpp @@ -267,10 +267,10 @@ namespace xo { void - DExpectQDictSsm::forward_children(obj gc) noexcept + DExpectQDictSsm::visit_gco_children(obj gc) noexcept { - gc.forward_inplace(const_cast(&key_)); - gc.forward_inplace(&dict_); + gc.visit_child(&key_); + gc.visit_child(&dict_); } } /*namespace scm*/ diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp index 59df8c2c..965351c3 100644 --- a/src/reader2/DExpectQListSsm.cpp +++ b/src/reader2/DExpectQListSsm.cpp @@ -215,10 +215,10 @@ namespace xo { refrtag("list", list_pr)); } void - DExpectQListSsm::forward_children(obj gc) noexcept + DExpectQListSsm::visit_gco_children(obj gc) noexcept { - gc.forward_inplace(&start_); - gc.forward_inplace(&end_); + gc.visit_child(&start_); + gc.visit_child(&end_); } } diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index b87eff24..c49cf565 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -256,7 +256,7 @@ namespace xo { refrtag("expect", this->get_expect_str())); } void - DExpectQLiteralSsm::forward_children(obj /*gc*/) noexcept + DExpectQLiteralSsm::visit_gco_children(obj) noexcept { // cxl_on_rightparen_, cxl_on_rightbracket_: POD, skip } diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index 0875a044..fa1372b1 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -146,7 +146,7 @@ namespace xo { ); } void - DExpectSymbolSsm::forward_children(obj /*gc*/) noexcept + DExpectSymbolSsm::visit_gco_children(obj) noexcept { // no gc-aware members } diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index b25c9380..47cc5a6c 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -198,7 +198,7 @@ namespace xo { } void - DExpectTypeSsm::forward_children(obj /*gc*/) noexcept + DExpectTypeSsm::visit_gco_children(obj) noexcept { // corrected_: POD, skip } diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp index 2893beda..64eabd4f 100644 --- a/src/reader2/DGlobalEnv.cpp +++ b/src/reader2/DGlobalEnv.cpp @@ -107,25 +107,17 @@ namespace xo { // ----- AGCObject facet ----- - std::size_t - DGlobalEnv::shallow_size() const noexcept - { - return sizeof(*this); - } - DGlobalEnv * DGlobalEnv::shallow_move(obj gc) noexcept { return gc.std_move_for(this); } - std::size_t - DGlobalEnv::forward_children(obj gc) noexcept + void + DGlobalEnv::visit_gco_children(obj gc) noexcept { - gc.forward_inplace(&symtab_); - gc.forward_inplace(&values_); - - return this->shallow_size(); + gc.visit_child(&symtab_); + gc.visit_child(&values_); } // ----- APrintable facet ----- diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index 03bd1589..f4fd4f88 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -510,9 +510,9 @@ namespace xo { } void - DIfElseSsm::forward_children(obj gc) noexcept + DIfElseSsm::visit_gco_children(obj gc) noexcept { - gc.forward_pivot_inplace(&if_expr_); + gc.visit_poly_child(&if_expr_); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index d23f04e6..f0fed420 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -4,16 +4,13 @@ **/ #include "LambdaSsm.hpp" -//#include "ssm/ISyntaxStateMachine_DLambdaSsm.hpp" #include "ExpectFormalArglistSsm.hpp" -//#include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp" #include "DExpectTypeSsm.hpp" #include "DExpectExprSsm.hpp" #include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" #include #include -//#include //#include #include #include @@ -474,15 +471,15 @@ namespace xo { } void - DLambdaSsm::forward_children(obj gc) noexcept + DLambdaSsm::visit_gco_children(obj gc) noexcept { - gc.forward_inplace(&local_symtab_); + gc.visit_child(&local_symtab_); // explicit_return_td not gcobject // lambda_td not gcobject - gc.forward_pivot_inplace(&body_); - gc.forward_pivot_inplace(&parent_symtab_); + gc.visit_poly_child(&body_); + gc.visit_poly_child(&parent_symtab_); } } /*namespace scm*/ diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index 13fb728a..82320cb6 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -459,9 +459,9 @@ namespace xo { } void - DParenSsm::forward_children(obj gc) noexcept + DParenSsm::visit_gco_children(obj gc) noexcept { - gc.forward_pivot_inplace(&expr_); + gc.visit_poly_child(&expr_); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 345ba5fd..04c87fac 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -1244,10 +1244,10 @@ case optype::op_assign: } void - DProgressSsm::forward_children(obj gc) noexcept + DProgressSsm::visit_gco_children(obj gc) noexcept { - gc.forward_pivot_inplace(&lhs_); - gc.forward_pivot_inplace(&rhs_); + gc.visit_poly_child(&lhs_); + gc.visit_poly_child(&rhs_); } } /*namespace scm*/ diff --git a/src/reader2/DQuoteSsm.cpp b/src/reader2/DQuoteSsm.cpp index 3a665eb5..cbbedc73 100644 --- a/src/reader2/DQuoteSsm.cpp +++ b/src/reader2/DQuoteSsm.cpp @@ -212,9 +212,9 @@ namespace xo { } void - DQuoteSsm::forward_children(obj gc) noexcept + DQuoteSsm::visit_gco_children(obj gc) noexcept { - gc.forward_pivot_inplace(&expr_); + gc.visit_poly_child(&expr_); } } /*namespace scm*/ diff --git a/src/reader2/DSchematikaParser.cpp b/src/reader2/DSchematikaParser.cpp index e25e76aa..1d5ecea7 100644 --- a/src/reader2/DSchematikaParser.cpp +++ b/src/reader2/DSchematikaParser.cpp @@ -184,12 +184,6 @@ namespace xo { ); } - std::size_t - DSchematikaParser::shallow_size() const noexcept - { - return sizeof(DSchematikaParser); - } - DSchematikaParser * DSchematikaParser::shallow_move(obj gc) noexcept { @@ -202,12 +196,10 @@ namespace xo { return nullptr; } - std::size_t - DSchematikaParser::forward_children(obj gc) noexcept + void + DSchematikaParser::visit_gco_children(obj gc) noexcept { - psm_.forward_children(gc); - - return this->shallow_size(); + psm_.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index f6caeb06..a6d4013b 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -258,9 +258,9 @@ namespace xo { } void - DSequenceSsm::forward_children(obj gc) noexcept + DSequenceSsm::visit_gco_children(obj gc) noexcept { - gc.forward_inplace(&seq_expr_); + gc.visit_child(&seq_expr_); } } /*namespace scm*/ diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index 9252c700..e660f780 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -518,7 +518,7 @@ namespace xo { refrtag("seqtype", seqtype_)); } void - DToplevelSeqSsm::forward_children(obj /*gc*/) noexcept + DToplevelSeqSsm::visit_gco_children(obj) noexcept { // seqtype_: POD, skip } diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 7d174c5b..a260bdc9 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -96,7 +96,7 @@ ISyntaxStateMachine_Any::on_quoted_literal(Opaque, obj, ParserStateMa } auto -ISyntaxStateMachine_Any::forward_children(Opaque, obj) -> void +ISyntaxStateMachine_Any::visit_gco_children(Opaque, obj) -> void { _fatal(); } diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index 75464bcc..0ecc4e24 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectExprSsm::forward_children(DExpectExprSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectExprSsm::visit_gco_children(DExpectExprSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp index 61b219f0..4db6a480 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectFormalArglistSsm::forward_children(DExpectFormalArglistSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectFormalArglistSsm::visit_gco_children(DExpectFormalArglistSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp index b938f1e7..ea8b14cc 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectQArraySsm::forward_children(DExpectQArraySsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectQArraySsm::visit_gco_children(DExpectQArraySsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp index 19df0dff..363f9646 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectQListSsm::forward_children(DExpectQListSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectQListSsm::visit_gco_children(DExpectQListSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp index e6f338fc..61e15926 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectQLiteralSsm::forward_children(DExpectQLiteralSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectQLiteralSsm::visit_gco_children(DExpectQLiteralSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index b8e8fed0..c1331ceb 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectSymbolSsm::forward_children(DExpectSymbolSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectSymbolSsm::visit_gco_children(DExpectSymbolSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 011edc4f..8daed04c 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectTypeSsm::forward_children(DExpectTypeSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectTypeSsm::visit_gco_children(DExpectTypeSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp index 6ee6902b..42a199cb 100644 --- a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DParenSsm::forward_children(DParenSsm & self, obj gc) -> void + ISyntaxStateMachine_DParenSsm::visit_gco_children(DParenSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 01e1e754..9c5ad07d 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DProgressSsm::forward_children(DProgressSsm & self, obj gc) -> void + ISyntaxStateMachine_DProgressSsm::visit_gco_children(DProgressSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp index 30e164d8..a6375288 100644 --- a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DSequenceSsm::forward_children(DSequenceSsm & self, obj gc) -> void + ISyntaxStateMachine_DSequenceSsm::visit_gco_children(DSequenceSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp index 73f23da0..47788590 100644 --- a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DToplevelSeqSsm::forward_children(DToplevelSeqSsm & self, obj gc) -> void + ISyntaxStateMachine_DToplevelSeqSsm::visit_gco_children(DToplevelSeqSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/ParserResult.cpp b/src/reader2/ParserResult.cpp index fa9c9591..609f204f 100644 --- a/src/reader2/ParserResult.cpp +++ b/src/reader2/ParserResult.cpp @@ -106,12 +106,12 @@ namespace xo { } void - ParserResult::forward_children(obj gc) noexcept + ParserResult::visit_gco_children(obj gc) noexcept { // {result_type_, error_src_fn_}: pod, ignore - gc.forward_pivot_inplace(&result_expr_); - gc.forward_inplace(const_cast(&error_description_)); + gc.visit_poly_child(&result_expr_); + gc.visit_child(&error_description_); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ParserStack.cpp b/src/reader2/ParserStack.cpp index f40696b2..721b19b4 100644 --- a/src/reader2/ParserStack.cpp +++ b/src/reader2/ParserStack.cpp @@ -90,14 +90,14 @@ namespace xo { } void - ParserStack::forward_children(obj gc) noexcept + ParserStack::visit_gco_children(obj gc) noexcept { for (ParserStack * target = this; target; target = target->parent_) { // ParserStack::ckp: skip, POD if (target->ssm_) - target->ssm_.forward_children(gc); + target->ssm_.visit_gco_children(gc); } } diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index c3d92a0c..6bec1833 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -907,7 +907,7 @@ namespace xo { #endif void - ParserStateMachine::forward_children(obj gc) noexcept + ParserStateMachine::visit_gco_children(obj gc) noexcept { //scope log(XO_DEBUG(true)); @@ -916,23 +916,23 @@ namespace xo { //log && log("forward stack_", xtag("addr", stack_)); if (stack_) { - stack_->forward_children(gc); + stack_->visit_gco_children(gc); } // static_assert(!expr_alloc_.is_gc_eligible()); // static_assert(!aux_alloc_.is_gc_eligible()); //log && log("global_symtab_", xtag("addr", global_symtab_.data())); - gc.forward_inplace(&global_symtab_); + gc.visit_child(&global_symtab_); //log && log("local_symtab_", xtag("addr", local_symtab_.data())); - gc.forward_inplace(&local_symtab_); + gc.visit_child(&local_symtab_); //log && log("global_env_", xtag("addr", global_env_.data())); - gc.forward_inplace(&global_env_); + gc.visit_child(&global_env_); //log && log("result_"); - result_.forward_children(gc); + result_.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index ba681bab..c9405916 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -10,9 +10,9 @@ namespace xo { namespace scm { void - ReaderResult::forward_children(obj gc) noexcept + ReaderResult::visit_gco_children(obj gc) noexcept { - gc.forward_pivot_inplace(&expr_); + gc.visit_poly_child(&expr_); } // ----- SchematikaReader ----- @@ -208,12 +208,12 @@ namespace xo { } void - SchematikaReader::forward_children(obj gc) noexcept + SchematikaReader::visit_gco_children(obj gc) noexcept { // tokenizer doesn't contain any gc-aware pointers. - parser_.forward_children(gc); - result_.forward_children(gc); + parser_.visit_gco_children(gc); + result_.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/IGCObject_DGlobalEnv.cpp b/src/reader2/facet/IGCObject_DGlobalEnv.cpp index 5c61e9ea..e826c422 100644 --- a/src/reader2/facet/IGCObject_DGlobalEnv.cpp +++ b/src/reader2/facet/IGCObject_DGlobalEnv.cpp @@ -21,9 +21,9 @@ namespace xo { return self.shallow_move(gc); } auto - IGCObject_DGlobalEnv::forward_children(DGlobalEnv & self, obj gc) noexcept -> void + IGCObject_DGlobalEnv::visit_gco_children(DGlobalEnv & self, obj fn) noexcept -> void { - self.forward_children(gc); + self.visit_gco_children(fn); } } /*namespace scm*/ diff --git a/src/reader2/facet/IGCObject_DSchematikaParser.cpp b/src/reader2/facet/IGCObject_DSchematikaParser.cpp index 133b3f9c..cd9ec847 100644 --- a/src/reader2/facet/IGCObject_DSchematikaParser.cpp +++ b/src/reader2/facet/IGCObject_DSchematikaParser.cpp @@ -21,9 +21,9 @@ namespace xo { return self.shallow_move(gc); } auto - IGCObject_DSchematikaParser::forward_children(DSchematikaParser & self, obj gc) noexcept -> void + IGCObject_DSchematikaParser::visit_gco_children(DSchematikaParser & self, obj fn) noexcept -> void { - self.forward_children(gc); + self.visit_gco_children(fn); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp index daff54de..01f685fe 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DApplySsm::forward_children(DApplySsm & self, obj gc) -> void + ISyntaxStateMachine_DApplySsm::visit_gco_children(DApplySsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp index 9867898f..886155c0 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DDefineSsm::forward_children(DDefineSsm & self, obj gc) -> void + ISyntaxStateMachine_DDefineSsm::visit_gco_children(DDefineSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp index e6e54b1c..874849ff 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DDeftypeSsm::forward_children(DDeftypeSsm & self, obj gc) -> void + ISyntaxStateMachine_DDeftypeSsm::visit_gco_children(DDeftypeSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp index 059fd4b2..85f8dd7a 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectFormalArgSsm::forward_children(DExpectFormalArgSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectFormalArgSsm::visit_gco_children(DExpectFormalArgSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp index b760ac9a..d3b292ad 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectListTypeSsm::forward_children(DExpectListTypeSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectListTypeSsm::visit_gco_children(DExpectListTypeSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp index 7ee82e82..9f4d74cc 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectQDictSsm::forward_children(DExpectQDictSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectQDictSsm::visit_gco_children(DExpectQDictSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp index c78464c7..68034ba4 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DIfElseSsm::forward_children(DIfElseSsm & self, obj gc) -> void + ISyntaxStateMachine_DIfElseSsm::visit_gco_children(DIfElseSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp index b54d54fc..88e52100 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DLambdaSsm::forward_children(DLambdaSsm & self, obj gc) -> void + ISyntaxStateMachine_DLambdaSsm::visit_gco_children(DLambdaSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp index 9624c899..39d26414 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DQuoteSsm::forward_children(DQuoteSsm & self, obj gc) -> void + ISyntaxStateMachine_DQuoteSsm::visit_gco_children(DQuoteSsm & self, obj gc) -> void { - self.forward_children(gc); + self.visit_gco_children(gc); } } /*namespace scm*/ From 0bc037f1ea3cab60e727b4f313af7ffce49a82b9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 6 Apr 2026 00:11:08 -0400 Subject: [PATCH 333/342] refactor: make shallow_move() available from AGCObjectVisitor --- include/xo/reader2/env/IGCObject_DGlobalEnv.hpp | 2 +- include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp index 8e97a792..2b961b43 100644 --- a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp +++ b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp @@ -53,7 +53,7 @@ namespace xo { // const methods // non-const methods - /** move instance using allocator **/ + /** move instance using collector **/ static Opaque shallow_move(DGlobalEnv & self, obj gc) noexcept; /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. Context: provides address of data pointer so it can be updated in place diff --git a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp index f2ca67de..ce93ba8a 100644 --- a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp +++ b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp @@ -53,7 +53,7 @@ namespace xo { // const methods // non-const methods - /** move instance using allocator **/ + /** move instance using collector **/ static Opaque shallow_move(DSchematikaParser & self, obj gc) noexcept; /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. Context: provides address of data pointer so it can be updated in place From 31df51ac8ea0d39678b60dfe76d52dfe6576baf7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 6 Apr 2026 15:21:48 -0400 Subject: [PATCH 334/342] refactor: use GCObjectVisitor api w/ gco_shallow_move --- include/xo/reader2/DGlobalEnv.hpp | 4 ++-- include/xo/reader2/env/IGCObject_DGlobalEnv.hpp | 5 +++-- include/xo/reader2/parser/DSchematikaParser.hpp | 4 ++-- include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp | 5 +++-- src/reader2/DGlobalEnv.cpp | 2 +- src/reader2/DSchematikaParser.cpp | 2 +- src/reader2/facet/IGCObject_DGlobalEnv.cpp | 4 ++-- src/reader2/facet/IGCObject_DSchematikaParser.cpp | 4 ++-- 8 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/xo/reader2/DGlobalEnv.hpp b/include/xo/reader2/DGlobalEnv.hpp index 04605c4c..6bb88f49 100644 --- a/include/xo/reader2/DGlobalEnv.hpp +++ b/include/xo/reader2/DGlobalEnv.hpp @@ -27,7 +27,7 @@ namespace xo { class DGlobalEnv { public: using TypeDescr = xo::reflect::TypeDescr; - using ACollector = xo::mm::ACollector; + //using ACollector = xo::mm::ACollector; using AGCObject = xo::mm::AGCObject; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; @@ -72,7 +72,7 @@ namespace xo { /** @defgroup scm-globalenv-gcobject-facet **/ ///@{ - DGlobalEnv * shallow_move(obj gc) noexcept; + DGlobalEnv * gco_shallow_move(obj gc) noexcept; void visit_gco_children(obj gc) noexcept; ///@} diff --git a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp index 2b961b43..f96deebc 100644 --- a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp +++ b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp @@ -53,8 +53,9 @@ namespace xo { // const methods // non-const methods - /** move instance using collector **/ - static Opaque shallow_move(DGlobalEnv & self, obj gc) noexcept; + /** move instance using object visitor. +Arguably abusing the word 'visitor' here **/ + static Opaque gco_shallow_move(DGlobalEnv & self, obj gc) noexcept; /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. Context: provides address of data pointer so it can be updated in place when @p fn invokes garbage collector reentry point **/ diff --git a/include/xo/reader2/parser/DSchematikaParser.hpp b/include/xo/reader2/parser/DSchematikaParser.hpp index c3de4930..24e4b46a 100644 --- a/include/xo/reader2/parser/DSchematikaParser.hpp +++ b/include/xo/reader2/parser/DSchematikaParser.hpp @@ -164,7 +164,7 @@ namespace xo { using token_type = Token; using ArenaHashMapConfig = xo::map::ArenaHashMapConfig; using ArenaConfig = xo::mm::ArenaConfig; - using ACollector = xo::mm::ACollector; + //using ACollector = xo::mm::ACollector; using AGCObject = xo::mm::AGCObject; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; @@ -295,7 +295,7 @@ namespace xo { ///@{ /** not implemented (SchematikaParser not designed to be copyable) **/ - DSchematikaParser * shallow_move(obj gc) noexcept; + DSchematikaParser * gco_shallow_move(obj gc) noexcept; /** forward gc-aware children **/ void visit_gco_children(obj gc) noexcept; diff --git a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp index ce93ba8a..64394e65 100644 --- a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp +++ b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp @@ -53,8 +53,9 @@ namespace xo { // const methods // non-const methods - /** move instance using collector **/ - static Opaque shallow_move(DSchematikaParser & self, obj gc) noexcept; + /** move instance using object visitor. +Arguably abusing the word 'visitor' here **/ + static Opaque gco_shallow_move(DSchematikaParser & self, obj gc) noexcept; /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. Context: provides address of data pointer so it can be updated in place when @p fn invokes garbage collector reentry point **/ diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp index 64eabd4f..8491c60b 100644 --- a/src/reader2/DGlobalEnv.cpp +++ b/src/reader2/DGlobalEnv.cpp @@ -108,7 +108,7 @@ namespace xo { // ----- AGCObject facet ----- DGlobalEnv * - DGlobalEnv::shallow_move(obj gc) noexcept + DGlobalEnv::gco_shallow_move(obj gc) noexcept { return gc.std_move_for(this); } diff --git a/src/reader2/DSchematikaParser.cpp b/src/reader2/DSchematikaParser.cpp index 1d5ecea7..fc71d12f 100644 --- a/src/reader2/DSchematikaParser.cpp +++ b/src/reader2/DSchematikaParser.cpp @@ -185,7 +185,7 @@ namespace xo { } DSchematikaParser * - DSchematikaParser::shallow_move(obj gc) noexcept + DSchematikaParser::gco_shallow_move(obj gc) noexcept { (void)gc; diff --git a/src/reader2/facet/IGCObject_DGlobalEnv.cpp b/src/reader2/facet/IGCObject_DGlobalEnv.cpp index e826c422..9a2802ae 100644 --- a/src/reader2/facet/IGCObject_DGlobalEnv.cpp +++ b/src/reader2/facet/IGCObject_DGlobalEnv.cpp @@ -16,9 +16,9 @@ namespace xo { namespace scm { auto - IGCObject_DGlobalEnv::shallow_move(DGlobalEnv & self, obj gc) noexcept -> Opaque + IGCObject_DGlobalEnv::gco_shallow_move(DGlobalEnv & self, obj gc) noexcept -> Opaque { - return self.shallow_move(gc); + return self.gco_shallow_move(gc); } auto IGCObject_DGlobalEnv::visit_gco_children(DGlobalEnv & self, obj fn) noexcept -> void diff --git a/src/reader2/facet/IGCObject_DSchematikaParser.cpp b/src/reader2/facet/IGCObject_DSchematikaParser.cpp index cd9ec847..f1778d5a 100644 --- a/src/reader2/facet/IGCObject_DSchematikaParser.cpp +++ b/src/reader2/facet/IGCObject_DSchematikaParser.cpp @@ -16,9 +16,9 @@ namespace xo { namespace scm { auto - IGCObject_DSchematikaParser::shallow_move(DSchematikaParser & self, obj gc) noexcept -> Opaque + IGCObject_DSchematikaParser::gco_shallow_move(DSchematikaParser & self, obj gc) noexcept -> Opaque { - return self.shallow_move(gc); + return self.gco_shallow_move(gc); } auto IGCObject_DSchematikaParser::visit_gco_children(DSchematikaParser & self, obj fn) noexcept -> void From d14f119a37d64dfe56d1b42b438dc336ab5a6cb6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 10 Apr 2026 01:10:03 -0400 Subject: [PATCH 335/342] xo-interpreter2 stack: + reason arg to visit_gco_children() Helps streamline DX1Collector in xo-gc/. Want both forward and verify entry points for the same representation. --- idl/SyntaxStateMachine.json5 | 3 ++- include/xo/reader2/DDefineSsm.hpp | 4 +++- include/xo/reader2/DExpectExprSsm.hpp | 3 ++- include/xo/reader2/DExpectFormalArglistSsm.hpp | 4 +++- include/xo/reader2/DExpectQArraySsm.hpp | 4 +++- include/xo/reader2/DExpectQListSsm.hpp | 3 ++- include/xo/reader2/DExpectQLiteralSsm.hpp | 3 ++- include/xo/reader2/DExpectSymbolSsm.hpp | 3 ++- include/xo/reader2/DExpectTypeSsm.hpp | 4 +++- include/xo/reader2/DGlobalEnv.hpp | 4 ++-- include/xo/reader2/DProgressSsm.hpp | 4 +++- include/xo/reader2/DQuoteSsm.hpp | 3 ++- include/xo/reader2/DSequenceSsm.hpp | 4 +++- include/xo/reader2/DToplevelSeqSsm.hpp | 3 ++- include/xo/reader2/ParserResult.hpp | 3 ++- include/xo/reader2/ParserStack.hpp | 4 +++- include/xo/reader2/ParserStateMachine.hpp | 6 ++++-- include/xo/reader2/SchematikaReader.hpp | 8 ++++++-- include/xo/reader2/apply/DApplySsm.hpp | 7 +++---- .../reader2/apply/ISyntaxStateMachine_DApplySsm.hpp | 3 ++- .../define/ISyntaxStateMachine_DDefineSsm.hpp | 3 ++- include/xo/reader2/deftype/DDeftypeSsm.hpp | 3 ++- .../deftype/ISyntaxStateMachine_DDeftypeSsm.hpp | 3 ++- include/xo/reader2/env/IGCObject_DGlobalEnv.hpp | 3 ++- .../expect_formal_arg/DExpectFormalArgSsm.hpp | 4 +++- .../ISyntaxStateMachine_DExpectFormalArgSsm.hpp | 3 ++- .../reader2/expect_listtype/DExpectListTypeSsm.hpp | 4 +++- .../ISyntaxStateMachine_DExpectListTypeSsm.hpp | 3 ++- include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp | 4 +++- .../ISyntaxStateMachine_DExpectQDictSsm.hpp | 3 ++- include/xo/reader2/ifelse/DIfElseSsm.hpp | 4 +++- .../ifelse/ISyntaxStateMachine_DIfElseSsm.hpp | 3 ++- include/xo/reader2/lambda/DLambdaSsm.hpp | 4 +++- .../lambda/ISyntaxStateMachine_DLambdaSsm.hpp | 3 ++- include/xo/reader2/paren/DParenSsm.hpp | 4 +++- .../reader2/paren/ISyntaxStateMachine_DParenSsm.hpp | 3 ++- include/xo/reader2/parser/DSchematikaParser.hpp | 4 ++-- .../reader2/parser/IGCObject_DSchematikaParser.hpp | 3 ++- .../reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp | 3 ++- include/xo/reader2/ssm/ASyntaxStateMachine.hpp | 4 +++- include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp | 3 ++- .../ssm/ISyntaxStateMachine_DExpectExprSsm.hpp | 3 ++- .../ISyntaxStateMachine_DExpectFormalArglistSsm.hpp | 3 ++- .../ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp | 3 ++- .../ssm/ISyntaxStateMachine_DExpectQListSsm.hpp | 3 ++- .../ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp | 3 ++- .../ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp | 3 ++- .../ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp | 3 ++- .../ssm/ISyntaxStateMachine_DProgressSsm.hpp | 3 ++- .../ssm/ISyntaxStateMachine_DSequenceSsm.hpp | 3 ++- .../ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp | 3 ++- include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 5 +++-- include/xo/reader2/ssm/RSyntaxStateMachine.hpp | 5 +++-- src/reader2/DApplySsm.cpp | 7 ++++--- src/reader2/DDefineSsm.cpp | 5 +++-- src/reader2/DDeftypeSsm.cpp | 2 +- src/reader2/DExpectExprSsm.cpp | 3 ++- src/reader2/DExpectFormalArgSsm.cpp | 3 ++- src/reader2/DExpectFormalArglistSsm.cpp | 5 +++-- src/reader2/DExpectListTypeSsm.cpp | 5 +++-- src/reader2/DExpectQArraySsm.cpp | 5 +++-- src/reader2/DExpectQDictSsm.cpp | 7 ++++--- src/reader2/DExpectQListSsm.cpp | 7 ++++--- src/reader2/DExpectQLiteralSsm.cpp | 2 +- src/reader2/DExpectSymbolSsm.cpp | 3 ++- src/reader2/DExpectTypeSsm.cpp | 3 ++- src/reader2/DGlobalEnv.cpp | 7 ++++--- src/reader2/DIfElseSsm.cpp | 5 +++-- src/reader2/DLambdaSsm.cpp | 9 +++++---- src/reader2/DParenSsm.cpp | 5 +++-- src/reader2/DProgressSsm.cpp | 7 ++++--- src/reader2/DQuoteSsm.cpp | 5 +++-- src/reader2/DSchematikaParser.cpp | 5 +++-- src/reader2/DSequenceSsm.cpp | 5 +++-- src/reader2/DToplevelSeqSsm.cpp | 2 +- src/reader2/ISyntaxStateMachine_Any.cpp | 2 +- src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp | 4 ++-- .../ISyntaxStateMachine_DExpectFormalArglistSsm.cpp | 4 ++-- .../ISyntaxStateMachine_DExpectQArraySsm.cpp | 4 ++-- src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp | 4 ++-- .../ISyntaxStateMachine_DExpectQLiteralSsm.cpp | 4 ++-- .../ISyntaxStateMachine_DExpectSymbolSsm.cpp | 4 ++-- src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp | 4 ++-- src/reader2/ISyntaxStateMachine_DParenSsm.cpp | 4 ++-- src/reader2/ISyntaxStateMachine_DProgressSsm.cpp | 4 ++-- src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp | 4 ++-- src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp | 4 ++-- src/reader2/ParserResult.cpp | 7 ++++--- src/reader2/ParserStack.cpp | 5 +++-- src/reader2/ParserStateMachine.cpp | 13 +++++++------ src/reader2/SchematikaReader.cpp | 12 +++++++----- src/reader2/facet/IGCObject_DGlobalEnv.cpp | 4 ++-- src/reader2/facet/IGCObject_DSchematikaParser.cpp | 4 ++-- src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp | 4 ++-- .../facet/ISyntaxStateMachine_DDefineSsm.cpp | 4 ++-- .../facet/ISyntaxStateMachine_DDeftypeSsm.cpp | 4 ++-- .../ISyntaxStateMachine_DExpectFormalArgSsm.cpp | 4 ++-- .../ISyntaxStateMachine_DExpectListTypeSsm.cpp | 4 ++-- .../facet/ISyntaxStateMachine_DExpectQDictSsm.cpp | 4 ++-- .../facet/ISyntaxStateMachine_DIfElseSsm.cpp | 4 ++-- .../facet/ISyntaxStateMachine_DLambdaSsm.cpp | 4 ++-- src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp | 4 ++-- 102 files changed, 258 insertions(+), 167 deletions(-) diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index d47656b7..c2d8aff1 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -29,7 +29,7 @@ { name: "TypeDescr", doc: [ "reflected c++ type" ], definition: "xo::reflect::TypeDescr" }, { name: "AGCObjectVisitor", doc: [ "gc visitor interface" ], definition: "xo::mm::AGCObjectVisitor" }, { name: "AGCObject", doc: [ "gc-aware object" ], definition: "xo::mm::AGCObject" }, - // { name: string, doc: [ string ], definition: string }, + { name: "VisitReason", doc: [ "hint when traversing gco graph" ], definition: "xo::mm::VisitReason" }, ], const_methods: [ { @@ -151,6 +151,7 @@ doc: ["gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each"], return_type: "void", args: [ + {type: "VisitReason", name: "reason"}, {type: "obj", name: "gc"}, ], } diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index e31c3b2a..36afb4b4 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -74,6 +74,7 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -200,7 +201,8 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index e73e1f16..b0d4b5f3 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -18,6 +18,7 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -194,7 +195,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectFormalArglistSsm.hpp b/include/xo/reader2/DExpectFormalArglistSsm.hpp index 954cdc72..c321b135 100644 --- a/include/xo/reader2/DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/DExpectFormalArglistSsm.hpp @@ -56,6 +56,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -130,7 +131,8 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectQArraySsm.hpp b/include/xo/reader2/DExpectQArraySsm.hpp index 2ec32eb4..fcd1a14e 100644 --- a/include/xo/reader2/DExpectQArraySsm.hpp +++ b/include/xo/reader2/DExpectQArraySsm.hpp @@ -58,6 +58,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -123,7 +124,8 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectQListSsm.hpp b/include/xo/reader2/DExpectQListSsm.hpp index 3b9ab53d..8c9185ca 100644 --- a/include/xo/reader2/DExpectQListSsm.hpp +++ b/include/xo/reader2/DExpectQListSsm.hpp @@ -59,6 +59,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -124,7 +125,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectQLiteralSsm.hpp b/include/xo/reader2/DExpectQLiteralSsm.hpp index 2538fb6f..58d7a0b4 100644 --- a/include/xo/reader2/DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/DExpectQLiteralSsm.hpp @@ -16,6 +16,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -129,7 +130,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DExpectSymbolSsm.hpp b/include/xo/reader2/DExpectSymbolSsm.hpp index f4c3c156..0acd75c3 100644 --- a/include/xo/reader2/DExpectSymbolSsm.hpp +++ b/include/xo/reader2/DExpectSymbolSsm.hpp @@ -22,6 +22,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; using ppindentinfo = xo::print::ppindentinfo; @@ -80,7 +81,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; ///@} }; diff --git a/include/xo/reader2/DExpectTypeSsm.hpp b/include/xo/reader2/DExpectTypeSsm.hpp index d405e916..fd65a3ec 100644 --- a/include/xo/reader2/DExpectTypeSsm.hpp +++ b/include/xo/reader2/DExpectTypeSsm.hpp @@ -29,6 +29,7 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -87,7 +88,8 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DGlobalEnv.hpp b/include/xo/reader2/DGlobalEnv.hpp index 6bb88f49..02a4679a 100644 --- a/include/xo/reader2/DGlobalEnv.hpp +++ b/include/xo/reader2/DGlobalEnv.hpp @@ -27,9 +27,9 @@ namespace xo { class DGlobalEnv { public: using TypeDescr = xo::reflect::TypeDescr; - //using ACollector = xo::mm::ACollector; using AGCObject = xo::mm::AGCObject; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using ppindentinfo = xo::print::ppindentinfo; @@ -73,7 +73,7 @@ namespace xo { ///@{ DGlobalEnv * gco_shallow_move(obj gc) noexcept; - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; ///@} /** @defgroup scm-globalenv-printable-facet **/ diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 372b3af6..3abc38ea 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -90,6 +90,7 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -217,7 +218,8 @@ namespace xo { /** @defgroup scm-progressssm-gc-support gc support methods **/ ///@{ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DQuoteSsm.hpp b/include/xo/reader2/DQuoteSsm.hpp index 542342ef..0874b549 100644 --- a/include/xo/reader2/DQuoteSsm.hpp +++ b/include/xo/reader2/DQuoteSsm.hpp @@ -66,6 +66,7 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -150,7 +151,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; ///@} private: diff --git a/include/xo/reader2/DSequenceSsm.hpp b/include/xo/reader2/DSequenceSsm.hpp index a7819048..c153d76e 100644 --- a/include/xo/reader2/DSequenceSsm.hpp +++ b/include/xo/reader2/DSequenceSsm.hpp @@ -30,6 +30,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -97,7 +98,8 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/DToplevelSeqSsm.hpp b/include/xo/reader2/DToplevelSeqSsm.hpp index 4103f45a..5df90f4d 100644 --- a/include/xo/reader2/DToplevelSeqSsm.hpp +++ b/include/xo/reader2/DToplevelSeqSsm.hpp @@ -41,6 +41,7 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -161,7 +162,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; ///@} diff --git a/include/xo/reader2/ParserResult.hpp b/include/xo/reader2/ParserResult.hpp index 823372da..c8976da4 100644 --- a/include/xo/reader2/ParserResult.hpp +++ b/include/xo/reader2/ParserResult.hpp @@ -33,6 +33,7 @@ namespace xo { class ParserResult { public: using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using ppindentinfo = xo::print::ppindentinfo; public: @@ -69,7 +70,7 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; /** gc support: forward gc-eligible children **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; public: /** none|expression|error_description diff --git a/include/xo/reader2/ParserStack.hpp b/include/xo/reader2/ParserStack.hpp index e4b414b4..fade2079 100644 --- a/include/xo/reader2/ParserStack.hpp +++ b/include/xo/reader2/ParserStack.hpp @@ -24,6 +24,7 @@ namespace xo { public: //using ACollector = xo::mm::ACollector; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -56,7 +57,8 @@ namespace xo { /** pretty-printer support **/ bool pretty(const ppindentinfo & ppii) const; - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; private: /** stack pointer: top of stack just before this instance created **/ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index fedd574d..b73eac0b 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -40,10 +40,11 @@ namespace xo { public: using TypeDescr = xo::reflect::TypeDescr; using ACollector = xo::mm::ACollector; + using AGCObject = xo::mm::AGCObject; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using ArenaConfig = xo::mm::ArenaConfig; - using AGCObject = xo::mm::AGCObject; using DArena = xo::mm::DArena; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using ArenaHashMapConfig = xo::map::ArenaHashMapConfig; @@ -354,7 +355,8 @@ namespace xo { ///@{ /** update gc-aware exit pointers from this ParserStateMachine **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/SchematikaReader.hpp b/include/xo/reader2/SchematikaReader.hpp index d70c2c04..fd2f5cc9 100644 --- a/include/xo/reader2/SchematikaReader.hpp +++ b/include/xo/reader2/SchematikaReader.hpp @@ -15,12 +15,14 @@ namespace xo { struct ReaderResult { using ACollector = xo::mm::ACollector; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using span_type = xo::mm::span; bool is_tk_error() const { return tk_error_.is_error(); } /** forward gc-aware pointers (called during gc cycle) **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; /** schematika expression parsed from input **/ obj expr_; @@ -43,6 +45,7 @@ namespace xo { public: using ACollector = xo::mm::ACollector; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using span_type = xo::mm::span; @@ -110,7 +113,8 @@ namespace xo { void reset_to_idle_toplevel(); /** update gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; private: /** tokenizer converts a stream of chars diff --git a/include/xo/reader2/apply/DApplySsm.hpp b/include/xo/reader2/apply/DApplySsm.hpp index f7ee1cce..dd724066 100644 --- a/include/xo/reader2/apply/DApplySsm.hpp +++ b/include/xo/reader2/apply/DApplySsm.hpp @@ -8,7 +8,6 @@ #include "DSyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" #include -//#include #include @@ -66,12 +65,11 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; - //using Apply = xo::scm::Apply; - public: /** @defgroup scm-applyssm-ctors constructors **/ ///@{ @@ -190,7 +188,8 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp b/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp index db3a147d..a50740f5 100644 --- a/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp +++ b/include/xo/reader2/apply/ISyntaxStateMachine_DApplySsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DApplySsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DApplySsm & self, obj gc); + static void visit_gco_children(DApplySsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp b/include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp index d5338cd5..35df5ded 100644 --- a/include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp +++ b/include/xo/reader2/define/ISyntaxStateMachine_DDefineSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DDefineSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DDefineSsm & self, obj gc); + static void visit_gco_children(DDefineSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/deftype/DDeftypeSsm.hpp b/include/xo/reader2/deftype/DDeftypeSsm.hpp index b1a6d910..8bbe3ea1 100644 --- a/include/xo/reader2/deftype/DDeftypeSsm.hpp +++ b/include/xo/reader2/deftype/DDeftypeSsm.hpp @@ -67,6 +67,7 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -172,7 +173,7 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; ///@} diff --git a/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp b/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp index 9bfdfba5..b984bc7d 100644 --- a/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp +++ b/include/xo/reader2/deftype/ISyntaxStateMachine_DDeftypeSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DDeftypeSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DDeftypeSsm & self, obj gc); + static void visit_gco_children(DDeftypeSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp index f96deebc..8efa3c27 100644 --- a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp +++ b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp @@ -45,6 +45,7 @@ namespace xo { using AAllocator = xo::mm::AGCObject::AAllocator; using ACollector = xo::mm::AGCObject::ACollector; using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; + using VisitReason = xo::mm::AGCObject::VisitReason; using Copaque = xo::mm::AGCObject::Copaque; using Opaque = xo::mm::AGCObject::Opaque; ///@} @@ -59,7 +60,7 @@ Arguably abusing the word 'visitor' here **/ /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. Context: provides address of data pointer so it can be updated in place when @p fn invokes garbage collector reentry point **/ - static void visit_gco_children(DGlobalEnv & self, obj fn) noexcept; + static void visit_gco_children(DGlobalEnv & self, VisitReason reason, obj fn) noexcept; ///@} }; diff --git a/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp b/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp index 5c7e6dec..38a4bb3e 100644 --- a/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/expect_formal_arg/DExpectFormalArgSsm.hpp @@ -49,6 +49,7 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -126,7 +127,8 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp b/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp index a880fad3..ccdfc0bd 100644 --- a/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp +++ b/include/xo/reader2/expect_formal_arg/ISyntaxStateMachine_DExpectFormalArgSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectFormalArgSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DExpectFormalArgSsm & self, obj gc); + static void visit_gco_children(DExpectFormalArgSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp b/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp index eeadd15c..ce69f929 100644 --- a/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp +++ b/include/xo/reader2/expect_listtype/DExpectListTypeSsm.hpp @@ -63,6 +63,7 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -135,7 +136,8 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} private: diff --git a/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp b/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp index 9ed4214c..b320b9c9 100644 --- a/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp +++ b/include/xo/reader2/expect_listtype/ISyntaxStateMachine_DExpectListTypeSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectListTypeSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DExpectListTypeSsm & self, obj gc); + static void visit_gco_children(DExpectListTypeSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp index 5ed40fab..18c52bac 100644 --- a/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp +++ b/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp @@ -64,6 +64,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -159,7 +160,8 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp index c629e07b..006e43b1 100644 --- a/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp +++ b/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQDictSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DExpectQDictSsm & self, obj gc); + static void visit_gco_children(DExpectQDictSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ifelse/DIfElseSsm.hpp b/include/xo/reader2/ifelse/DIfElseSsm.hpp index fd7b8168..3b63cdb7 100644 --- a/include/xo/reader2/ifelse/DIfElseSsm.hpp +++ b/include/xo/reader2/ifelse/DIfElseSsm.hpp @@ -56,6 +56,7 @@ namespace xo { public: using Super = DSyntaxStateMachine; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -171,7 +172,8 @@ namespace xo { /** @defgroup scm-ifelsessm-gc-support gc support methods **/ ///@{ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp b/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp index 17f6b4cd..a88e9af1 100644 --- a/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp +++ b/include/xo/reader2/ifelse/ISyntaxStateMachine_DIfElseSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DIfElseSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DIfElseSsm & self, obj gc); + static void visit_gco_children(DIfElseSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/lambda/DLambdaSsm.hpp b/include/xo/reader2/lambda/DLambdaSsm.hpp index 7b16503b..93642f5f 100644 --- a/include/xo/reader2/lambda/DLambdaSsm.hpp +++ b/include/xo/reader2/lambda/DLambdaSsm.hpp @@ -60,6 +60,7 @@ namespace xo { using Super = DSyntaxStateMachine; using DLocalSymtab = xo::scm::DLocalSymtab; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using TypeDescr = xo::reflect::TypeDescr; @@ -189,7 +190,8 @@ namespace xo { ///@{ /** gc support: visit gc-aware child pointers **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp b/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp index db67ee9a..baeb5af4 100644 --- a/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp +++ b/include/xo/reader2/lambda/ISyntaxStateMachine_DLambdaSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DLambdaSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DLambdaSsm & self, obj gc); + static void visit_gco_children(DLambdaSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/paren/DParenSsm.hpp b/include/xo/reader2/paren/DParenSsm.hpp index e70ba255..9da3ba42 100644 --- a/include/xo/reader2/paren/DParenSsm.hpp +++ b/include/xo/reader2/paren/DParenSsm.hpp @@ -51,6 +51,7 @@ namespace xo { using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; @@ -136,7 +137,8 @@ namespace xo { ///@{ /** gc support: visit immediate gc-aware children **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, + obj gc) noexcept; ///@} diff --git a/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp b/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp index 4dd7ef74..dc1a826d 100644 --- a/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp +++ b/include/xo/reader2/paren/ISyntaxStateMachine_DParenSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DParenSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DParenSsm & self, obj gc); + static void visit_gco_children(DParenSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/parser/DSchematikaParser.hpp b/include/xo/reader2/parser/DSchematikaParser.hpp index 24e4b46a..f699c30b 100644 --- a/include/xo/reader2/parser/DSchematikaParser.hpp +++ b/include/xo/reader2/parser/DSchematikaParser.hpp @@ -164,9 +164,9 @@ namespace xo { using token_type = Token; using ArenaHashMapConfig = xo::map::ArenaHashMapConfig; using ArenaConfig = xo::mm::ArenaConfig; - //using ACollector = xo::mm::ACollector; using AGCObject = xo::mm::AGCObject; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; using AAllocator = xo::mm::AAllocator; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using ppindentinfo = xo::print::ppindentinfo; @@ -297,7 +297,7 @@ namespace xo { /** not implemented (SchematikaParser not designed to be copyable) **/ DSchematikaParser * gco_shallow_move(obj gc) noexcept; /** forward gc-aware children **/ - void visit_gco_children(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; ///@} private: diff --git a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp index 64394e65..586678cd 100644 --- a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp +++ b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp @@ -45,6 +45,7 @@ namespace xo { using AAllocator = xo::mm::AGCObject::AAllocator; using ACollector = xo::mm::AGCObject::ACollector; using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; + using VisitReason = xo::mm::AGCObject::VisitReason; using Copaque = xo::mm::AGCObject::Copaque; using Opaque = xo::mm::AGCObject::Opaque; ///@} @@ -59,7 +60,7 @@ Arguably abusing the word 'visitor' here **/ /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. Context: provides address of data pointer so it can be updated in place when @p fn invokes garbage collector reentry point **/ - static void visit_gco_children(DSchematikaParser & self, obj fn) noexcept; + static void visit_gco_children(DSchematikaParser & self, VisitReason reason, obj fn) noexcept; ///@} }; diff --git a/include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp b/include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp index 35dc5da1..0f01d967 100644 --- a/include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp +++ b/include/xo/reader2/quote/ISyntaxStateMachine_DQuoteSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DQuoteSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DQuoteSsm & self, obj gc); + static void visit_gco_children(DQuoteSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index 07d992c1..fc71175b 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -50,6 +50,8 @@ public: using AGCObjectVisitor = xo::mm::AGCObjectVisitor; /** gc-aware object **/ using AGCObject = xo::mm::AGCObject; + /** hint when traversing gco graph **/ + using VisitReason = xo::mm::VisitReason; ///@} /** @defgroup scm-syntaxstatemachine-methods **/ @@ -91,7 +93,7 @@ public: /** update state machine for nested quoted literal @p lit **/ virtual void on_quoted_literal(Opaque data, obj lit, ParserStateMachine * p_psm) = 0; /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - virtual void visit_gco_children(Opaque data, obj gc) = 0; + virtual void visit_gco_children(Opaque data, VisitReason reason, obj gc) = 0; ///@} }; /*ASyntaxStateMachine*/ diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 34e7ec84..88b0cde2 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -47,6 +47,7 @@ namespace scm { using TypeDescr = ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = ASyntaxStateMachine::AGCObject; + using VisitReason = ASyntaxStateMachine::VisitReason; ///@} /** @defgroup scm-syntaxstatemachine-any-methods **/ @@ -75,7 +76,7 @@ namespace scm { [[noreturn]] void on_parsed_expression(Opaque, obj, ParserStateMachine *) override; [[noreturn]] void on_parsed_expression_with_token(Opaque, obj, const Token &, ParserStateMachine *) override; [[noreturn]] void on_quoted_literal(Opaque, obj, ParserStateMachine *) override; - [[noreturn]] void visit_gco_children(Opaque, obj) override; + [[noreturn]] void visit_gco_children(Opaque, VisitReason, obj) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp index 5ca9f1c0..63210b94 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectExprSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DExpectExprSsm & self, obj gc); + static void visit_gco_children(DExpectExprSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp index 04da69bd..8b9d4083 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectFormalArglistSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DExpectFormalArglistSsm & self, obj gc); + static void visit_gco_children(DExpectFormalArglistSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp index 7b345008..e4b15c21 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQArraySsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQArraySsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DExpectQArraySsm & self, obj gc); + static void visit_gco_children(DExpectQArraySsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp index ea0cb3c2..42fdc804 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQListSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DExpectQListSsm & self, obj gc); + static void visit_gco_children(DExpectQListSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp index 4a4bdbfb..5dc2130b 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQLiteralSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectQLiteralSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DExpectQLiteralSsm & self, obj gc); + static void visit_gco_children(DExpectQLiteralSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp index e3cf7146..dfc0d6bb 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectSymbolSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectSymbolSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DExpectSymbolSsm & self, obj gc); + static void visit_gco_children(DExpectSymbolSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp index 965212d1..b8607deb 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectTypeSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DExpectTypeSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DExpectTypeSsm & self, obj gc); + static void visit_gco_children(DExpectTypeSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp index 7c12ee39..3a2b3aaf 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DProgressSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DProgressSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DProgressSsm & self, obj gc); + static void visit_gco_children(DProgressSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp index b35d45a1..74183d99 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DSequenceSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DSequenceSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DSequenceSsm & self, obj gc); + static void visit_gco_children(DSequenceSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp index 695da17c..55da530d 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DToplevelSeqSsm.hpp @@ -44,6 +44,7 @@ namespace xo { using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = xo::scm::ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using VisitReason = xo::scm::ASyntaxStateMachine::VisitReason; using Copaque = xo::scm::ASyntaxStateMachine::Copaque; using Opaque = xo::scm::ASyntaxStateMachine::Opaque; ///@} @@ -77,7 +78,7 @@ namespace xo { /** update state machine for nested quoted literal @p lit **/ static void on_quoted_literal(DToplevelSeqSsm & self, obj lit, ParserStateMachine * p_psm); /** gc support: visit immediate gc-aware child pointers with @p gc. Call gc.visit_child() for each **/ - static void visit_gco_children(DToplevelSeqSsm & self, obj gc); + static void visit_gco_children(DToplevelSeqSsm & self, VisitReason reason, obj gc); ///@} }; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index df1a87f4..1d971d3b 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -36,6 +36,7 @@ namespace scm { using TypeDescr = ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = ASyntaxStateMachine::AGCObject; + using VisitReason = ASyntaxStateMachine::VisitReason; ///@} /** @defgroup scm-syntaxstatemachine-xfer-methods **/ @@ -89,8 +90,8 @@ namespace scm { void on_quoted_literal(Opaque data, obj lit, ParserStateMachine * p_psm) override { return I::on_quoted_literal(_dcast(data), lit, p_psm); } - void visit_gco_children(Opaque data, obj gc) override { - return I::visit_gco_children(_dcast(data), gc); + void visit_gco_children(Opaque data, VisitReason reason, obj gc) override { + return I::visit_gco_children(_dcast(data), reason, gc); } ///@} diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 9c8a8274..2f5b9fb0 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -34,6 +34,7 @@ public: using TypeDescr = ASyntaxStateMachine::TypeDescr; using AGCObjectVisitor = ASyntaxStateMachine::AGCObjectVisitor; using AGCObject = ASyntaxStateMachine::AGCObject; + using VisitReason = ASyntaxStateMachine::VisitReason; ///@} /** @defgroup scm-syntaxstatemachine-router-ctors **/ @@ -93,8 +94,8 @@ public: void on_quoted_literal(obj lit, ParserStateMachine * p_psm) { return O::iface()->on_quoted_literal(O::data(), lit, p_psm); } - void visit_gco_children(obj gc) { - return O::iface()->visit_gco_children(O::data(), gc); + void visit_gco_children(VisitReason reason, obj gc) { + return O::iface()->visit_gco_children(O::data(), reason, gc); } ///@} diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index 1787d560..ef84187b 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -397,10 +397,11 @@ namespace xo { } void - DApplySsm::visit_gco_children(obj gc) noexcept + DApplySsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_poly_child(&fn_expr_); - gc.visit_child(&args_expr_v_); + gc.visit_poly_child(reason, &fn_expr_); + gc.visit_child(reason, &args_expr_v_); } } /*namespace scm*/ diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 1ee8e3aa..0e38f93d 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -692,9 +692,10 @@ namespace xo { // ----- gc support ----- void - DDefineSsm::visit_gco_children(obj gc) noexcept + DDefineSsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_child(&def_expr_.data_); + gc.visit_child(reason, &def_expr_.data_); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DDeftypeSsm.cpp b/src/reader2/DDeftypeSsm.cpp index 0007d940..108f6be7 100644 --- a/src/reader2/DDeftypeSsm.cpp +++ b/src/reader2/DDeftypeSsm.cpp @@ -271,7 +271,7 @@ namespace xo { refrtag("expect", this->get_expect_str())); } void - DDeftypeSsm::visit_gco_children(obj) noexcept + DDeftypeSsm::visit_gco_children(VisitReason, obj) noexcept { static_assert(!DUniqueString::is_gc_eligible()); } diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index bce870f6..9526aaea 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -625,7 +625,8 @@ namespace xo { #endif void - DExpectExprSsm::visit_gco_children(obj) noexcept + DExpectExprSsm::visit_gco_children(VisitReason, + obj) noexcept { // all members POD, skip } diff --git a/src/reader2/DExpectFormalArgSsm.cpp b/src/reader2/DExpectFormalArgSsm.cpp index 7a529983..f1bdd81d 100644 --- a/src/reader2/DExpectFormalArgSsm.cpp +++ b/src/reader2/DExpectFormalArgSsm.cpp @@ -265,7 +265,8 @@ namespace xo { } void - DExpectFormalArgSsm::visit_gco_children(obj) noexcept + DExpectFormalArgSsm::visit_gco_children(VisitReason, + obj) noexcept { static_assert(!DUniqueString::is_gc_eligible()); } diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 6cbf199a..6d68a610 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -358,9 +358,10 @@ namespace xo { } void - DExpectFormalArglistSsm::visit_gco_children(obj gc) noexcept + DExpectFormalArglistSsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_child(&argl_); + gc.visit_child(reason, &argl_); } } /*namespace scm*/ diff --git a/src/reader2/DExpectListTypeSsm.cpp b/src/reader2/DExpectListTypeSsm.cpp index 001ff254..e94e299b 100644 --- a/src/reader2/DExpectListTypeSsm.cpp +++ b/src/reader2/DExpectListTypeSsm.cpp @@ -204,9 +204,10 @@ namespace xo { } void - DExpectListTypeSsm::visit_gco_children(obj gc) noexcept + DExpectListTypeSsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_poly_child(&elt_type_); + gc.visit_poly_child(reason, &elt_type_); } } /*namespace scm*/ diff --git a/src/reader2/DExpectQArraySsm.cpp b/src/reader2/DExpectQArraySsm.cpp index 9e281f8c..97e68228 100644 --- a/src/reader2/DExpectQArraySsm.cpp +++ b/src/reader2/DExpectQArraySsm.cpp @@ -220,9 +220,10 @@ namespace xo { refrtag("array", array_pr)); } void - DExpectQArraySsm::visit_gco_children(obj gc) noexcept + DExpectQArraySsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_child(&array_); + gc.visit_child(reason, &array_); } } diff --git a/src/reader2/DExpectQDictSsm.cpp b/src/reader2/DExpectQDictSsm.cpp index 9839ffd2..4a34d19a 100644 --- a/src/reader2/DExpectQDictSsm.cpp +++ b/src/reader2/DExpectQDictSsm.cpp @@ -267,10 +267,11 @@ namespace xo { void - DExpectQDictSsm::visit_gco_children(obj gc) noexcept + DExpectQDictSsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_child(&key_); - gc.visit_child(&dict_); + gc.visit_child(reason, &key_); + gc.visit_child(reason, &dict_); } } /*namespace scm*/ diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp index 965351c3..5a570caa 100644 --- a/src/reader2/DExpectQListSsm.cpp +++ b/src/reader2/DExpectQListSsm.cpp @@ -215,10 +215,11 @@ namespace xo { refrtag("list", list_pr)); } void - DExpectQListSsm::visit_gco_children(obj gc) noexcept + DExpectQListSsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_child(&start_); - gc.visit_child(&end_); + gc.visit_child(reason, &start_); + gc.visit_child(reason, &end_); } } diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index c49cf565..5265aeb7 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -256,7 +256,7 @@ namespace xo { refrtag("expect", this->get_expect_str())); } void - DExpectQLiteralSsm::visit_gco_children(obj) noexcept + DExpectQLiteralSsm::visit_gco_children(VisitReason, obj) noexcept { // cxl_on_rightparen_, cxl_on_rightbracket_: POD, skip } diff --git a/src/reader2/DExpectSymbolSsm.cpp b/src/reader2/DExpectSymbolSsm.cpp index fa1372b1..6847a776 100644 --- a/src/reader2/DExpectSymbolSsm.cpp +++ b/src/reader2/DExpectSymbolSsm.cpp @@ -146,7 +146,8 @@ namespace xo { ); } void - DExpectSymbolSsm::visit_gco_children(obj) noexcept + DExpectSymbolSsm::visit_gco_children(VisitReason, + obj) noexcept { // no gc-aware members } diff --git a/src/reader2/DExpectTypeSsm.cpp b/src/reader2/DExpectTypeSsm.cpp index 47cc5a6c..7a5d55a3 100644 --- a/src/reader2/DExpectTypeSsm.cpp +++ b/src/reader2/DExpectTypeSsm.cpp @@ -198,7 +198,8 @@ namespace xo { } void - DExpectTypeSsm::visit_gco_children(obj) noexcept + DExpectTypeSsm::visit_gco_children(VisitReason, + obj) noexcept { // corrected_: POD, skip } diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp index 8491c60b..b1eecf37 100644 --- a/src/reader2/DGlobalEnv.cpp +++ b/src/reader2/DGlobalEnv.cpp @@ -114,10 +114,11 @@ namespace xo { } void - DGlobalEnv::visit_gco_children(obj gc) noexcept + DGlobalEnv::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_child(&symtab_); - gc.visit_child(&values_); + gc.visit_child(reason, &symtab_); + gc.visit_child(reason, &values_); } // ----- APrintable facet ----- diff --git a/src/reader2/DIfElseSsm.cpp b/src/reader2/DIfElseSsm.cpp index f4fd4f88..5efd9289 100644 --- a/src/reader2/DIfElseSsm.cpp +++ b/src/reader2/DIfElseSsm.cpp @@ -510,9 +510,10 @@ namespace xo { } void - DIfElseSsm::visit_gco_children(obj gc) noexcept + DIfElseSsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_poly_child(&if_expr_); + gc.visit_poly_child(reason, &if_expr_); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index f0fed420..e39e530b 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -471,15 +471,16 @@ namespace xo { } void - DLambdaSsm::visit_gco_children(obj gc) noexcept + DLambdaSsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_child(&local_symtab_); + gc.visit_child(reason, &local_symtab_); // explicit_return_td not gcobject // lambda_td not gcobject - gc.visit_poly_child(&body_); - gc.visit_poly_child(&parent_symtab_); + gc.visit_poly_child(reason, &body_); + gc.visit_poly_child(reason, &parent_symtab_); } } /*namespace scm*/ diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index 82320cb6..a832bd15 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -459,9 +459,10 @@ namespace xo { } void - DParenSsm::visit_gco_children(obj gc) noexcept + DParenSsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_poly_child(&expr_); + gc.visit_poly_child(reason, &expr_); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 04c87fac..00ce5f61 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -1244,10 +1244,11 @@ case optype::op_assign: } void - DProgressSsm::visit_gco_children(obj gc) noexcept + DProgressSsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_poly_child(&lhs_); - gc.visit_poly_child(&rhs_); + gc.visit_poly_child(reason, &lhs_); + gc.visit_poly_child(reason, &rhs_); } } /*namespace scm*/ diff --git a/src/reader2/DQuoteSsm.cpp b/src/reader2/DQuoteSsm.cpp index cbbedc73..af5d08e3 100644 --- a/src/reader2/DQuoteSsm.cpp +++ b/src/reader2/DQuoteSsm.cpp @@ -212,9 +212,10 @@ namespace xo { } void - DQuoteSsm::visit_gco_children(obj gc) noexcept + DQuoteSsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_poly_child(&expr_); + gc.visit_poly_child(reason, &expr_); } } /*namespace scm*/ diff --git a/src/reader2/DSchematikaParser.cpp b/src/reader2/DSchematikaParser.cpp index fc71d12f..c1a92c5b 100644 --- a/src/reader2/DSchematikaParser.cpp +++ b/src/reader2/DSchematikaParser.cpp @@ -197,9 +197,10 @@ namespace xo { } void - DSchematikaParser::visit_gco_children(obj gc) noexcept + DSchematikaParser::visit_gco_children(VisitReason reason, + obj gc) noexcept { - psm_.visit_gco_children(gc); + psm_.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index a6d4013b..c3517065 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -258,9 +258,10 @@ namespace xo { } void - DSequenceSsm::visit_gco_children(obj gc) noexcept + DSequenceSsm::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_child(&seq_expr_); + gc.visit_child(reason, &seq_expr_); } } /*namespace scm*/ diff --git a/src/reader2/DToplevelSeqSsm.cpp b/src/reader2/DToplevelSeqSsm.cpp index e660f780..cab947b1 100644 --- a/src/reader2/DToplevelSeqSsm.cpp +++ b/src/reader2/DToplevelSeqSsm.cpp @@ -518,7 +518,7 @@ namespace xo { refrtag("seqtype", seqtype_)); } void - DToplevelSeqSsm::visit_gco_children(obj) noexcept + DToplevelSeqSsm::visit_gco_children(VisitReason, obj) noexcept { // seqtype_: POD, skip } diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index a260bdc9..e20b42f6 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -96,7 +96,7 @@ ISyntaxStateMachine_Any::on_quoted_literal(Opaque, obj, ParserStateMa } auto -ISyntaxStateMachine_Any::visit_gco_children(Opaque, obj) -> void +ISyntaxStateMachine_Any::visit_gco_children(Opaque, VisitReason, obj) -> void { _fatal(); } diff --git a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp index 0ecc4e24..0d6146e4 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectExprSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectExprSsm::visit_gco_children(DExpectExprSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectExprSsm::visit_gco_children(DExpectExprSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp index 4db6a480..77bf5f55 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectFormalArglistSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectFormalArglistSsm::visit_gco_children(DExpectFormalArglistSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectFormalArglistSsm::visit_gco_children(DExpectFormalArglistSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp index ea8b14cc..2eb6f6b5 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQArraySsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectQArraySsm::visit_gco_children(DExpectQArraySsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectQArraySsm::visit_gco_children(DExpectQArraySsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp index 363f9646..b0f89a2d 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectQListSsm::visit_gco_children(DExpectQListSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectQListSsm::visit_gco_children(DExpectQListSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp index 61e15926..69f17c50 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectQLiteralSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectQLiteralSsm::visit_gco_children(DExpectQLiteralSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectQLiteralSsm::visit_gco_children(DExpectQLiteralSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp index c1331ceb..ea2b7a0d 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectSymbolSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectSymbolSsm::visit_gco_children(DExpectSymbolSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectSymbolSsm::visit_gco_children(DExpectSymbolSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp index 8daed04c..e107f011 100644 --- a/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DExpectTypeSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectTypeSsm::visit_gco_children(DExpectTypeSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectTypeSsm::visit_gco_children(DExpectTypeSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp index 42a199cb..f67e77c8 100644 --- a/src/reader2/ISyntaxStateMachine_DParenSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DParenSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DParenSsm::visit_gco_children(DParenSsm & self, obj gc) -> void + ISyntaxStateMachine_DParenSsm::visit_gco_children(DParenSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp index 9c5ad07d..5ad51fe2 100644 --- a/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DProgressSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DProgressSsm::visit_gco_children(DProgressSsm & self, obj gc) -> void + ISyntaxStateMachine_DProgressSsm::visit_gco_children(DProgressSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp index a6375288..8dff7fa0 100644 --- a/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DSequenceSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DSequenceSsm::visit_gco_children(DSequenceSsm & self, obj gc) -> void + ISyntaxStateMachine_DSequenceSsm::visit_gco_children(DSequenceSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp index 47788590..ba17482f 100644 --- a/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp +++ b/src/reader2/ISyntaxStateMachine_DToplevelSeqSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DToplevelSeqSsm::visit_gco_children(DToplevelSeqSsm & self, obj gc) -> void + ISyntaxStateMachine_DToplevelSeqSsm::visit_gco_children(DToplevelSeqSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/ParserResult.cpp b/src/reader2/ParserResult.cpp index 609f204f..bb3d4034 100644 --- a/src/reader2/ParserResult.cpp +++ b/src/reader2/ParserResult.cpp @@ -106,12 +106,13 @@ namespace xo { } void - ParserResult::visit_gco_children(obj gc) noexcept + ParserResult::visit_gco_children(VisitReason reason, + obj gc) noexcept { // {result_type_, error_src_fn_}: pod, ignore - gc.visit_poly_child(&result_expr_); - gc.visit_child(&error_description_); + gc.visit_poly_child(reason, &result_expr_); + gc.visit_child(reason, &error_description_); } } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/ParserStack.cpp b/src/reader2/ParserStack.cpp index 721b19b4..83d21df1 100644 --- a/src/reader2/ParserStack.cpp +++ b/src/reader2/ParserStack.cpp @@ -90,14 +90,15 @@ namespace xo { } void - ParserStack::visit_gco_children(obj gc) noexcept + ParserStack::visit_gco_children(VisitReason reason, + obj gc) noexcept { for (ParserStack * target = this; target; target = target->parent_) { // ParserStack::ckp: skip, POD if (target->ssm_) - target->ssm_.visit_gco_children(gc); + target->ssm_.visit_gco_children(reason, gc); } } diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 6bec1833..71028ebe 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -907,7 +907,8 @@ namespace xo { #endif void - ParserStateMachine::visit_gco_children(obj gc) noexcept + ParserStateMachine::visit_gco_children(VisitReason reason, + obj gc) noexcept { //scope log(XO_DEBUG(true)); @@ -916,23 +917,23 @@ namespace xo { //log && log("forward stack_", xtag("addr", stack_)); if (stack_) { - stack_->visit_gco_children(gc); + stack_->visit_gco_children(reason, gc); } // static_assert(!expr_alloc_.is_gc_eligible()); // static_assert(!aux_alloc_.is_gc_eligible()); //log && log("global_symtab_", xtag("addr", global_symtab_.data())); - gc.visit_child(&global_symtab_); + gc.visit_child(reason, &global_symtab_); //log && log("local_symtab_", xtag("addr", local_symtab_.data())); - gc.visit_child(&local_symtab_); + gc.visit_child(reason, &local_symtab_); //log && log("global_env_", xtag("addr", global_env_.data())); - gc.visit_child(&global_env_); + gc.visit_child(reason, &global_env_); //log && log("result_"); - result_.visit_gco_children(gc); + result_.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/SchematikaReader.cpp b/src/reader2/SchematikaReader.cpp index c9405916..168f562a 100644 --- a/src/reader2/SchematikaReader.cpp +++ b/src/reader2/SchematikaReader.cpp @@ -10,9 +10,10 @@ namespace xo { namespace scm { void - ReaderResult::visit_gco_children(obj gc) noexcept + ReaderResult::visit_gco_children(VisitReason reason, + obj gc) noexcept { - gc.visit_poly_child(&expr_); + gc.visit_poly_child(reason, &expr_); } // ----- SchematikaReader ----- @@ -208,12 +209,13 @@ namespace xo { } void - SchematikaReader::visit_gco_children(obj gc) noexcept + SchematikaReader::visit_gco_children(VisitReason reason, + obj gc) noexcept { // tokenizer doesn't contain any gc-aware pointers. - parser_.visit_gco_children(gc); - result_.visit_gco_children(gc); + parser_.visit_gco_children(reason, gc); + result_.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/IGCObject_DGlobalEnv.cpp b/src/reader2/facet/IGCObject_DGlobalEnv.cpp index 9a2802ae..72c9b065 100644 --- a/src/reader2/facet/IGCObject_DGlobalEnv.cpp +++ b/src/reader2/facet/IGCObject_DGlobalEnv.cpp @@ -21,9 +21,9 @@ namespace xo { return self.gco_shallow_move(gc); } auto - IGCObject_DGlobalEnv::visit_gco_children(DGlobalEnv & self, obj fn) noexcept -> void + IGCObject_DGlobalEnv::visit_gco_children(DGlobalEnv & self, VisitReason reason, obj fn) noexcept -> void { - self.visit_gco_children(fn); + self.visit_gco_children(reason, fn); } } /*namespace scm*/ diff --git a/src/reader2/facet/IGCObject_DSchematikaParser.cpp b/src/reader2/facet/IGCObject_DSchematikaParser.cpp index f1778d5a..7586fc25 100644 --- a/src/reader2/facet/IGCObject_DSchematikaParser.cpp +++ b/src/reader2/facet/IGCObject_DSchematikaParser.cpp @@ -21,9 +21,9 @@ namespace xo { return self.gco_shallow_move(gc); } auto - IGCObject_DSchematikaParser::visit_gco_children(DSchematikaParser & self, obj fn) noexcept -> void + IGCObject_DSchematikaParser::visit_gco_children(DSchematikaParser & self, VisitReason reason, obj fn) noexcept -> void { - self.visit_gco_children(fn); + self.visit_gco_children(reason, fn); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp index 01f685fe..baba1c7f 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DApplySsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DApplySsm::visit_gco_children(DApplySsm & self, obj gc) -> void + ISyntaxStateMachine_DApplySsm::visit_gco_children(DApplySsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp index 886155c0..5fe37536 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DDefineSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DDefineSsm::visit_gco_children(DDefineSsm & self, obj gc) -> void + ISyntaxStateMachine_DDefineSsm::visit_gco_children(DDefineSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp index 874849ff..a88b1005 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DDeftypeSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DDeftypeSsm::visit_gco_children(DDeftypeSsm & self, obj gc) -> void + ISyntaxStateMachine_DDeftypeSsm::visit_gco_children(DDeftypeSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp index 85f8dd7a..c0adc804 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectFormalArgSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectFormalArgSsm::visit_gco_children(DExpectFormalArgSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectFormalArgSsm::visit_gco_children(DExpectFormalArgSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp index d3b292ad..1306e061 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectListTypeSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectListTypeSsm::visit_gco_children(DExpectListTypeSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectListTypeSsm::visit_gco_children(DExpectListTypeSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp index 9f4d74cc..5cc75b00 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DExpectQDictSsm::visit_gco_children(DExpectQDictSsm & self, obj gc) -> void + ISyntaxStateMachine_DExpectQDictSsm::visit_gco_children(DExpectQDictSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp index 68034ba4..37a20363 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DIfElseSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DIfElseSsm::visit_gco_children(DIfElseSsm & self, obj gc) -> void + ISyntaxStateMachine_DIfElseSsm::visit_gco_children(DIfElseSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp index 88e52100..08754857 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DLambdaSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DLambdaSsm::visit_gco_children(DLambdaSsm & self, obj gc) -> void + ISyntaxStateMachine_DLambdaSsm::visit_gco_children(DLambdaSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ diff --git a/src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp index 39d26414..b4ee1261 100644 --- a/src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp +++ b/src/reader2/facet/ISyntaxStateMachine_DQuoteSsm.cpp @@ -78,9 +78,9 @@ namespace xo { self.on_quoted_literal(lit, p_psm); } auto - ISyntaxStateMachine_DQuoteSsm::visit_gco_children(DQuoteSsm & self, obj gc) -> void + ISyntaxStateMachine_DQuoteSsm::visit_gco_children(DQuoteSsm & self, VisitReason reason, obj gc) -> void { - self.visit_gco_children(gc); + self.visit_gco_children(reason, gc); } } /*namespace scm*/ From 32fea42633d960d0fc904b0c33464e69cae3334e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 11 Apr 2026 16:51:52 -0400 Subject: [PATCH 336/342] xo-gc: bugfixes for GCObjectStore, unit test exapnded In particular: drop casual assignment to DList.rest_, will break acyclic assumption of DList.size() --- src/reader2/DExpectQListSsm.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp index 5a570caa..184bcc41 100644 --- a/src/reader2/DExpectQListSsm.cpp +++ b/src/reader2/DExpectQListSsm.cpp @@ -182,7 +182,9 @@ namespace xo { = DList::_cons(p_psm->expr_alloc(), lit, DList::_nil()); if (this->end_) { - end_->assign_rest(new_last); + /* DExpectQListSsm owns {start_, end_} -> preserves acyclic property */ + + end_->_assign_rest(new_last); this->end_ = new_last; } else { From df32ec55c869a9b1405cdd2439741640bbd4d2c0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 28 Apr 2026 23:17:00 -0400 Subject: [PATCH 337/342] xo-object2: obj argument to DArray::push_back() --- src/reader2/DApplySsm.cpp | 10 ++++++---- src/reader2/DExpectFormalArglistSsm.cpp | 13 +++++++++---- src/reader2/DExpectQArraySsm.cpp | 9 ++++++--- src/reader2/DGlobalEnv.cpp | 2 +- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index ef84187b..5c4802cc 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -15,6 +15,7 @@ //#include "expect_expr_xs.hpp" namespace xo { + using xo::mm::ACollector; using xo::mm::AGCObject; using xo::print::APrintable; using xo::reflect::typeseq; @@ -73,7 +74,7 @@ namespace xo { * * See similar code in DExpectFormalArglistSsm::_make */ - DArray * args = DArray::empty(mm, 8); + DArray * args = DArray::_empty(mm, 8); applyexprstatetype applystate = (fn_expr @@ -232,23 +233,24 @@ namespace xo { assert(expr_gco); obj mm(&(p_psm->parser_alloc())); + auto gc = obj(mm).try_to_facet(); if (args_expr_v_->size() == args_expr_v_->capacity()) { // need to expand .args_expr_v_ capacity. // Could use DArena checkpoint to redo this in place, // since argument array must be on the top of the stack. - DArray * argv_2x = DArray::empty(mm, 2 * args_expr_v_->capacity()); + DArray * argv_2x = DArray::_empty(mm, 2 * args_expr_v_->capacity()); for (DArray::size_type i = 0, n = args_expr_v_->size(); i < n; ++i) { - argv_2x->push_back((*args_expr_v_)[i]); + argv_2x->push_back(gc, (*args_expr_v_)[i]); } this->args_expr_v_ = argv_2x; } if (args_expr_v_->size() < args_expr_v_->capacity()) - args_expr_v_->push_back(expr_gco); + args_expr_v_->push_back(gc, expr_gco); if (tk.tk_type() == tokentype::tk_rightparen) { obj apply_ex = this->assemble_expr(p_psm->expr_alloc()); diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 6d68a610..18531816 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -17,6 +17,7 @@ namespace xo { using xo::print::APrintable; using xo::print::ppstate; using xo::print::ppindentinfo; + using xo::mm::ACollector; using xo::mm::AGCObject; using xo::mm::AAllocator; using xo::facet::FacetRegistry; @@ -61,7 +62,7 @@ namespace xo { /* allocate room for 8 arguments (during parsing) * will re-alloc to expand as needed */ - DArray * argl = DArray::empty(mm, 8); + DArray * argl = DArray::_empty(mm, 8); return new (mem) DExpectFormalArglistSsm(argl); } @@ -198,18 +199,22 @@ namespace xo { // could do this in place since this SSM is at the top of the parser stack. obj mm(&parser_alloc); - DArray * argl_2x = DArray::empty(mm, 2 * argl_->capacity()); + DArray * argl_2x = DArray::_empty(mm, 2 * argl_->capacity()); + + auto gc = obj(mm).try_to_facet(); for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { // TODO: prefer non-bounds-checked access here - argl_2x->push_back(argl_->at(i)); + argl_2x->push_back(gc, argl_->at(i)); } // update in place this->argl_ = argl_2x; } - this->argl_->push_back(var_o); + auto gc = expr_alloc.try_to_facet(); + + this->argl_->push_back(gc, var_o); } void diff --git a/src/reader2/DExpectQArraySsm.cpp b/src/reader2/DExpectQArraySsm.cpp index 97e68228..1d09b154 100644 --- a/src/reader2/DExpectQArraySsm.cpp +++ b/src/reader2/DExpectQArraySsm.cpp @@ -13,6 +13,7 @@ namespace xo { using xo::print::APrintable; using xo::facet::FacetRegistry; + using xo::mm::ACollector; using xo::mm::AGCObject; namespace scm { @@ -142,8 +143,8 @@ namespace xo { if (state_.code() == QArrayXst::code::qarray_0) { this->state_ = QArrayXst(QArrayXst::code::qarray_1a); - this->array_ = DArray::empty(p_psm->expr_alloc(), - 8 /*heuristic starting capacity*/); + this->array_ = DArray::_empty(p_psm->expr_alloc(), + 8 /*heuristic starting capacity*/); DExpectQLiteralSsm::start(p_psm, false /*cxl_on_rightparen*/, @@ -177,6 +178,8 @@ namespace xo { DExpectQArraySsm::on_quoted_literal(obj lit, ParserStateMachine * p_psm) { + auto gc = p_psm->expr_alloc().try_to_facet(); + if(state_.code() == QArrayXst::code::qarray_1a) { // append lit at the end of array_ { @@ -192,7 +195,7 @@ namespace xo { 2 * array_->capacity()); } - bool ok = array_->push_back(lit); + bool ok = array_->push_back(gc, lit); assert(ok); } diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp index b1eecf37..2fc2e881 100644 --- a/src/reader2/DGlobalEnv.cpp +++ b/src/reader2/DGlobalEnv.cpp @@ -21,7 +21,7 @@ namespace xo { DGlobalEnv::_make(obj mm, DGlobalSymtab * symtab) { - DArray * values = DArray::empty(mm, symtab->var_capacity()); + DArray * values = DArray::_empty(mm, symtab->var_capacity()); void * mem = mm.alloc_for(); From 3d24a523f3b5580c8cf48a680003a7d89ffe8ea6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 1 May 2026 19:54:26 -0400 Subject: [PATCH 338/342] refactor focusing on xo-alloc2/ xo-gc/ write-barrier ability to inform allocator of gco->gco mutation, via AAllocator i/face. --- src/reader2/DApplySsm.cpp | 6 +++--- src/reader2/DExpectFormalArglistSsm.cpp | 8 ++++---- src/reader2/DExpectQArraySsm.cpp | 4 ++-- src/reader2/DGlobalEnv.cpp | 8 ++++++-- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index 5c4802cc..ee043ddd 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -233,7 +233,7 @@ namespace xo { assert(expr_gco); obj mm(&(p_psm->parser_alloc())); - auto gc = obj(mm).try_to_facet(); + //auto gc = obj(mm).try_to_facet(); if (args_expr_v_->size() == args_expr_v_->capacity()) { // need to expand .args_expr_v_ capacity. @@ -243,14 +243,14 @@ namespace xo { DArray * argv_2x = DArray::_empty(mm, 2 * args_expr_v_->capacity()); for (DArray::size_type i = 0, n = args_expr_v_->size(); i < n; ++i) { - argv_2x->push_back(gc, (*args_expr_v_)[i]); + argv_2x->push_back(mm, (*args_expr_v_)[i]); } this->args_expr_v_ = argv_2x; } if (args_expr_v_->size() < args_expr_v_->capacity()) - args_expr_v_->push_back(gc, expr_gco); + args_expr_v_->push_back(mm, expr_gco); if (tk.tk_type() == tokentype::tk_rightparen) { obj apply_ex = this->assemble_expr(p_psm->expr_alloc()); diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 18531816..3d86158c 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -201,20 +201,20 @@ namespace xo { obj mm(&parser_alloc); DArray * argl_2x = DArray::_empty(mm, 2 * argl_->capacity()); - auto gc = obj(mm).try_to_facet(); + //auto gc = obj(mm).try_to_facet(); for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { // TODO: prefer non-bounds-checked access here - argl_2x->push_back(gc, argl_->at(i)); + argl_2x->push_back(mm, argl_->at(i)); } // update in place this->argl_ = argl_2x; } - auto gc = expr_alloc.try_to_facet(); + //auto gc = expr_alloc.try_to_facet(); - this->argl_->push_back(gc, var_o); + this->argl_->push_back(expr_alloc, var_o); } void diff --git a/src/reader2/DExpectQArraySsm.cpp b/src/reader2/DExpectQArraySsm.cpp index 1d09b154..eda20eb2 100644 --- a/src/reader2/DExpectQArraySsm.cpp +++ b/src/reader2/DExpectQArraySsm.cpp @@ -178,7 +178,7 @@ namespace xo { DExpectQArraySsm::on_quoted_literal(obj lit, ParserStateMachine * p_psm) { - auto gc = p_psm->expr_alloc().try_to_facet(); + //auto gc = p_psm->expr_alloc().try_to_facet(); if(state_.code() == QArrayXst::code::qarray_1a) { // append lit at the end of array_ @@ -195,7 +195,7 @@ namespace xo { 2 * array_->capacity()); } - bool ok = array_->push_back(gc, lit); + bool ok = array_->push_back(p_psm->expr_alloc(), lit); assert(ok); } diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp index 2fc2e881..c1caf833 100644 --- a/src/reader2/DGlobalEnv.cpp +++ b/src/reader2/DGlobalEnv.cpp @@ -8,6 +8,7 @@ #include namespace xo { + using xo::mm::ACollector; using xo::mm::AAllocator; using xo::mm::AGCObject; @@ -84,8 +85,11 @@ namespace xo { values_->resize(ix.j_slot() + 1); } - log && log("STUB: need write barrier for GC here"); - (*values_)[ix.j_slot()] = x; + //auto gc = mm.try_to_facet(); + + values_->assign_at(mm, + ix.j_slot(), + x); } DVariable * From 866b6a55e2fecdf9308e62b5980f0421b347c90c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 1 May 2026 20:38:38 -0400 Subject: [PATCH 339/342] xo-object2: streamline write barriers for DList,DArray muts --- src/reader2/DExpectQListSsm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp index 184bcc41..8ea243ca 100644 --- a/src/reader2/DExpectQListSsm.cpp +++ b/src/reader2/DExpectQListSsm.cpp @@ -184,7 +184,7 @@ namespace xo { if (this->end_) { /* DExpectQListSsm owns {start_, end_} -> preserves acyclic property */ - end_->_assign_rest(new_last); + end_->_assign_rest(p_psm->expr_alloc(), new_last); this->end_ = new_last; } else { From 2713050d8438ca6aecf1622695b44fa1fe8ef763 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 2 May 2026 13:49:29 -0400 Subject: [PATCH 340/342] xo-gc stack: refactor + streamline. Retiring unused Collector typealiases. Fix #include topology. Fix/improve write barrier setup. --- include/xo/reader2/env/IGCObject_DGlobalEnv.hpp | 1 - include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp | 1 - include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp | 8 ++++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp index 8efa3c27..b8fb15f0 100644 --- a/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp +++ b/include/xo/reader2/env/IGCObject_DGlobalEnv.hpp @@ -43,7 +43,6 @@ namespace xo { ///@{ using size_type = xo::mm::AGCObject::size_type; using AAllocator = xo::mm::AGCObject::AAllocator; - using ACollector = xo::mm::AGCObject::ACollector; using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; using VisitReason = xo::mm::AGCObject::VisitReason; using Copaque = xo::mm::AGCObject::Copaque; diff --git a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp index 586678cd..0143ba76 100644 --- a/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp +++ b/include/xo/reader2/parser/IGCObject_DSchematikaParser.hpp @@ -43,7 +43,6 @@ namespace xo { ///@{ using size_type = xo::mm::AGCObject::size_type; using AAllocator = xo::mm::AGCObject::AAllocator; - using ACollector = xo::mm::AGCObject::ACollector; using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; using VisitReason = xo::mm::AGCObject::VisitReason; using Copaque = xo::mm::AGCObject::Copaque; diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index 1d971d3b..e0c3bee5 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -9,10 +9,18 @@ * [iface_facet_any.hpp.j2] * 3. idl for facet methods * [idl/SyntaxStateMachine.json5] + * + * variables: + * {facet_hpp_fname} -> SyntaxStateMachine.hpp + * {impl_hpp_subdir} -> ssm + * {facet_ns1} -> xo + * {facet_detail_subdir} -> ssm + * {abstract_facet_fname} -> ASyntaxStateMachine.hpp **/ #pragma once +#include "ASyntaxStateMachine.hpp" #include "ParserStateMachine.hpp" #include "syntaxstatetype.hpp" #include From 6068da02affac88616368f413b44307f4ed4dfa1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 2 May 2026 13:58:22 -0400 Subject: [PATCH 341/342] tidy: drop stale ACollector comments --- src/reader2/DApplySsm.cpp | 1 - src/reader2/DExpectFormalArglistSsm.cpp | 4 ---- src/reader2/DExpectQArraySsm.cpp | 2 -- src/reader2/DGlobalEnv.cpp | 2 -- 4 files changed, 9 deletions(-) diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index ee043ddd..0a616e9a 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -233,7 +233,6 @@ namespace xo { assert(expr_gco); obj mm(&(p_psm->parser_alloc())); - //auto gc = obj(mm).try_to_facet(); if (args_expr_v_->size() == args_expr_v_->capacity()) { // need to expand .args_expr_v_ capacity. diff --git a/src/reader2/DExpectFormalArglistSsm.cpp b/src/reader2/DExpectFormalArglistSsm.cpp index 3d86158c..7036ffb5 100644 --- a/src/reader2/DExpectFormalArglistSsm.cpp +++ b/src/reader2/DExpectFormalArglistSsm.cpp @@ -201,8 +201,6 @@ namespace xo { obj mm(&parser_alloc); DArray * argl_2x = DArray::_empty(mm, 2 * argl_->capacity()); - //auto gc = obj(mm).try_to_facet(); - for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { // TODO: prefer non-bounds-checked access here argl_2x->push_back(mm, argl_->at(i)); @@ -212,8 +210,6 @@ namespace xo { this->argl_ = argl_2x; } - //auto gc = expr_alloc.try_to_facet(); - this->argl_->push_back(expr_alloc, var_o); } diff --git a/src/reader2/DExpectQArraySsm.cpp b/src/reader2/DExpectQArraySsm.cpp index eda20eb2..b06920c4 100644 --- a/src/reader2/DExpectQArraySsm.cpp +++ b/src/reader2/DExpectQArraySsm.cpp @@ -178,8 +178,6 @@ namespace xo { DExpectQArraySsm::on_quoted_literal(obj lit, ParserStateMachine * p_psm) { - //auto gc = p_psm->expr_alloc().try_to_facet(); - if(state_.code() == QArrayXst::code::qarray_1a) { // append lit at the end of array_ { diff --git a/src/reader2/DGlobalEnv.cpp b/src/reader2/DGlobalEnv.cpp index c1caf833..0343d2c2 100644 --- a/src/reader2/DGlobalEnv.cpp +++ b/src/reader2/DGlobalEnv.cpp @@ -85,8 +85,6 @@ namespace xo { values_->resize(ix.j_slot() + 1); } - //auto gc = mm.try_to_facet(); - values_->assign_at(mm, ix.j_slot(), x); From adba8536d98358a60a438fcbd0c7c4c73c72c0a4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 7 May 2026 23:44:32 -0400 Subject: [PATCH 342/342] xo-gc stack: fix mutation setup + xo-reader2 utest --- src/reader2/DDefineSsm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 0e38f93d..59388820 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -466,7 +466,7 @@ namespace xo { DDefineSsm::on_parsed_typedescr(TypeDescr td, ParserStateMachine * p_psm) { - scope log(XO_DEBUG(true), xtag("td", td)); + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("td", td)); if (defstate_ == defexprstatetype::def_3) { this->defstate_ = defexprstatetype::def_4;