2957 lines
171 KiB
Lua
2957 lines
171 KiB
Lua
--[[
|
|
Literate Pandoc & Fennel Bundle:
|
|
A Pandoc filter for literate and natural programming
|
|
Fennel:
|
|
(C) 2016-2023 Calvin Rose and contributors
|
|
License: MIT License https://git.sr.ht/~technomancy/fennel/tree/main/item/LICENSE
|
|
Source: https://sr.ht/~technomancy/fennel or https://github.com/bakpakin/Fennel/issues
|
|
Website: https://fennel-lang.org
|
|
Literate Pandoc:
|
|
(C) 2023 perro hi@perrotuerto.blog
|
|
License: GPLv3 https://git.cuates.net/perro/literate-pandoc/src/branch/no-masters/LICENSE.txt
|
|
Source: https://git.cuates.net/perro/literate-pandoc
|
|
The following code is minified, check Literate Pandoc source for a readable version
|
|
]]--
|
|
|
|
package.preload["fennel.repl"]=package.preload["fennel.repl"]or
|
|
function(...)
|
|
local o=require("fennel.utils")local UesS=require("fennel.parser")
|
|
local CZ=require("fennel.compiler")local iD90MK=require("fennel.specials")
|
|
local ZuYO=require("fennel.view")local j=(table.unpack or _G.unpack)
|
|
local function t(aBv0K6z)
|
|
local function GI()if(0 <
|
|
aBv0K6z["stack-size"])then return".."else return">> "end end;io.write(GI())io.flush()local nsm9=io.read()return
|
|
(nsm9 and(nsm9 .."\n"))end;local function NChC(kO)io.write(table.concat(kO,"\9"))
|
|
return io.write("\n")end
|
|
local function Z4(FIHZeLmK,Gho7Jfcz,pi3tYW)
|
|
local function nt()local R7iAD=FIHZeLmK
|
|
if
|
|
(R7iAD=="Lua Compile")then return
|
|
("Bad code generated - likely a bug with the compiler:\n".."--- Generated Lua Start ---\n"..
|
|
pi3tYW.."--- Generated Lua End ---\n")elseif(R7iAD==
|
|
"Runtime")then return
|
|
(CZ.traceback(tostring(Gho7Jfcz),4).."\n")elseif true then local Re6P_=R7iAD;return
|
|
("%s error: %s\n"):format(FIHZeLmK,tostring(Gho7Jfcz))else return nil end end;return io.write(nt())end
|
|
local function I13Z9(VNtfqHq,wB,cmQxB1bj)local aozwWK
|
|
do local G0AXlB={}local Pv=#G0AXlB
|
|
for HW in pairs(VNtfqHq.___replLocals___)do
|
|
local cWzY=("local %s = ___replLocals___['%s']"):format(HW,HW)
|
|
if(nil~=cWzY)then Pv=(Pv+1)do end(G0AXlB)[Pv]=cWzY else end end;aozwWK=G0AXlB end;local GbnuD
|
|
do local ESO={}local DEb=#ESO
|
|
for Uzk3,LVrOH0 in pairs(cmQxB1bj.manglings)do local YLRWb;if not
|
|
cmQxB1bj.gensyms[LVrOH0]then
|
|
YLRWb=("___replLocals___['%s'] = %s"):format(LVrOH0,LVrOH0)else YLRWb=nil end;if
|
|
(nil~=YLRWb)then DEb=(DEb+1)do end(ESO)[DEb]=YLRWb else end end;GbnuD=ESO end;local CW2;if wB:find("\n")then CW2="\n"else CW2=" "end;local function vlSSXJ()
|
|
if next(aozwWK)then return(
|
|
table.concat(aozwWK," ")..CW2)else return""end end
|
|
local function k()
|
|
local u6sl,F=wB:match("^(.*)[\n ](return .*)$")
|
|
if((nil~=u6sl)and(nil~=F))then local fgPC0lUc=u6sl;local oRfi=F;return
|
|
(fgPC0lUc..CW2 ..
|
|
table.concat(GbnuD," ")..CW2 ..oRfi)elseif true then local CrAGWh=u6sl;return wB else return nil end end;return(vlSSXJ()..k())end
|
|
local function tj(d,sCjf4,y)local P=2000;local Av={}local nw={}local OVuV52eb=y:gsub(".*[%s)(]+","")local c=false
|
|
local function Td(yqTH,gcTeY,Ce)
|
|
local QzyH5hCR=(
|
|
(gcTeY==d)or(gcTeY==d.___replLocals___))local hYkd7=nw;local UKZpzj=#hYkd7;local function Fniffr()
|
|
if QzyH5hCR then return sCjf4.manglings else return gcTeY end end
|
|
for FMt_pX,ouz in o.allpairs(Fniffr())do if
|
|
(P<=#nw)then break end;local K1TX5
|
|
do local BYnM1VtZ
|
|
if QzyH5hCR then BYnM1VtZ=ouz else BYnM1VtZ=FMt_pX end
|
|
if
|
|
(
|
|
(type(FMt_pX)=="string")and
|
|
(yqTH==FMt_pX:sub(0,#yqTH))and not Av[FMt_pX]and((":"~=Ce:sub(-1))or
|
|
("function"==type(gcTeY[BYnM1VtZ]))))then Av[FMt_pX]=true;K1TX5=(Ce..FMt_pX)else K1TX5=nil end end
|
|
if(nil~=K1TX5)then UKZpzj=(UKZpzj+1)do end(hYkd7)[UKZpzj]=K1TX5 else end end;return hYkd7 end
|
|
local function KlzsEvn(djzP,b_,Q1w1zKw,a5F,Ue0N)local L99;if Ue0N then L99="^([^:]+):(.*)"else L99="^([^.]+)%.(.*)"end
|
|
local B3,PL7_Dl=djzP:match(L99)local N8V=(sCjf4.manglings[B3]or B3)
|
|
if(
|
|
type(b_[N8V])=="table")then c=true;if Ue0N then return
|
|
Td(PL7_Dl,b_[N8V],(Q1w1zKw..B3 ..":"))else
|
|
return a5F(PL7_Dl,b_[N8V],(Q1w1zKw..B3))end else return nil end end
|
|
local function eOfvjl1(b,kCfK5,TJ5Kz5NO)local Pke1T8
|
|
if TJ5Kz5NO then Pke1T8=(TJ5Kz5NO..".")else Pke1T8=""end
|
|
if(not b:find("%.")and b:find(":"))then return
|
|
KlzsEvn(b,kCfK5,Pke1T8,eOfvjl1,true)elseif not b:find("%.")then return Td(b,kCfK5,Pke1T8)else return
|
|
KlzsEvn(b,kCfK5,Pke1T8,eOfvjl1,false)end end
|
|
for HKyO,mx in
|
|
ipairs({sCjf4.specials,sCjf4.macros,(d.___replLocals___ or{}),d,d._G})do if c then break end;eOfvjl1(OVuV52eb,mx)end;return nw end;local EgG={}local function YgsJ(od)return od:match("^%s*,")end
|
|
local function aV1Rus()local iRgs
|
|
do
|
|
local KYSkMOxM9={}local m1=#KYSkMOxM9
|
|
for L,uApola2 in pairs(EgG)do
|
|
local jbLeA=(" ,%s - %s"):format(L,(
|
|
(CZ.metadata):get(uApola2,"fnl/docstring")or"undocumented"))
|
|
if(nil~=jbLeA)then m1=(m1+1)do end(KYSkMOxM9)[m1]=jbLeA else end end;iRgs=KYSkMOxM9 end;return table.concat(iRgs,"\n")end
|
|
EgG.help=function(Jy,KDEqSly,w2hBXVO)
|
|
return
|
|
w2hBXVO({("Welcome to Fennel.\nThis is the REPL where you can enter code to be evaluated.\nYou can also run these repl commands:\n\n"..
|
|
|
|
aV1Rus()..
|
|
"\n ,exit - Leave the repl.\n\nUse ,doc something to see descriptions for individual macros and special forms.\n\nFor more information about the language, see https://fennel-lang.org/reference")})end;do end
|
|
(CZ.metadata):set(EgG.help,"fnl/docstring","Show this message.")
|
|
local function Gsx955(Q,c9MGuH,aOuScj,XXtE6Ji)
|
|
local J,oyvqbnx=pcall(iD90MK["load-code"]("return require(...)",c9MGuH),Q)
|
|
if((J==true)and(nil~=oyvqbnx))then local YdCSDvl=oyvqbnx;local Cum;package.loaded[Q]=
|
|
nil;Cum=nil;local Je_,x=pcall(require,Q)local _nbhL;if not Je_ then aOuScj({x})
|
|
_nbhL=YdCSDvl else _nbhL=x end
|
|
iD90MK["macro-loaded"][Q]=nil
|
|
if
|
|
((type(YdCSDvl)=="table")and(type(_nbhL)=="table"))then
|
|
for VJ_RQcYw,bgDxqiW in pairs(_nbhL)do YdCSDvl[VJ_RQcYw]=bgDxqiW end;for u in pairs(YdCSDvl)do
|
|
if(nil== (_nbhL)[u])then YdCSDvl[u]=nil else end end;package.loaded[Q]=YdCSDvl else end;return aOuScj({"ok"})elseif
|
|
((J==false)and(nil~=oyvqbnx))then local n_=oyvqbnx
|
|
if n_:match("loop or previous error loading module")then package.loaded[Q]=
|
|
nil;return Gsx955(Q,c9MGuH,aOuScj,XXtE6Ji)elseif
|
|
(iD90MK["macro-loaded"])[Q]then iD90MK["macro-loaded"][Q]=nil;return nil else local function a()
|
|
local xei=n_:gsub("\n.*","")return xei end;return XXtE6Ji("Runtime",a())end else return nil end end
|
|
local function _bh_k(zHHW,H,OQYu)local k9,bRREug,R_RJfoeP=pcall(zHHW)
|
|
if((k9 ==true)and(bRREug==true)and(nil~=
|
|
R_RJfoeP))then
|
|
local HuvPsV=R_RJfoeP;return OQYu(HuvPsV)elseif(k9 ==false)then
|
|
return H("Parse","Couldn't parse input.")else return nil end end
|
|
EgG.reload=function(pZ8,J12U,jzU,nrU)
|
|
local function Bi7(EW4bXR)return Gsx955(tostring(EW4bXR),pZ8,jzU,nrU)end;return _bh_k(J12U,nrU,Bi7)end;do end
|
|
(CZ.metadata):set(EgG.reload,"fnl/docstring","Reload the specified module.")
|
|
EgG.reset=function(vL_Vj_v,fi3,hbfOHU)vL_Vj_v.___replLocals___={}return hbfOHU({"ok"})end;do end
|
|
(CZ.metadata):set(EgG.reset,"fnl/docstring","Erase all repl-local scope.")
|
|
EgG.complete=function(GpItItxe,O,Equz,dsN,HzKU,Zbl8)
|
|
local function I_iWZE2I()return
|
|
Equz(tj(GpItItxe,HzKU,string.char(j(Zbl8)):gsub(",complete +",""):sub(1,
|
|
-2)))end;return _bh_k(O,dsN,I_iWZE2I)end;do end
|
|
(CZ.metadata):set(EgG.complete,"fnl/docstring","Print all possible completions for a given input symbol.")
|
|
local function w7(c5q,iXFMywMG,a,RgyIZgQm,Kz)
|
|
for hncJ5,oMSPa in pairs(iXFMywMG)do
|
|
if
|
|
(("string"==type(hncJ5))and(package~=oMSPa))then local _pJ7=type(oMSPa)
|
|
if(_pJ7 =="function")then
|
|
if
|
|
((a..hncJ5)):match(c5q)then table.insert(Kz,(a..hncJ5))else end elseif(_pJ7 =="table")then if not RgyIZgQm[oMSPa]then local sa6R;do local gH=RgyIZgQm
|
|
gH[oMSPa]=true;sa6R=gH end
|
|
w7(c5q,oMSPa,(a..hncJ5:gsub("%.","/").."."),sa6R,Kz)else end else end else end end;return Kz end
|
|
local function drEf10P(mRsiV)local PbSET=w7(mRsiV,package.loaded,"",{},{})local hpVB={}
|
|
local YWvn1scCO=#hpVB
|
|
for _u9Y,_BGX in ipairs(PbSET)do local m4bfrLhD=_BGX:gsub("^_G%.","")
|
|
if(nil~=m4bfrLhD)then YWvn1scCO=(
|
|
YWvn1scCO+1)do end(hpVB)[YWvn1scCO]=m4bfrLhD else end end;return hpVB end
|
|
EgG.apropos=function(phlgUmyq,y1uQkA,n_b,X5Kb,IjSJ6)
|
|
local function nDieWGG(P)return n_b(drEf10P(tostring(P)))end;return _bh_k(y1uQkA,X5Kb,nDieWGG)end;do end
|
|
(CZ.metadata):set(EgG.apropos,"fnl/docstring","Print all functions matching a pattern in all loaded modules.")
|
|
local function U9bX9Qj(_li)local VgksUV
|
|
do local egVOS={}local L7hI7N16=#egVOS;for d in _li:gmatch("[^%.]+")do local H0J=d
|
|
if(nil~=H0J)then L7hI7N16=(
|
|
L7hI7N16+1)do end(egVOS)[L7hI7N16]=H0J else end end;VgksUV=egVOS end;local lD8E0=package.loaded
|
|
for oLsc,qXd in ipairs(VgksUV)do if(nil==lD8E0)then break end;local cZ8mW;do
|
|
local U=qXd:gsub("%/",".")cZ8mW=U end;lD8E0=lD8E0[cZ8mW]end;return lD8E0 end
|
|
local function F3vF(MA)local RmPOf3Wl={}local ROso3G=#RmPOf3Wl
|
|
for AaZVi3,A in ipairs(drEf10P(".*"))do local X7eznY
|
|
do
|
|
local nui3w2g=U9bX9Qj(A)
|
|
if("function"==type(nui3w2g))then
|
|
local TyY1TP=(CZ.metadata):get(nui3w2g,"fnl/docstring")if(nil~=TyY1TP)then local I=TyY1TP;X7eznY=(I:match(MA)and A)else
|
|
X7eznY=nil end else X7eznY=nil end end;if(nil~=X7eznY)then ROso3G=(ROso3G+1)do end
|
|
(RmPOf3Wl)[ROso3G]=X7eznY else end end;return RmPOf3Wl end
|
|
EgG["apropos-doc"]=function(p,nWwv,U5,SSRIM2dF,TQ)local function PZd(lp2390NG)
|
|
return U5(F3vF(tostring(lp2390NG)))end;return _bh_k(nWwv,SSRIM2dF,PZd)end;do end
|
|
(CZ.metadata):set(EgG["apropos-doc"],"fnl/docstring","Print all functions that match the pattern in their docs")
|
|
local function l1YXXES(Vc,NV)
|
|
for f_qSS3,jkNMk in ipairs(drEf10P(NV))do local C4yJBj5=U9bX9Qj(jkNMk)
|
|
if
|
|
(
|
|
("function"==type(C4yJBj5))and(CZ.metadata):get(C4yJBj5,"fnl/docstring"))then Vc(iD90MK.doc(C4yJBj5,jkNMk))Vc()else end end;return nil end
|
|
EgG["apropos-show-docs"]=function(Kdb,A8f,f,bvP)local function fRpw3tSl(Wj3o4LNJ)
|
|
return l1YXXES(f,tostring(Wj3o4LNJ))end;return _bh_k(A8f,bvP,fRpw3tSl)end;do end
|
|
(CZ.metadata):set(EgG["apropos-show-docs"],"fnl/docstring","Print all documentations matching a pattern in function name")
|
|
local function QO9Kq(aq67Ya3,x,LJVh6)local pqvpad=x;local pA=pqvpad["___replLocals___"]local BU1O2_L=pqvpad;local uZM;local function ZcEsZ(pwz7,Kt_w)return(pA[Kt_w]or
|
|
BU1O2_L[Kt_w])end
|
|
uZM=setmetatable({},{__index=ZcEsZ})
|
|
local Q56iTd,no8ruIR=pcall(CZ["compile-string"],tostring(aq67Ya3),{scope=LJVh6})
|
|
if((Q56iTd==true)and(nil~=no8ruIR))then
|
|
local F=no8ruIR;return iD90MK["load-code"](F,uZM)()else return nil end end
|
|
EgG.find=function(S0,Sm,hViv5C_,jh,Pwq)
|
|
local function q16(k1oD)local P7WPKR
|
|
do local O=o["sym?"](k1oD)if(nil~=O)then
|
|
local nZ0YB=QO9Kq(O,S0,Pwq)
|
|
if(nil~=nZ0YB)then P7WPKR=debug.getinfo(nZ0YB)else P7WPKR=nZ0YB end else P7WPKR=O end end
|
|
if
|
|
(
|
|
|
|
(_G.type(P7WPKR)=="table")and
|
|
((P7WPKR).what=="Lua")and(nil~= (P7WPKR).source)and(nil~= (P7WPKR).linedefined)and(nil~= (P7WPKR).short_src))then local p6e=(P7WPKR).source;local po8N=(P7WPKR).linedefined
|
|
local a7=(P7WPKR).short_src;local U6w
|
|
do local Irt=CZ.sourcemap;if(nil~=Irt)then Irt=(Irt)[p6e]else end;if(nil~=
|
|
Irt)then Irt=(Irt)[po8N]else end;if(nil~=Irt)then
|
|
Irt=(Irt)[2]else end;U6w=Irt end;return
|
|
hViv5C_({string.format("%s:%s",a7,(U6w or po8N))})elseif(P7WPKR==nil)then
|
|
return jh("Repl","Unknown value")elseif true then local khsuDn=P7WPKR;return jh("Repl","No source info")else return nil end end;return _bh_k(Sm,jh,q16)end;do end
|
|
(CZ.metadata):set(EgG.find,"fnl/docstring","Print the filename and line number for a given function")
|
|
EgG.doc=function(iDQAM,dJEEzHLA,VhIhDh,rSwA,IuZ)
|
|
local function uQBNaZ8L(amTY)local YbIZJ=tostring(amTY)
|
|
local kVCVg=(o["multi-sym?"](YbIZJ)or{YbIZJ})local E5J5PpiD,yxld=nil,nil
|
|
local function rn0()return
|
|
(o["get-in"](IuZ.specials,kVCVg)or
|
|
o["get-in"](IuZ.macros,kVCVg)or QO9Kq(YbIZJ,iDQAM,IuZ))end;E5J5PpiD,yxld=pcall(rn0)
|
|
if E5J5PpiD then return
|
|
VhIhDh({iD90MK.doc(yxld,YbIZJ)})else return
|
|
rSwA("Repl","Could not resolve value for docstring lookup")end end;return _bh_k(dJEEzHLA,rSwA,uQBNaZ8L)end;do end
|
|
(CZ.metadata):set(EgG.doc,"fnl/docstring","Print the docstring and arglist for a function, macro, or special form.")
|
|
EgG.compile=function(Kz3Upt,FNcg,ip1Y,SNe51hiO,nbh)
|
|
local function xyD5eM3(dvQC_Q)
|
|
local w7pQl=iD90MK["current-global-names"](Kz3Upt)
|
|
local F4cjGy,D5=pcall(CZ.compile,dvQC_Q,{env=Kz3Upt,scope=nbh,allowedGlobals=w7pQl})
|
|
if F4cjGy then return ip1Y({D5})else return
|
|
SNe51hiO("Repl",("Error compiling expression: "..D5))end end;return _bh_k(FNcg,SNe51hiO,xyD5eM3)end;do end
|
|
(CZ.metadata):set(EgG.compile,"fnl/docstring","compiles the expression into lua and prints the result.")
|
|
local function eG8QRxg(K46A)
|
|
for B,DIW in ipairs((K46A or{}))do
|
|
for mcrg,zg74G in pairs(DIW)do
|
|
local C4Qpi_bm=mcrg:match("^repl%-command%-(.*)")if(nil~=C4Qpi_bm)then local nsBJr=C4Qpi_bm
|
|
EgG[nsBJr]=(EgG[nsBJr]or zg74G)else end end end;return nil end
|
|
local function YjH(y0,KkoR7,rs,l8eg,YAV,F_XBNQq,QTmbwc,Qa95Sy)local M8OIL=y0:match(",([^%s/]+)")
|
|
do local aeH=EgG[M8OIL]
|
|
if(nil~=aeH)then
|
|
local LPJB=aeH;LPJB(l8eg,KkoR7,YAV,F_XBNQq,QTmbwc,Qa95Sy)elseif true then local zwqy0k=aeH
|
|
if("exit"~=
|
|
M8OIL)then YAV({"Unknown command",M8OIL})else end else end end;if("exit"~=M8OIL)then return rs()else return nil end end
|
|
local function C(_5SaCc,ywU,vd2O)
|
|
if ywU then
|
|
if vd2O.set_readline_name then vd2O.set_readline_name("fennel")else end;vd2O.set_options({keeplines=1000,histfile=""})
|
|
_5SaCc.readChunk=function(L)
|
|
local hlKRv
|
|
if(0 <L["stack-size"])then hlKRv=".. "else hlKRv=">> "end;local hkB=vd2O.readline(hlKRv)
|
|
if hkB then return(hkB.."\n")else return nil end end;local DS=nil
|
|
_5SaCc.registerCompleter=function(zz7LdNp)DS=zz7LdNp;return nil end
|
|
local function JoHY0u(hn,JyiDC,HNfI3)if DS then vd2O.set_completion_append_character("")return
|
|
DS(hn:sub(JyiDC,HNfI3))else return{}end end;vd2O.set_complete_function(JoHY0u)return vd2O else return nil end end
|
|
local function YmhoTRx(vCj849a)return
|
|
(
|
|
("dumb"~=os.getenv("TERM"))and not vCj849a.readChunk and not vCj849a.registerCompleter)end
|
|
local function TlXcZ1(Weyl3)local SPQWFq=o.root.options;local iKW_cPpO=o.copy(Weyl3)
|
|
local YS4T=iKW_cPpO["fennelrc"]local Q_=iKW_cPpO;local Un;Q_.fennelrc=nil;Un=nil
|
|
local CvX=(YmhoTRx(Q_)and
|
|
C(Q_,pcall(require,"readline")))local Mum;if YS4T then Mum=YS4T()else Mum=nil end
|
|
local HBCtgC=iD90MK["wrap-env"]((Q_.env or
|
|
rawget(_G,"_ENV")or _G))local zV=(Q_.saveLocals~=false)
|
|
local xz7=(Q_.readChunk or t)local k0jnx9=(Q_.onValues or NChC)
|
|
local WQG=(Q_.onError or Z4)local FApYEt=(Q_.pp or ZuYO)local Tv94e,LhzI8e3Y=UesS.granulate(xz7)
|
|
local YGa={}local IYYREqB,Ghy=nil,nil
|
|
local function Cdb(V)local VL=Tv94e(V)table.insert(YGa,VL)return VL end;IYYREqB,Ghy=UesS.parser(Cdb)
|
|
Q_.env,Q_.scope=HBCtgC,CZ["make-scope"]()Q_.useMetadata=(Q_.useMetadata~=false)if
|
|
(Q_.allowedGlobals==nil)then
|
|
Q_.allowedGlobals=iD90MK["current-global-names"](HBCtgC)else end
|
|
if Q_.registerCompleter then
|
|
local function hXei3()local yiXQIkB7=HBCtgC
|
|
local ccRfT=Q_.scope;local function _(...)return tj(yiXQIkB7,ccRfT,...)end;return _ end;Q_.registerCompleter(hXei3())else end;eG8QRxg(Q_.plugins)
|
|
if zV then
|
|
local function sUj(ubOT,Q,ddrN)if Q_.scope.unmanglings[Q]then
|
|
return rawset(ubOT,Q,ddrN)else return nil end end
|
|
HBCtgC.___replLocals___=setmetatable({},{__newindex=sUj})else end
|
|
local function GelE3uPj(...)local BqFbTyTP={...}local uQS1={}HBCtgC._,HBCtgC.__=BqFbTyTP[1],BqFbTyTP;for m6qA=1,select("#",...)
|
|
do
|
|
table.insert(uQS1,FApYEt(BqFbTyTP[m6qA]))end;return k0jnx9(uQS1)end
|
|
local function dTeimz()for EpoQUjJ in pairs(YGa)do YGa[EpoQUjJ]=nil end;Ghy()
|
|
local rRzTAof,Yw,vWiYYutP=pcall(IYYREqB)local uL5iEiVf=string.char(j(YGa))
|
|
local IUBPM=(not CvX or(uL5iEiVf~="(null)"))local dP1Jx=(IUBPM and Yw)
|
|
if not rRzTAof then WQG("Parse",dP1Jx)
|
|
LhzI8e3Y()return dTeimz()elseif YgsJ(uL5iEiVf)then return
|
|
YjH(uL5iEiVf,IYYREqB,dTeimz,HBCtgC,k0jnx9,WQG,Q_.scope,YGa)else
|
|
if dP1Jx then
|
|
do local iehY,Ljtmwa1=nil,nil;local function f4uVo()local KR=Q_
|
|
KR["source"]=uL5iEiVf;return KR end
|
|
iehY,Ljtmwa1=pcall(CZ.compile,vWiYYutP,f4uVo())
|
|
if((iehY==false)and(nil~=Ljtmwa1))then
|
|
local eV4iiyUX=Ljtmwa1;LhzI8e3Y()WQG("Compile",eV4iiyUX)elseif((iehY==true)and
|
|
(nil~=Ljtmwa1))then local FjS2u2tJ=Ljtmwa1;local k_;if zV then
|
|
k_=I13Z9(HBCtgC,FjS2u2tJ,Q_.scope)else k_=FjS2u2tJ end
|
|
local s,QJHR8OCl=pcall(iD90MK["load-code"],k_,HBCtgC)
|
|
if((s==false)and(nil~=QJHR8OCl))then local tS=QJHR8OCl
|
|
LhzI8e3Y()WQG("Lua Compile",tS,k_)elseif
|
|
(true and(nil~=QJHR8OCl))then local p=s;local QCN=QJHR8OCl;local function WQyVRxD()return GelE3uPj(QCN())end
|
|
local function xW()local function TC3eID8n(...)return
|
|
WQG("Runtime",...)end;return TC3eID8n end;xpcall(WQyVRxD,xW())else end else end end;o.root.options=SPQWFq;return dTeimz()else return nil end end end;dTeimz()
|
|
if CvX then return CvX.save_history()else return nil end end;return TlXcZ1 end
|
|
package.preload["fennel.specials"]=package.preload["fennel.specials"]or
|
|
function(...)
|
|
local Jzh=require("fennel.utils")local fNDs=require("fennel.view")
|
|
local S=require("fennel.parser")local AHA=require("fennel.compiler")
|
|
local cI0i=(table.unpack or _G.unpack)local O11E=AHA.scopes.global.specials
|
|
local function LhQHR(qhPco)local function Id(uoOlhf,e)
|
|
if Jzh["string?"](e)then return
|
|
qhPco[AHA["global-unmangling"](e)]else return qhPco[e]end end
|
|
local function WL(uTc6g,Zn4fIs,Ppx)
|
|
if
|
|
Jzh["string?"](Zn4fIs)then
|
|
qhPco[AHA["global-unmangling"](Zn4fIs)]=Ppx;return nil else qhPco[Zn4fIs]=Ppx;return nil end end
|
|
local function w()
|
|
local function kAU(LL82TJ5q,wdM5AGuw)local _Y;if Jzh["string?"](LL82TJ5q)then
|
|
_Y=AHA["global-unmangling"](LL82TJ5q)else _Y=LL82TJ5q end;return _Y,wdM5AGuw end;return next,Jzh.kvmap(qhPco,kAU),nil end
|
|
return setmetatable({},{__index=Id,__newindex=WL,__pairs=w})end
|
|
local function V(AUwG6)local x5_xK
|
|
do local KOHj1O=getmetatable(AUwG6)
|
|
if
|
|
(
|
|
(_G.type(KOHj1O)=="table")and(nil~= (KOHj1O).__pairs))then local TAF_rrY=(KOHj1O).__pairs;local zYUy={}for Dw5,yRGXM in TAF_rrY(AUwG6)do local L,qqjD4e=Dw5,yRGXM
|
|
if(
|
|
(L~=nil)and(qqjD4e~=nil))then zYUy[L]=qqjD4e else end end;x5_xK=zYUy elseif
|
|
(KOHj1O==nil)then x5_xK=(AUwG6 or _G)else x5_xK=nil end end;return
|
|
(x5_xK and Jzh.kvmap(x5_xK,AHA["global-unmangling"]))end
|
|
local function WpQBPz(dhfvbed,qoLSvP,lUV1Y)
|
|
local dg5N=(qoLSvP or rawget(_G,"_ENV")or _G)local wwx,Pohtng=rawget(_G,"setfenv"),rawget(_G,"loadstring")
|
|
if(
|
|
(nil~=wwx)and(nil~=Pohtng))then local t=wwx;local _H=Pohtng
|
|
local hLbS=assert(_H(dhfvbed,lUV1Y))local qTkqZM=hLbS;t(qTkqZM,dg5N)return qTkqZM elseif true then local JalgRqs=wwx;return
|
|
assert(load(dhfvbed,lUV1Y,"t",dg5N))else return nil end end
|
|
local function YMl(_qwQtun2,HJ)
|
|
if not _qwQtun2 then return(HJ.." not found")else
|
|
local lEZKOn=((
|
|
(AHA.metadata):get(_qwQtun2,"fnl/docstring")or"#<undocumented>")):gsub("\n$",""):gsub("\n","\n ")local BhRI=getmetatable(_qwQtun2)
|
|
if
|
|
(
|
|
(type(_qwQtun2)=="function")or((type(BhRI)=="table")and
|
|
(type(BhRI.__call)=="function")))then
|
|
local Hnykp=table.concat(((AHA.metadata):get(_qwQtun2,"fnl/arglist")or
|
|
{"#<unknown-arguments>"})," ")local KVZGVS;if(0 <#Hnykp)then KVZGVS=" "else KVZGVS=""end;return
|
|
string.format("(%s%s%s)\n %s",HJ,KVZGVS,Hnykp,lEZKOn)else
|
|
return string.format("%s\n %s",HJ,lEZKOn)end end end
|
|
local function qh0m(W,l,YtJ3Vld,gesxk)
|
|
AHA.metadata[O11E[W]]={["fnl/arglist"]=l,["fnl/docstring"]=YtJ3Vld,["fnl/body-form?"]=gesxk}return nil end
|
|
local function T1pL(RPBF,MA,cQiY,mi0Su5)local RSbaegr=(mi0Su5 or 2)local D_XnV=#RPBF
|
|
local T5b=AHA["make-scope"](MA)
|
|
for Pzvq9=RSbaegr,D_XnV do AHA.compile1(RPBF[Pzvq9],T5b,cQiY,{nval=0})end;return nil end
|
|
O11E["do"]=function(xWDqizI,lLfybj,kfv75hSt,L,QtUzJA8W,vyg,i,iu)local AQAZ71dv=(QtUzJA8W or 2)
|
|
local hnm7wW0=(i or AHA["make-scope"](lLfybj))local UM52=(vyg or{})local D_=#xWDqizI;local rVtCZOT={returned=true}
|
|
local function zXaijdUvQ(RZ7Pv3B4,utllnvh,Cy)
|
|
if
|
|
(D_<AQAZ71dv)then
|
|
AHA.compile1(nil,hnm7wW0,UM52,{tail=utllnvh,target=RZ7Pv3B4})else
|
|
for Sc=AQAZ71dv,D_ do
|
|
local Ilv={nval=(((Sc~=D_)and 0)or L.nval),tail=(
|
|
((Sc==D_)and utllnvh)or nil),target=(((Sc==D_)and RZ7Pv3B4)or nil)}local HiEsql=Jzh["propagate-options"](L,Ilv)
|
|
local IB3=AHA.compile1(xWDqizI[Sc],hnm7wW0,UM52,Ilv)if(Sc~=D_)then
|
|
AHA["keep-side-effects"](IB3,kfv75hSt,nil,xWDqizI[Sc])else end end end;AHA.emit(kfv75hSt,UM52,xWDqizI)
|
|
AHA.emit(kfv75hSt,"end",xWDqizI)Jzh.hook("do",xWDqizI,hnm7wW0)return(Cy or rVtCZOT)end
|
|
if(L.target or(L.nval==0)or L.tail)then
|
|
AHA.emit(kfv75hSt,"do",xWDqizI)return zXaijdUvQ(L.target,L.tail)elseif L.nval then local GO9cd={}for puiZj=1,L.nval do
|
|
local cRj7Bs6=(
|
|
(iu and(iu)[puiZj])or AHA.gensym(lLfybj))do end(GO9cd)[puiZj]=cRj7Bs6
|
|
rVtCZOT[puiZj]=Jzh.expr(cRj7Bs6,"sym")end
|
|
local shT=table.concat(GO9cd,", ")
|
|
AHA.emit(kfv75hSt,string.format("local %s",shT),xWDqizI)AHA.emit(kfv75hSt,"do",xWDqizI)
|
|
return zXaijdUvQ(shT,L.tail)else local LRdW=AHA.gensym(lLfybj)local Nao8
|
|
if lLfybj.vararg then Nao8="..."else Nao8=""end
|
|
AHA.emit(kfv75hSt,string.format("local function %s(%s)",LRdW,Nao8),xWDqizI)return
|
|
zXaijdUvQ(nil,true,Jzh.expr((LRdW.."("..Nao8 ..")"),"statement"))end end
|
|
qh0m("do",{"..."},"Evaluate multiple forms; return last value.",true)
|
|
O11E.values=function(wx,KPk,vHVswxQg)local O8sHnXSb=#wx;local vRuSKT={}
|
|
for yNM=2,O8sHnXSb do
|
|
local uQKBCL=AHA.compile1(wx[yNM],KPk,vHVswxQg,{nval=((yNM~=O8sHnXSb)and 1)})table.insert(vRuSKT,uQKBCL[1])if(yNM==O8sHnXSb)then
|
|
for U=2,#uQKBCL
|
|
do table.insert(vRuSKT,uQKBCL[U])end else end end;return vRuSKT end
|
|
qh0m("values",{"..."},"Return multiple values from a function. Must be in tail position.")
|
|
local function x(i1U2ZgP1,eaa)for qt7CqAhB,Sut in pairs(eaa)do local uXZKm=i1U2ZgP1;table.insert(uXZKm,qt7CqAhB)
|
|
table.insert(uXZKm,Sut)end;return i1U2ZgP1 end
|
|
local function SM(RrqZ)local j2vFDP=true
|
|
if Jzh["list?"](RrqZ)then j2vFDP=false elseif Jzh["table?"](RrqZ)then
|
|
local ULRN_=x({},RrqZ)
|
|
for SO4d,PEj in ipairs(ULRN_)do if not j2vFDP then break end;if Jzh["list?"](PEj)then j2vFDP=false elseif
|
|
Jzh["table?"](PEj)then x(ULRN_,PEj)else end end else end;return j2vFDP end
|
|
local function mz725oTF(ghM3GY)local LA={nval=1,tail=false}local XsfY=AHA["make-scope"]()local PHZn={}
|
|
local gPKGb=AHA.compile1(ghM3GY,XsfY,PHZn,LA)local wp_V=gPKGb[1]local lZIs5NY=wp_V[1]return lZIs5NY end
|
|
local function a(uYH7X,VwUT43myq,ZB)
|
|
local x87MJd0={["escape-newlines?"]=true,["line-length"]=math.huge,["one-line?"]=true}
|
|
AHA.assert((type(VwUT43myq)=="string"),("expected string keys in metadata table, got: %s"):format(fNDs(VwUT43myq,x87MJd0)))
|
|
AHA.assert(SM(ZB),("expected literal value in metadata table, got: %s %s"):format(fNDs(VwUT43myq,x87MJd0),fNDs(ZB,x87MJd0)))local NOf=uYH7X;table.insert(NOf,fNDs(VwUT43myq))local function sksgyG()
|
|
if("string"==
|
|
type(ZB))then return fNDs(ZB,x87MJd0)else return mz725oTF(ZB)end end
|
|
table.insert(NOf,sksgyG())return NOf end
|
|
local function rx(WO8me2,S1)
|
|
local ejeeWF={["one-line?"]=true,["escape-newlines?"]=true,["line-length"]=math.huge}local SUqZnH=WO8me2;table.insert(SUqZnH,"\"fnl/arglist\"")local function gKJj(sidQs)return
|
|
fNDs(fNDs(sidQs,ejeeWF))end
|
|
table.insert(SUqZnH,("{"..
|
|
table.concat(Jzh.map(S1,gKJj),", ").."}"))return SUqZnH end
|
|
local function t4X(GYH_v,KEOG,toEWCo)
|
|
if Jzh.root.options.useMetadata then local Xy2rqD={}for Tk,PyoiZ34 in Jzh.stablepairs(GYH_v)do
|
|
if
|
|
(Tk=="fnl/arglist")then rx(Xy2rqD,PyoiZ34)else a(Xy2rqD,Tk,PyoiZ34)end end
|
|
local f1g01=("require(\"%s\").metadata"):format((
|
|
Jzh.root.options.moduleName or"fennel"))return
|
|
AHA.emit(KEOG,("pcall(function() %s:setall(%s, %s) end)"):format(f1g01,toEWCo,table.concat(Xy2rqD,", ")))else return nil end end
|
|
local function Bt8c_K(Ri,h8Kdnxlz,uULb49,Yw)
|
|
if(uULb49 and(uULb49[1]~="nil"))then local Ny1;if not Yw then
|
|
Ny1=AHA["declare-local"](uULb49,{},h8Kdnxlz,Ri)else
|
|
Ny1=(AHA["symbol-to-expression"](uULb49,h8Kdnxlz))[1]end
|
|
return Ny1,not Yw,3 else return nil,true,2 end end
|
|
local function Ytae(_dvf1W51,Ve,WF,laWJ0,yavQNo,J8QVv4,fC,_HE3xI6g,KY)
|
|
for _IhpETSL=(yavQNo+1),#_dvf1W51 do
|
|
AHA.compile1(_dvf1W51[_IhpETSL],Ve,WF,{nval=((
|
|
(_IhpETSL~=#_dvf1W51)and 0)or nil),tail=(_IhpETSL==
|
|
#_dvf1W51)})end;local _I4E0r7
|
|
if fC then _I4E0r7="local function %s(%s)"else _I4E0r7="%s = function(%s)"end
|
|
AHA.emit(laWJ0,string.format(_I4E0r7,J8QVv4,table.concat(_HE3xI6g,", ")),_dvf1W51)AHA.emit(laWJ0,WF,_dvf1W51)
|
|
AHA.emit(laWJ0,"end",_dvf1W51)t4X(KY,laWJ0,J8QVv4)Jzh.hook("fn",_dvf1W51,Ve)return
|
|
Jzh.expr(J8QVv4,"sym")end
|
|
local function lce(LSCe,p5,B8Suwl,XARyK,ODqlVU,n,koXJCN4L,de)local QoqS9_YO=AHA.gensym(de)return
|
|
Ytae(LSCe,p5,B8Suwl,XARyK,ODqlVU,QoqS9_YO,true,n,koXJCN4L)end
|
|
local function oKL2U4fJ(OdYG6Ap)local YpFQMbmN=#OdYG6Ap;local t3cE9NzG,Sci787H,QNz8ZORV=pairs(OdYG6Ap)
|
|
local function KUeDP()if(YpFQMbmN==0)then return
|
|
QNz8ZORV else return YpFQMbmN end end
|
|
return(nil~=t3cE9NzG(Sci787H,KUeDP()))end
|
|
local function QcKEbkF(aH,H0vWTA,Zt4vZRsD)local Q={["fnl/arglist"]=H0vWTA}local Vl=(Zt4vZRsD+1)
|
|
local Z4=aH[Vl]
|
|
if(Jzh["string?"](Z4)and(Vl<#aH))then local mOmsyRAV
|
|
do
|
|
local SGToljD=Q;SGToljD["fnl/docstring"]=Z4;mOmsyRAV=SGToljD end;return mOmsyRAV,Vl elseif
|
|
(Jzh["table?"](Z4)and(Vl<#aH)and oKL2U4fJ(Z4))then local nDI;do local QO=Q
|
|
for hN,yU in pairs(Z4)do local umHu,Zk=hN,yU;if
|
|
((umHu~=nil)and(Zk~=nil))then QO[umHu]=Zk else end end;nDI=QO end
|
|
return nDI,Vl else return Q,Zt4vZRsD end end
|
|
O11E.fn=function(foUvUPWx,x_NZCXZ,lbkcp)local Kz5L;do local PCPu=AHA["make-scope"](x_NZCXZ)do end
|
|
(PCPu)["vararg"]=false;Kz5L=PCPu end;local WKXgQ={}
|
|
local vQicu=Jzh["sym?"](foUvUPWx[2])
|
|
local wWqc1=(vQicu and Jzh["multi-sym?"](vQicu[1]))local L,O,UNE1=Bt8c_K(foUvUPWx,x_NZCXZ,vQicu,wWqc1)
|
|
local C=AHA.assert(Jzh["table?"](foUvUPWx[UNE1]),"expected parameters table",foUvUPWx)
|
|
AHA.assert((not wWqc1 or not wWqc1["multi-sym-method-call"]),(
|
|
"unexpected multi symbol "..tostring(L)),vQicu)
|
|
local function FAcgh(_LmNV)local mi2=Jzh.sym(AHA.gensym(x_NZCXZ))
|
|
local wtZMPRlR=AHA["declare-local"](mi2,{},Kz5L,foUvUPWx)
|
|
AHA.destructure(_LmNV,mi2,foUvUPWx,Kz5L,WKXgQ,{declaration=true,nomulti=true,symtype="arg"})return wtZMPRlR end
|
|
local function t9nNfj(epbNPkw)
|
|
AHA.assert((epbNPkw== (#C-1)),"expected rest argument before last parameter",C[(epbNPkw+1)],C)Kz5L.vararg=true
|
|
AHA.destructure(C[#C],{Jzh.varg()},foUvUPWx,Kz5L,WKXgQ,{declaration=true,nomulti=true,symtype="arg"})return"..."end
|
|
local function XRZLOso(LW,sFtYbPYh9)
|
|
if Kz5L.vararg then return nil elseif Jzh["varg?"](LW)then
|
|
AHA.assert((LW==C[#C]),"expected vararg as last parameter",foUvUPWx)Kz5L.vararg=true;return"..."elseif(Jzh.sym("&")==LW)then
|
|
return t9nNfj(sFtYbPYh9)elseif
|
|
(Jzh["sym?"](LW)and(tostring(LW)~="nil")and not
|
|
Jzh["multi-sym?"](tostring(LW)))then return AHA["declare-local"](LW,{},Kz5L,foUvUPWx)elseif
|
|
Jzh["table?"](LW)then return FAcgh(LW)else return
|
|
AHA.assert(false,("expected symbol for function parameter: %s"):format(tostring(LW)),foUvUPWx[UNE1])end end;local ktQi8H
|
|
do local qZ4gSk={}local v9OIHvZ=#qZ4gSk;for Au,z8 in ipairs(C)do local rfFHu6=XRZLOso(z8,Au)
|
|
if
|
|
(nil~=rfFHu6)then v9OIHvZ=(v9OIHvZ+1)do end(qZ4gSk)[v9OIHvZ]=rfFHu6 else end end
|
|
ktQi8H=qZ4gSk end;local XtwfE,tdtJB=QcKEbkF(foUvUPWx,C,UNE1)
|
|
if L then return
|
|
Ytae(foUvUPWx,Kz5L,WKXgQ,lbkcp,tdtJB,L,O,ktQi8H,XtwfE)else return
|
|
lce(foUvUPWx,Kz5L,WKXgQ,lbkcp,tdtJB,ktQi8H,XtwfE,x_NZCXZ)end end
|
|
qh0m("fn",{"name?","args","docstring?","..."},"Function syntax. May optionally include a name and docstring or a metadata table.\nIf a name is provided, the function will be bound in the current scope.\nWhen called with the wrong number of args, excess args will be discarded\nand lacking args will be nil, use lambda for arity-checked functions.",true)
|
|
O11E.lua=function(rVKBG,YYZ,D)
|
|
AHA.assert(((#rVKBG==2)or(#rVKBG==3)),"expected 1 or 2 arguments",rVKBG)local vy
|
|
do local peLm=Jzh["sym?"](rVKBG[2])if(nil~=peLm)then
|
|
vy=tostring(peLm)else vy=peLm end end;if("nil"~=vy)then
|
|
table.insert(D,{ast=rVKBG,leaf=tostring(rVKBG[2])})else end;local kt8sWFAZ;do
|
|
local ljkJc4X=Jzh["sym?"](rVKBG[3])
|
|
if(nil~=ljkJc4X)then kt8sWFAZ=tostring(ljkJc4X)else kt8sWFAZ=ljkJc4X end end;if
|
|
("nil"~=kt8sWFAZ)then return tostring(rVKBG[3])else return nil end end
|
|
local function VtWtn6ES(dKPTqbD,fWMAuVe_,RsGV8)
|
|
AHA.assert((1 <#dKPTqbD),"expected table argument",dKPTqbD)local dwy=#dKPTqbD
|
|
local dsskdo1=AHA.compile1(dKPTqbD[2],fWMAuVe_,RsGV8,{nval=1})local RwcXVp9t=dsskdo1[1]
|
|
if(dwy==2)then return tostring(RwcXVp9t)else local Wj9plOE={}
|
|
for Z=3,dwy do
|
|
local F_=dKPTqbD[Z]
|
|
if
|
|
(Jzh["string?"](F_)and Jzh["valid-lua-identifier?"](F_))then table.insert(Wj9plOE,("."..F_))else
|
|
local Ce=AHA.compile1(F_,fWMAuVe_,RsGV8,{nval=1})local gjI84l9=Ce[1]
|
|
table.insert(Wj9plOE,("["..tostring(gjI84l9).."]"))end end
|
|
if(tostring(RwcXVp9t):find("[{\"0-9]")or
|
|
("nil"==tostring(RwcXVp9t)))then return
|
|
("("..
|
|
tostring(RwcXVp9t)..")"..table.concat(Wj9plOE))else return
|
|
(tostring(RwcXVp9t)..table.concat(Wj9plOE))end end end;O11E["."]=VtWtn6ES
|
|
qh0m(".",{"tbl","key1","..."},"Look up key1 in tbl table. If more args are provided, do a nested lookup.")
|
|
O11E.global=function(ZVokSV,VH,hyn)
|
|
AHA.assert((#ZVokSV==3),"expected name and value",ZVokSV)
|
|
AHA.destructure(ZVokSV[2],ZVokSV[3],ZVokSV,VH,hyn,{forceglobal=true,nomulti=true,symtype="global"})return nil end
|
|
qh0m("global",{"name","val"},"Set name as a global with val.")
|
|
O11E.set=function(n5IarGf,EMbzMM6,Vd5F9a)
|
|
AHA.assert((#n5IarGf==3),"expected name and value",n5IarGf)
|
|
AHA.destructure(n5IarGf[2],n5IarGf[3],n5IarGf,EMbzMM6,Vd5F9a,{noundef=true,symtype="set"})return nil end
|
|
qh0m("set",{"name","val"},"Set a local variable to a new value. Only works on locals using var.")
|
|
local function QkuEC(b,OFgu,bi28)AHA.assert((#b==3),"expected name and value",b)
|
|
AHA.destructure(b[2],b[3],b,OFgu,bi28,{forceset=true,symtype="set"})return nil end;O11E["set-forcibly!"]=QkuEC
|
|
local function Dg3M(bWN,ppTbLuHA,H7SAeS)
|
|
AHA.assert((#bWN==3),"expected name and value",bWN)
|
|
AHA.destructure(bWN[2],bWN[3],bWN,ppTbLuHA,H7SAeS,{declaration=true,nomulti=true,symtype="local"})return nil end;O11E["local"]=Dg3M
|
|
qh0m("local",{"name","val"},"Introduce new top-level immutable local.")
|
|
O11E.var=function(tjH7RRxU,IS,NAeI)
|
|
AHA.assert((#tjH7RRxU==3),"expected name and value",tjH7RRxU)
|
|
AHA.destructure(tjH7RRxU[2],tjH7RRxU[3],tjH7RRxU,IS,NAeI,{declaration=true,isvar=true,nomulti=true,symtype="var"})return nil end
|
|
qh0m("var",{"name","val"},"Introduce new mutable local.")
|
|
local function u(M9Fz82D)local sajQQWk
|
|
do local NNXy={}local geeYJ5=#NNXy
|
|
for sdL in pairs(M9Fz82D)do local qjIDvx3o;if
|
|
("number"~=type(sdL))then qjIDvx3o=sdL else qjIDvx3o=nil end
|
|
if(nil~=qjIDvx3o)then geeYJ5=(
|
|
geeYJ5+1)do end(NNXy)[geeYJ5]=qjIDvx3o else end end;sajQQWk=NNXy end;return(sajQQWk)[1]end
|
|
O11E.let=function(Dvm,f7etxLRX,SjSDwyLj,L)local MzKuRgHx=Dvm[2]local VtXX={}
|
|
AHA.assert((Jzh["table?"](MzKuRgHx)and
|
|
not u(MzKuRgHx)),"expected binding sequence",MzKuRgHx)
|
|
AHA.assert(((#MzKuRgHx%2)==0),"expected even number of name/value bindings",Dvm[2])
|
|
AHA.assert((3 <=#Dvm),"expected body expression",Dvm[1])for SpYtj4r=1,(L.nval or 0)do
|
|
table.insert(VtXX,AHA.gensym(f7etxLRX))end
|
|
local JDBN=AHA["make-scope"](f7etxLRX)local OQUWt={}for ywFen=1,#MzKuRgHx,2 do
|
|
AHA.destructure(MzKuRgHx[ywFen],MzKuRgHx[(ywFen+1)],Dvm,JDBN,OQUWt,{declaration=true,nomulti=true,symtype="let"})end;return
|
|
O11E["do"](Dvm,f7etxLRX,SjSDwyLj,L,3,OQUWt,JDBN,VtXX)end
|
|
qh0m("let",{"[name1 val1 ... nameN valN]","..."},"Introduces a new scope in which a given set of local bindings are used.",true)local function Pr0Efo(BA31JLSR)
|
|
if("table"==type(BA31JLSR))then
|
|
return Pr0Efo((BA31JLSR.leaf or
|
|
BA31JLSR[#BA31JLSR]))else return(BA31JLSR or"")end end
|
|
local function yv(uhTac3rOu,iifM1a)local function i()
|
|
local BdD0A=Pr0Efo(iifM1a)
|
|
if(nil~=BdD0A)then local Z2=BdD0A;return Z2:match("%)$")else return nil end end;return(
|
|
uhTac3rOu:match("^{")or i())end
|
|
O11E.tset=function(NZj,dz,Nvs7)
|
|
AHA.assert((3 <#NZj),"expected table, key, and value arguments",NZj)
|
|
local k=(AHA.compile1(NZj[2],dz,Nvs7,{nval=1}))[1]local SUy4={}for W=3,(#NZj-1)do
|
|
local Oc=AHA.compile1(NZj[W],dz,Nvs7,{nval=1})local bK9fBMf=Oc[1]
|
|
table.insert(SUy4,tostring(bK9fBMf))end
|
|
local DQu5s=(AHA.compile1(NZj[#NZj],dz,Nvs7,{nval=1}))[1]local kn=tostring(k)local TmhRKP55;if yv(kn,Nvs7)then TmhRKP55="do end (%s)[%s] = %s"else
|
|
TmhRKP55="%s[%s] = %s"end;return
|
|
AHA.emit(Nvs7,TmhRKP55:format(kn,table.concat(SUy4,"]["),tostring(DQu5s)),NZj)end
|
|
qh0m("tset",{"tbl","key1","...","keyN","val"},"Set the value of a table field. Can take additional keys to set\nnested values, but all parents must contain an existing table.")
|
|
local function jRkGV(N,zuqP56)
|
|
if not
|
|
(zuqP56.tail or zuqP56.target or zuqP56.nval)then return"iife",true,nil elseif(
|
|
zuqP56.nval and(zuqP56.nval~=0)and not zuqP56.target)then
|
|
local yioYK={}local K0T={}for rgUL=1,zuqP56.nval do local VEQy4L=AHA.gensym(N)do end(yioYK)[rgUL]=VEQy4L
|
|
K0T[rgUL]=Jzh.expr(VEQy4L,"sym")end;return"target",zuqP56.tail,
|
|
table.concat(yioYK,", "),K0T else return"none",zuqP56.tail,zuqP56.target end end
|
|
local function BA8Q(Z,Cf8U8i,zr,g0z)
|
|
AHA.assert((2 <#Z),"expected condition and body",Z)local c=AHA["make-scope"](Cf8U8i)local ax={}
|
|
local aT,Ot,Fuo_RrjU,dhy4az=jRkGV(Cf8U8i,g0z)local eDibIv={nval=g0z.nval,tail=Ot,target=Fuo_RrjU}
|
|
local function FdmMeSe(JkxKEV)local cMWL9={}
|
|
local KR03kcA=AHA["make-scope"](c)
|
|
AHA["keep-side-effects"](AHA.compile1(Z[JkxKEV],KR03kcA,cMWL9,eDibIv),cMWL9,nil,Z[JkxKEV])return{chunk=cMWL9,scope=KR03kcA}end
|
|
if(1 == (#Z%2))then table.insert(Z,Jzh.sym("nil"))else end
|
|
for gyFZNQR4=2,(#Z-1),2 do local MMS={}
|
|
local j0DhME8=AHA.compile1(Z[gyFZNQR4],c,MMS,{nval=1})local c4k3j=j0DhME8[1]local T1NA=FdmMeSe((gyFZNQR4+1))
|
|
T1NA.cond=c4k3j;T1NA.condchunk=MMS;T1NA.nested=((gyFZNQR4 ~=2)and
|
|
(next(MMS,nil)==nil))
|
|
table.insert(ax,T1NA)end;local Ap27=FdmMeSe(#Z)local bGBwaz=AHA.gensym(Cf8U8i)local aC_9FxPv={}
|
|
local Xo64In4=aC_9FxPv
|
|
for iMog_q_v=1,#ax do local SINHwL9=ax[iMog_q_v]local JWBR;if not SINHwL9.nested then JWBR="if %s then"else
|
|
JWBR="elseif %s then"end
|
|
local nAmOHr=tostring(SINHwL9.cond)local rB=JWBR:format(nAmOHr)if SINHwL9.nested then
|
|
AHA.emit(Xo64In4,SINHwL9.condchunk,Z)else
|
|
for yFwmVrC,eV0V8e in ipairs(SINHwL9.condchunk)do AHA.emit(Xo64In4,eV0V8e,Z)end end
|
|
AHA.emit(Xo64In4,rB,Z)AHA.emit(Xo64In4,SINHwL9.chunk,Z)
|
|
if(iMog_q_v==#ax)then
|
|
AHA.emit(Xo64In4,"else",Z)AHA.emit(Xo64In4,Ap27.chunk,Z)
|
|
AHA.emit(Xo64In4,"end",Z)elseif not(ax[(iMog_q_v+1)]).nested then local RQ7Fx={}
|
|
AHA.emit(Xo64In4,"else",Z)AHA.emit(Xo64In4,RQ7Fx,Z)AHA.emit(Xo64In4,"end",Z)
|
|
Xo64In4=RQ7Fx else end end
|
|
if(aT=="iife")then
|
|
local YT=((Cf8U8i.vararg and"...")or"")
|
|
AHA.emit(zr,("local function %s(%s)"):format(tostring(bGBwaz),YT),Z)AHA.emit(zr,aC_9FxPv,Z)AHA.emit(zr,"end",Z)return
|
|
Jzh.expr(("%s(%s)"):format(tostring(bGBwaz),YT),"statement")elseif(aT=="none")then for VD=1,#aC_9FxPv do
|
|
AHA.emit(zr,aC_9FxPv[VD],Z)end;return{returned=true}else
|
|
AHA.emit(zr,("local %s"):format(Fuo_RrjU),Z)
|
|
for Dhsrul35=1,#aC_9FxPv do AHA.emit(zr,aC_9FxPv[Dhsrul35],Z)end;return dhy4az end end;O11E["if"]=BA8Q
|
|
qh0m("if",{"cond1","body1","...","condN","bodyN"},"Conditional form.\nTakes any number of condition/body pairs and evaluates the first body where\nthe condition evaluates to truthy. Similar to cond in other lisps.")
|
|
local function Qat(mExbKwNw)local lH=mExbKwNw[(#mExbKwNw-1)]
|
|
if
|
|
((Jzh["sym?"](lH)and(
|
|
tostring(lH)=="&until"))or(
|
|
"until"==lH))then table.remove(mExbKwNw,(#mExbKwNw-1))return
|
|
table.remove(mExbKwNw)else return nil end end
|
|
local function StR7(CnKBj0I,LeYS7ST,n03R5Kx)
|
|
if CnKBj0I then
|
|
local hPPA=AHA.compile1(CnKBj0I,LeYS7ST,n03R5Kx,{nval=1})local Cj8R=hPPA[1]return
|
|
AHA.emit(n03R5Kx,("if %s then break end"):format(tostring(Cj8R)),Jzh.expr(CnKBj0I,"expression"))else return nil end end
|
|
O11E.each=function(ab,xuQ6HJG_,vEZ)
|
|
AHA.assert((3 <=#ab),"expected body expression",ab[1])
|
|
local oVsWEZ_J=AHA.assert(Jzh["table?"](ab[2]),"expected binding table",ab)
|
|
local Kvh=AHA.assert((2 <=#oVsWEZ_J),"expected binding and iterator",oVsWEZ_J)local TO12C4w_=Qat(oVsWEZ_J)
|
|
local gzIL4Hp=table.remove(oVsWEZ_J,#oVsWEZ_J)local E30Dza={}local JNQC8C={}local n1x=AHA["make-scope"](xuQ6HJG_)
|
|
local function Xf0A(AsRzIY)
|
|
AHA.assert(
|
|
not Jzh["string?"](AsRzIY),("unexpected iterator clause "..tostring(AsRzIY)),oVsWEZ_J)
|
|
if Jzh["sym?"](AsRzIY)then
|
|
return AHA["declare-local"](AsRzIY,{},n1x,ab,JNQC8C)else local qE=Jzh.sym(AHA.gensym(n1x))do end
|
|
(E30Dza)[qE]=AsRzIY;return AHA["declare-local"](qE,{},n1x,ab)end end;local k=Jzh.map(oVsWEZ_J,Xf0A)
|
|
local Xz=AHA.compile1(gzIL4Hp,xuQ6HJG_,vEZ)local ab7qjN6I=Jzh.map(Xz,tostring)local qWCmS={}
|
|
AHA.emit(vEZ,("for %s in %s do"):format(table.concat(k,", "),table.concat(ab7qjN6I,", ")),ab)for mCn,tAn6 in Jzh.stablepairs(E30Dza)do
|
|
AHA.destructure(tAn6,mCn,ab,n1x,qWCmS,{declaration=true,nomulti=true,symtype="each"})end
|
|
AHA["apply-manglings"](n1x,JNQC8C,ab)StR7(TO12C4w_,n1x,qWCmS)T1pL(ab,n1x,qWCmS,3)
|
|
AHA.emit(vEZ,qWCmS,ab)return AHA.emit(vEZ,"end",ab)end
|
|
qh0m("each",{"[key value (iterator)]","..."},"Runs the body once for each set of values provided by the given iterator.\nMost commonly used with ipairs for sequential tables or pairs for undefined\norder, but can be used with any iterator.",true)
|
|
local function WwJGWL(z__i,Us5,O)local yVWnyOMv=#O
|
|
local wZnDs=(AHA.compile1(z__i[2],Us5,O,{nval=1}))[1]local Q4HLWP=#O;local t={}
|
|
if(yVWnyOMv~=Q4HLWP)then for RxPL=(yVWnyOMv+1),Q4HLWP do
|
|
table.insert(t,O[RxPL])do end(O)[RxPL]=nil end
|
|
AHA.emit(O,"while true do",z__i)
|
|
AHA.emit(t,("if not %s then break end"):format(wZnDs[1]),z__i)else
|
|
AHA.emit(O,("while "..tostring(wZnDs).." do"),z__i)end;T1pL(z__i,AHA["make-scope"](Us5),t,3)
|
|
AHA.emit(O,t,z__i)return AHA.emit(O,"end",z__i)end;O11E["while"]=WwJGWL
|
|
qh0m("while",{"condition","..."},"The classic while loop. Evaluates body until a condition is non-truthy.",true)
|
|
local function OchUF(QiT,y04JgdK,KycZksD)
|
|
local a4Y2fq=AHA.assert(Jzh["table?"](QiT[2]),"expected binding table",QiT)local kI=Qat(QiT[2])local fLoVQQlK=table.remove(QiT[2],1)
|
|
local CpQ5Gl=AHA["make-scope"](y04JgdK)local GVtZS={}local IYamaS={}
|
|
AHA.assert(Jzh["sym?"](fLoVQQlK),("unable to bind %s %s"):format(type(fLoVQQlK),tostring(fLoVQQlK)),QiT[2])
|
|
AHA.assert((3 <=#QiT),"expected body expression",QiT[1])
|
|
AHA.assert((#a4Y2fq<=3),"unexpected arguments",a4Y2fq[4])for iKh6Y=1,math.min(#a4Y2fq,3)do
|
|
GVtZS[iKh6Y]=tostring((AHA.compile1(a4Y2fq[iKh6Y],y04JgdK,KycZksD,{nval=1}))[1])end
|
|
AHA.emit(KycZksD,("for %s = %s do"):format(AHA["declare-local"](fLoVQQlK,{},CpQ5Gl,QiT),table.concat(GVtZS,", ")),QiT)StR7(kI,CpQ5Gl,IYamaS)T1pL(QiT,CpQ5Gl,IYamaS,3)
|
|
AHA.emit(KycZksD,IYamaS,QiT)return AHA.emit(KycZksD,"end",QiT)end;O11E["for"]=OchUF
|
|
qh0m("for",{"[index start stop step?]","..."},"Numeric loop construct.\nEvaluates body once for each value between start and stop (inclusive).",true)
|
|
local function q(oY8_Tb,jFXC6,TZdfAnc,wI4_E,au)local rAZNBKRL=oY8_Tb;local lEJ=rAZNBKRL[1]local fxJx49=rAZNBKRL[2]
|
|
local ad=rAZNBKRL[3]local D
|
|
if
|
|
(
|
|
(wI4_E.type=="literal")or(wI4_E.type=="varg")or(wI4_E.type=="expression"))then D="(%s):%s(%s)"else D="%s:%s(%s)"end;return
|
|
Jzh.expr(string.format(D,tostring(wI4_E),ad,table.concat(au,", ")),"statement")end
|
|
local function nWpL(BRN7oER,YCR,yj8ras,m,dx30orp)
|
|
local Z6w=tostring((AHA.compile1(BRN7oER[3],YCR,yj8ras,{nval=1}))[1])local IOYI6={tostring(m),cI0i(dx30orp)}return
|
|
Jzh.expr(string.format("%s[%s](%s)",tostring(m),Z6w,table.concat(IOYI6,", ")),"statement")end
|
|
local function OusWpn(cC,PM,m,m7dTfnqh,SwvAq)
|
|
local cO=tostring((AHA.compile1(cC[3],PM,m,{nval=1}))[1])local BoIL5A="(function(tgt, m, ...) return tgt[m](tgt, ...) end)(%s, %s)"
|
|
table.insert(SwvAq,1,cO)return
|
|
Jzh.expr(string.format(BoIL5A,tostring(m7dTfnqh),table.concat(SwvAq,", ")),"statement")end
|
|
local function mZ(xwOo,UN16W3,YHNf3RY)
|
|
AHA.assert((2 <#xwOo),"expected at least 2 arguments",xwOo)
|
|
local GJOS_Cb=AHA.compile1(xwOo[2],UN16W3,YHNf3RY,{nval=1})local c1Vq9=GJOS_Cb[1]local VzQwM={}
|
|
for iewIc=4,#xwOo do local b4;local EH61_oC;if(iewIc~=#xwOo)then EH61_oC=1 else EH61_oC=
|
|
nil end
|
|
b4=AHA.compile1(xwOo[iewIc],UN16W3,YHNf3RY,{nval=EH61_oC})Jzh.map(b4,tostring,VzQwM)end
|
|
if(Jzh["string?"](xwOo[3])and
|
|
Jzh["valid-lua-identifier?"](xwOo[3]))then return
|
|
q(xwOo,UN16W3,YHNf3RY,c1Vq9,VzQwM)elseif(c1Vq9.type=="sym")then return
|
|
nWpL(xwOo,UN16W3,YHNf3RY,c1Vq9,VzQwM)else
|
|
return OusWpn(xwOo,UN16W3,YHNf3RY,c1Vq9,VzQwM)end end;O11E[":"]=mZ
|
|
qh0m(":",{"tbl","method-name","..."},"Call the named method on tbl with the provided args.\nMethod name doesn't have to be known at compile-time; if it is, use\n(tbl:method-name ...) instead.")
|
|
O11E.comment=function(Og,ufAz3Vl,lTx)local bi={}for r=2,#Og do
|
|
table.insert(bi,fNDs(Og[r],{["one-line?"]=true}))end
|
|
return AHA.emit(lTx,("--[[ "..
|
|
table.concat(bi," ").." ]]"),Og)end
|
|
qh0m("comment",{"..."},"Comment which will be emitted in Lua output.",true)
|
|
local function sNoOf(KDGWmz,U,E70y)local f68Mn
|
|
if KDGWmz.symmeta[("$"..U)].used then f68Mn=U else f68Mn=E70y end
|
|
if(U<9)then return sNoOf(KDGWmz,(U+1),f68Mn)else return f68Mn end end
|
|
O11E.hashfn=function(if3,I3iKXOp,XJU38yi)
|
|
AHA.assert((#if3 ==2),"expected one argument",if3)local EJGvy
|
|
do local Vq=AHA["make-scope"](I3iKXOp)do end
|
|
(Vq)["vararg"]=false;Vq["hashfn"]=true;EJGvy=Vq end;local GMnE={}local hBd=AHA.gensym(I3iKXOp)local XE=Jzh.sym(hBd)local w={}
|
|
AHA["declare-local"](XE,{},I3iKXOp,if3)for bRC2=1,9 do
|
|
w[bRC2]=AHA["declare-local"](Jzh.sym(("$"..bRC2)),{},EJGvy,if3)end
|
|
local function Xur(M,UlXv,Qdj0Vkr)
|
|
if(Jzh["sym?"](UlXv)and(tostring(UlXv)==
|
|
"$..."))then
|
|
Qdj0Vkr[M]=Jzh.varg()EJGvy.vararg=true;return nil else return
|
|
(("table"==type(UlXv))and(
|
|
Jzh.sym("hashfn")~=UlXv[1])and(
|
|
Jzh["list?"](UlXv)or Jzh["table?"](UlXv)))end end;Jzh["walk-tree"](if3[2],Xur)
|
|
AHA.compile1(if3[2],EJGvy,GMnE,{tail=true})local YOkLhtrKM=sNoOf(EJGvy,1,0)if EJGvy.vararg then
|
|
AHA.assert((YOkLhtrKM==0),"$ and $... in hashfn are mutually exclusive",if3)else end;local gz1GyL
|
|
if EJGvy.vararg then
|
|
gz1GyL=tostring(Jzh.varg())else gz1GyL=table.concat(w,", ",1,YOkLhtrKM)end
|
|
AHA.emit(XJU38yi,string.format("local function %s(%s)",hBd,gz1GyL),if3)AHA.emit(XJU38yi,GMnE,if3)
|
|
AHA.emit(XJU38yi,"end",if3)return Jzh.expr(hBd,"sym")end
|
|
qh0m("hashfn",{"..."},"Function literal shorthand; args are either $... OR $1, $2, etc.")
|
|
local function B(cy3D1h,MV_v2fC,NS,UhBp)local VuHhF=UhBp;local pC0CuBZ=VuHhF["macros"]local FpoZTyWt=(Jzh["list?"](cy3D1h)and
|
|
tostring(cy3D1h[1]))
|
|
if
|
|
(
|
|
((
|
|
"or"==NS)or("and"==NS))and(1 <MV_v2fC)and
|
|
(pC0CuBZ[FpoZTyWt]or("set"==FpoZTyWt)or
|
|
("tset"==FpoZTyWt)or("global"==FpoZTyWt)))then return Jzh.list(Jzh.sym("do"),cy3D1h)else return cy3D1h end end
|
|
local function z(H,lGEkcoW,YTnQP,zT2pXxMG,xXB4,gIlW)local uwPip7=#zT2pXxMG;local idFw7={}local h1mcWj=(" "..H.." ")
|
|
for TN3I4w=2,uwPip7 do
|
|
local sln2J=B(zT2pXxMG[TN3I4w],TN3I4w,H,xXB4)local Vl0PD=AHA.compile1(sln2J,xXB4,gIlW)
|
|
if(TN3I4w==uwPip7)then
|
|
Jzh.map(Vl0PD,tostring,idFw7)else table.insert(idFw7,tostring(Vl0PD[1]))end end;local HY9zZy=#idFw7
|
|
if(HY9zZy==0)then local OGzIarca;do local O78YKA=lGEkcoW
|
|
AHA.assert(O78YKA,"Expected more than 0 arguments",zT2pXxMG)OGzIarca=O78YKA end;return
|
|
Jzh.expr(OGzIarca,"literal")elseif(HY9zZy==1)then
|
|
if YTnQP then return("("..
|
|
YTnQP..h1mcWj..idFw7[1]..")")else return idFw7[1]end elseif true then local M=HY9zZy;return
|
|
("("..table.concat(idFw7,h1mcWj)..")")else return nil end end
|
|
local function qFF(_Np3dAW,Pj3,ze6YJtgk,WqVbDxm)local AaH
|
|
do local Q8Ws_=(WqVbDxm or _Np3dAW)local WOb7pdqL=Pj3;local _t4B=ze6YJtgk;local function xuteFE9(...)return
|
|
z(Q8Ws_,WOb7pdqL,_t4B,...)end;AaH=xuteFE9 end;O11E[_Np3dAW]=AaH;return
|
|
qh0m(_Np3dAW,{"a","b","..."},"Arithmetic operator; works the same as Lua but accepts more arguments.")end;qFF("+","0")qFF("..","''")qFF("^")qFF("-",nil,"")
|
|
qFF("*","1")qFF("%")qFF("/",nil,"1")qFF("//",nil,"1")
|
|
O11E["or"]=function(f19Zp2yI,y,SwkB6)return
|
|
z("or","false",nil,f19Zp2yI,y,SwkB6)end
|
|
O11E["and"]=function(dxIUQX,alGFT,r)return z("and","true",nil,dxIUQX,alGFT,r)end
|
|
qh0m("and",{"a","b","..."},"Boolean operator; works the same as Lua but accepts more arguments.")
|
|
qh0m("or",{"a","b","..."},"Boolean operator; works the same as Lua but accepts more arguments.")
|
|
local function MhA6757(jfh,Yoy0,IxXnO,HAbNWq,G,qJNgN,cI)
|
|
if(#G==1)then
|
|
return AHA.assert(IxXnO,"Expected more than 0 arguments.",G)else local A5V=#G;local Q2RJxTQ_={}local SNK=(" "..jfh.." ")
|
|
local BgdP8C=("bit."..Yoy0)
|
|
for KdR0B94B=2,A5V do local Kq2b;local g0s;if(KdR0B94B~=A5V)then g0s=1 else g0s=nil end
|
|
Kq2b=AHA.compile1(G[KdR0B94B],qJNgN,cI,{nval=g0s})Jzh.map(Kq2b,tostring,Q2RJxTQ_)end
|
|
if(#Q2RJxTQ_==1)then
|
|
if Jzh.root.options.useBitLib then return
|
|
(BgdP8C.."("..HAbNWq..", "..
|
|
Q2RJxTQ_[1]..")")else return("("..
|
|
HAbNWq..SNK..Q2RJxTQ_[1]..")")end else
|
|
if Jzh.root.options.useBitLib then
|
|
return(BgdP8C.."("..
|
|
table.concat(Q2RJxTQ_,", ")..")")else return
|
|
("("..table.concat(Q2RJxTQ_,SNK)..")")end end end end
|
|
local function fB2Vks(ElLmtD,Wq9Fsh,PvCAI1i,sM6C)local KqV1
|
|
do local X=sM6C;local KV8sZEaH=ElLmtD;local omL2A=Wq9Fsh;local nh=PvCAI1i;local function Y9(...)return
|
|
MhA6757(X,KV8sZEaH,omL2A,nh,...)end;KqV1=Y9 end;O11E[ElLmtD]=KqV1;return nil end;fB2Vks("lshift",nil,"1","<<")
|
|
fB2Vks("rshift",nil,"1",">>")fB2Vks("band","0","0","&")fB2Vks("bor","0","0","|")
|
|
fB2Vks("bxor","0","0","~")
|
|
qh0m("lshift",{"x","n"},"Bitwise logical left shift of x by n bits.\nOnly works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.")
|
|
qh0m("rshift",{"x","n"},"Bitwise logical right shift of x by n bits.\nOnly works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.")
|
|
qh0m("band",{"x1","x2","..."},"Bitwise AND of any number of arguments.\nOnly works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.")
|
|
qh0m("bor",{"x1","x2","..."},"Bitwise OR of any number of arguments.\nOnly works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.")
|
|
qh0m("bxor",{"x1","x2","..."},"Bitwise XOR of any number of arguments.\nOnly works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.")
|
|
qh0m("..",{"a","b","..."},"String concatenation operator; works the same as Lua but accepts more arguments.")
|
|
local function KEar3_f(D7CGKmb8,uLyz97,BWkW1j,yZA)local WXYCK=uLyz97;local ifeZY=WXYCK[1]local hAzmuHjD=WXYCK[2]local wOpIPj=WXYCK[3]
|
|
local ezsAVF9Y=AHA.compile1(hAzmuHjD,BWkW1j,yZA,{nval=1})local wMf1B=ezsAVF9Y[1]
|
|
local b=AHA.compile1(wOpIPj,BWkW1j,yZA,{nval=1})local lObXzZtF=b[1]return
|
|
string.format("(%s %s %s)",tostring(wMf1B),D7CGKmb8,tostring(lObXzZtF))end
|
|
local function Bp(gXOgxVqi,aEAOdyb,aANaGdmD,gJ,I)local Iuy
|
|
do local CGX={}local YOdo=#CGX
|
|
for Ts=2,#aANaGdmD do
|
|
local Xoxdbm=tostring((AHA.compile1(aANaGdmD[Ts],gJ,I,{nval=1}))[1])
|
|
if(nil~=Xoxdbm)then YOdo=(YOdo+1)do end(CGX)[YOdo]=Xoxdbm else end end;Iuy=CGX end;local xpU0HjP5
|
|
do local v={}local TpRHAsM=#v
|
|
for O872Y=1,(#Iuy-1)do
|
|
local Fhc=string.format("(%s %s %s)",Iuy[O872Y],gXOgxVqi,Iuy[(O872Y+1)])
|
|
if(nil~=Fhc)then TpRHAsM=(TpRHAsM+1)do end(v)[TpRHAsM]=Fhc else end end;xpU0HjP5=v end
|
|
local E8GAk=string.format(" %s ",(aEAOdyb or"and"))return table.concat(xpU0HjP5,E8GAk)end
|
|
local function WRTH(Q19nu,tG,v7Zovu3S,R8Mr,E7pBdDI)local f5qj={}local bY={}local hi1fT={}
|
|
local d=string.format(" %s ",(tG or"and"))
|
|
for Ev=2,#v7Zovu3S do
|
|
table.insert(f5qj,tostring(AHA.gensym(R8Mr)))
|
|
table.insert(hi1fT,tostring((AHA.compile1(v7Zovu3S[Ev],R8Mr,E7pBdDI,{nval=1}))[1]))end
|
|
do local PinF3=bY;local Fl=#PinF3
|
|
for _RHbBQe_=1,(#f5qj-1)do
|
|
local csZGJji=string.format("(%s %s %s)",f5qj[_RHbBQe_],Q19nu,f5qj[(_RHbBQe_+1)])
|
|
if(nil~=csZGJji)then Fl=(Fl+1)do end(PinF3)[Fl]=csZGJji else end end end;return
|
|
string.format("(function(%s) return %s end)(%s)",table.concat(f5qj,","),table.concat(bY,d),table.concat(hi1fT,","))end
|
|
local function s(_IQM21V,c8S3fu,Z0)
|
|
do local cAn=(c8S3fu or _IQM21V)
|
|
local function zdq3gf(h574,nrS48GsH,VA8mi)
|
|
AHA.assert((2 <#h574),"expected at least two arguments",h574)
|
|
if(3 ==#h574)then return KEar3_f(cAn,h574,nrS48GsH,VA8mi)elseif
|
|
Jzh["every?"](Jzh["idempotent-expr?"],{cI0i(h574,2)})then return Bp(cAn,Z0,h574,nrS48GsH,VA8mi)else
|
|
return WRTH(cAn,Z0,h574,nrS48GsH,VA8mi)end end;O11E[_IQM21V]=zdq3gf end;return
|
|
qh0m(_IQM21V,{"a","b","..."},"Comparison operator; works the same as Lua but accepts more arguments.")end;s(">")s("<")s(">=")s("<=")s("=","==")
|
|
s("not=","~=","or")
|
|
local function gPVgI8V(pva,orki)
|
|
local function RqeYK(ojg0_C,mgD1,Bc)
|
|
AHA.assert((#ojg0_C==2),"expected one argument",ojg0_C)local bJwiKR=AHA.compile1(ojg0_C[2],mgD1,Bc,{nval=1})
|
|
return(
|
|
(orki or pva)..tostring(bJwiKR[1]))end;O11E[pva]=RqeYK;return nil end;gPVgI8V("not","not ")
|
|
qh0m("not",{"x"},"Logical operator; works the same as Lua.")gPVgI8V("bnot","~")
|
|
qh0m("bnot",{"x"},"Bitwise negation; only works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.")gPVgI8V("length","#")
|
|
qh0m("length",{"x"},"Returns the length of a table or string.")do end(O11E)["~="]=O11E["not="]O11E["#"]=O11E.length
|
|
O11E.quote=function(fCYOnUn,z5VJbT,I8OjNIh)
|
|
AHA.assert((
|
|
#fCYOnUn==2),"expected one argument",fCYOnUn)local BTxuZzK,qdtphyF=true,z5VJbT
|
|
while qdtphyF do qdtphyF=qdtphyF.parent;if
|
|
(qdtphyF==AHA.scopes.compiler)then BTxuZzK=false else end end
|
|
return AHA["do-quote"](fCYOnUn[2],z5VJbT,I8OjNIh,BTxuZzK)end
|
|
qh0m("quote",{"x"},"Quasiquote the following form. Only works in macro/compiler scope.")local uA5vZEb={}
|
|
local function ZNbFB(F)local qDcOp4_=getmetatable(F)
|
|
assert((qDcOp4_~=getmetatable("")),"Illegal metatable access!")return qDcOp4_ end;local SE0lo2=nil
|
|
local function GaxZqb()local Rafg8;do local N=rawget(_G,"utf8")if(nil~=N)then Rafg8=Jzh.copy(N)else
|
|
Rafg8=N end end
|
|
return
|
|
{table=Jzh.copy(table),math=Jzh.copy(math),string=Jzh.copy(string),pairs=Jzh.stablepairs,ipairs=ipairs,select=select,tostring=tostring,tonumber=tonumber,bit=rawget(_G,"bit"),pcall=pcall,xpcall=xpcall,next=next,print=print,type=type,assert=assert,error=error,setmetatable=setmetatable,getmetatable=ZNbFB,require=SE0lo2,rawlen=rawget(_G,"rawlen"),rawget=rawget,rawset=rawset,rawequal=rawequal,_VERSION=_VERSION,utf8=Rafg8}end
|
|
local function ZPz3(_5CGI6PZ)local Z={}local ipJKYa=getmetatable(_5CGI6PZ)
|
|
local dPQffKj=ipJKYa["__index"]if("table"==type(dPQffKj))then
|
|
for JSQ,JhH in pairs(dPQffKj)do Z[JSQ]=JhH end else end
|
|
for uh,gWvKWBjLE in next,_5CGI6PZ,nil do Z[uh]=gWvKWBjLE end;return next,Z,nil end
|
|
local function gwje(RsymxL,Iz,xzf,EgCB_nf)local P
|
|
do local vQoZJVom=(EgCB_nf or Jzh.root.options)
|
|
if((
|
|
_G.type(vQoZJVom)=="table")and
|
|
((vQoZJVom)["compiler-env"]=="strict"))then
|
|
P=GaxZqb()elseif((_G.type(vQoZJVom)=="table")and
|
|
(nil~= (vQoZJVom).compilerEnv))then
|
|
local ftq9dIXI=(vQoZJVom).compilerEnv;P=ftq9dIXI elseif
|
|
((_G.type(vQoZJVom)=="table")and(nil~=
|
|
(vQoZJVom)["compiler-env"]))then local FX=(vQoZJVom)["compiler-env"]P=FX elseif true then local zGwGt3E=vQoZJVom
|
|
P=GaxZqb(false)else P=nil end end;local kViUhgj;local function UyTq(vm7_I)return
|
|
Jzh.sym(AHA.gensym((AHA.scopes.macro or Iz),vm7_I))end;local function p()return
|
|
AHA.scopes.macro end;local function u6_LlQ46(L6C5NIeG)
|
|
AHA.assert(AHA.scopes.macro,"must call from macro",RsymxL)
|
|
return AHA.scopes.macro.manglings[tostring(L6C5NIeG)]end
|
|
local function GAPJTX(sgg_50x)
|
|
AHA.assert(AHA.scopes.macro,"must call from macro",RsymxL)return AHA.macroexpand(sgg_50x,AHA.scopes.macro)end
|
|
kViUhgj={_AST=RsymxL,_CHUNK=xzf,_IS_COMPILER=true,_SCOPE=Iz,_SPECIALS=AHA.scopes.global.specials,_VARARG=Jzh.varg(),["macro-loaded"]=uA5vZEb,unpack=cI0i,["assert-compile"]=AHA.assert,view=fNDs,version=Jzh.version,metadata=AHA.metadata,["ast-source"]=Jzh["ast-source"],list=Jzh.list,["list?"]=Jzh["list?"],["table?"]=Jzh["table?"],sequence=Jzh.sequence,["sequence?"]=Jzh["sequence?"],sym=Jzh.sym,["sym?"]=Jzh["sym?"],["multi-sym?"]=Jzh["multi-sym?"],comment=Jzh.comment,["comment?"]=Jzh["comment?"],["varg?"]=Jzh["varg?"],gensym=UyTq,["get-scope"]=p,["in-scope?"]=u6_LlQ46,macroexpand=GAPJTX}kViUhgj._G=kViUhgj;return
|
|
setmetatable(kViUhgj,{__index=P,__newindex=P,__pairs=ZPz3})end
|
|
local function lidmlMiV(...)local bWlu={}local aS=#bWlu
|
|
for a3KhFIf in
|
|
string.gmatch((package.config or""),"([^\n]+)")do local sAPG6y=a3KhFIf
|
|
if(nil~=sAPG6y)then aS=(aS+1)do end(bWlu)[aS]=sAPG6y else end end;return bWlu end;local qr0C1=lidmlMiV(...)local g=qr0C1[1]local o=qr0C1[2]local gAN1v8=qr0C1[3]
|
|
local pL4fol={dirsep=(g or"/"),pathmark=(
|
|
gAN1v8 or";"),pathsep=(o or"?")}
|
|
local function nmhV(m)return string.gsub(m,"[^%w]","%%%1")end
|
|
local function Wd1a_i(A,fd2H)local zQ5=nmhV(pL4fol.pathsep)
|
|
local xhs=("([^%s]*)%s"):format(zQ5,zQ5)local Bd=A:gsub("%.",pL4fol.dirsep)
|
|
local n4Rf=((fd2H or
|
|
Jzh["fennel-module"].path)..pL4fol.pathsep)
|
|
local function QT(vGQaEDQ)
|
|
local HpHT=vGQaEDQ:gsub(nmhV(pL4fol.pathmark),Bd)local e=vGQaEDQ:gsub(nmhV(pL4fol.pathmark),A)local OiRV=(
|
|
io.open(HpHT)or io.open(e))
|
|
if(nil~=OiRV)then
|
|
local kV=OiRV;kV:close()return HpHT elseif true then local Ieet0=OiRV
|
|
return nil, ("no file '"..HpHT.."'")else return nil end end
|
|
local function hjd(IZMQx0rC,BrM2hYPE)local igszykf=n4Rf:match(xhs,IZMQx0rC)
|
|
if(nil~=igszykf)then local q_v=igszykf
|
|
local I,H=QT(q_v)
|
|
if(nil~=I)then local aTdQOCcy=I;return aTdQOCcy elseif((I==nil)and(nil~=H))then local zSyor=H;local function HB()local fuSiMn=(
|
|
BrM2hYPE or{})table.insert(fuSiMn,zSyor)
|
|
return fuSiMn end;return
|
|
hjd((IZMQx0rC+#q_v+1),HB())else return nil end elseif true then local ZsrTm=igszykf;local function v7Q()
|
|
local oWrDs=table.concat((BrM2hYPE or{}),"\n\9")
|
|
if(_VERSION<"Lua 5.4")then return("\n\9"..oWrDs)else return oWrDs end end;return nil,
|
|
v7Q()else return nil end end;return hjd(1)end
|
|
local function ur(C9m4)
|
|
local function dVKfuf(ulHu)local kIuvqs_z=Jzh.copy(Jzh.root.options)for WXKWwF,nGfnz9aW in
|
|
pairs((C9m4 or{}))do kIuvqs_z[WXKWwF]=nGfnz9aW end
|
|
kIuvqs_z["module-name"]=ulHu;local DiibeTp,VE=Wd1a_i(ulHu)
|
|
if(nil~=DiibeTp)then local Jpkn2x2L=DiibeTp;local qIGM
|
|
do
|
|
local zd=Jpkn2x2L;local aIh=kIuvqs_z;local function Ox(...)
|
|
return Jzh["fennel-module"].dofile(zd,aIh,...)end;qIGM=Ox end;return qIGM,Jpkn2x2L elseif((DiibeTp==nil)and(nil~=VE))then
|
|
local T5K7=VE;return T5K7 else return nil end end;return dVKfuf end
|
|
local function IAEw(VXa0K,EcGb,GFIjpl,...)
|
|
local CXtt1l9J=(package.loaders or package.searchers or{})local MIJA=table.insert(CXtt1l9J,1,VXa0K)
|
|
local _rbAfa=Jzh["fennel-module"].dofile(EcGb,GFIjpl,...)table.remove(CXtt1l9J,1)return _rbAfa end
|
|
local function HkFs_(WC)local dpl5Qr8i
|
|
do local vdrp=Jzh.copy(Jzh.root.options)do end
|
|
(vdrp)["module-name"]=WC;vdrp["env"]="_COMPILER"vdrp["requireAsInclude"]=false;vdrp["allowedGlobals"]=
|
|
nil;dpl5Qr8i=vdrp end
|
|
local VhWZl_=Wd1a_i(WC,Jzh["fennel-module"]["macro-path"])
|
|
if(nil~=VhWZl_)then local xB=VhWZl_;local qtSF2kh
|
|
if
|
|
(dpl5Qr8i["compiler-env"]==_G)then local Bu=HkFs_;local ja=xB;local glp=dpl5Qr8i
|
|
local function oP(...)return IAEw(Bu,ja,glp,...)end;qtSF2kh=oP else local J92nyajw=xB;local wBBO=dpl5Qr8i;local function k3gZQQ(...)return
|
|
Jzh["fennel-module"].dofile(J92nyajw,wBBO,...)end
|
|
qtSF2kh=k3gZQQ end;return qtSF2kh,xB else return nil end end
|
|
local function a6y99PLZ(TW5ElhE)local ytAdXO=Wd1a_i(TW5ElhE,package.path)
|
|
if(nil~=ytAdXO)then
|
|
local QzBDtoL=ytAdXO;local Wh5WXYH
|
|
do local BIqcT3KO=io.open(QzBDtoL)
|
|
local function Ggug(as,...)BIqcT3KO:close()if as then return...else return
|
|
error(...,0)end end
|
|
local function D4()return assert(BIqcT3KO:read("*a"))end
|
|
Wh5WXYH=Ggug(_G.xpcall(D4,(package.loaded.fennel or debug).traceback))end;local _j=WpQBPz(Wh5WXYH,gwje(),QzBDtoL)return _j,QzBDtoL else return nil end end;local Maun0kCg={HkFs_,a6y99PLZ}
|
|
local function X1okTW(bKRB,bqOmBw)local UlRBdf2T=Maun0kCg[bqOmBw]
|
|
if
|
|
(nil~=UlRBdf2T)then local WqG=UlRBdf2T;local jQ6ByW,hI=WqG(bKRB)
|
|
if((nil~=jQ6ByW)and true)then
|
|
local X=jQ6ByW;local fvOp=hI;return X,fvOp elseif true then local xIB=jQ6ByW;return X1okTW(bKRB,(bqOmBw+1))else
|
|
return nil end else return nil end end
|
|
local function IL(MJ)
|
|
if
|
|
((MJ=="fennel.macros")or
|
|
(package and package.loaded and("table"==
|
|
type(package.loaded[MJ]))and(
|
|
package.loaded[MJ].metadata==AHA.metadata)))then return{metadata=AHA.metadata,view=fNDs}else return nil end end
|
|
local function Txnp(gk4oh)
|
|
local function drQ()local WxqsgF,B7=X1okTW(gk4oh,1)
|
|
AHA.assert(WxqsgF,(gk4oh.." module not found."))do end(uA5vZEb)[gk4oh]=WxqsgF(gk4oh,B7)
|
|
return uA5vZEb[gk4oh]end
|
|
return(uA5vZEb[gk4oh]or IL(gk4oh)or drQ())end;SE0lo2=Txnp
|
|
local function k7(DRaen,cOdno7,Q7NwnLvM)
|
|
AHA.assert(Jzh["table?"](DRaen),"expected macros to be table",cOdno7)
|
|
for b55dl,vv7Mbm in pairs(DRaen)do
|
|
AHA.assert((type(vv7Mbm)=="function"),"expected each macro to be function",cOdno7)
|
|
AHA["check-binding-valid"](Jzh.sym(b55dl),Q7NwnLvM,cOdno7,{["macro?"]=true})do end(Q7NwnLvM.macros)[b55dl]=vv7Mbm end;return nil end
|
|
local function i4bMH(iHFG,mbY,klPjHrEL,fT)local iRHgEZ1=iHFG;local qe3O8z=iRHgEZ1["filename"]local _qk=iRHgEZ1[2]
|
|
local WwYOV=(qe3O8z or(
|
|
Jzh["table?"](_qk)and _qk.filename))local TzOhP=Jzh.root.options["module-name"]
|
|
local DYbu7=AHA.compile(_qk,fT)local cW=WpQBPz(DYbu7)return cW(TzOhP,WwYOV)end
|
|
O11E["require-macros"]=function(DzAYbnQN,v,iX,xTWLsd)
|
|
AHA.assert((#DzAYbnQN==2),"Expected one module name argument",(xTWLsd or DzAYbnQN))local et4qFvy=i4bMH(DzAYbnQN,v,iX,{})
|
|
AHA.assert(Jzh["string?"](et4qFvy),"module name must compile to string",(
|
|
xTWLsd or DzAYbnQN))
|
|
if not uA5vZEb[et4qFvy]then local j,u3d=X1okTW(et4qFvy,1)
|
|
AHA.assert(j,(et4qFvy..
|
|
" module not found."),DzAYbnQN)do end
|
|
(uA5vZEb)[et4qFvy]=AHA.assert(Jzh["table?"](j(et4qFvy,u3d)),"expected macros to be table",(
|
|
xTWLsd or DzAYbnQN))else end
|
|
if("import-macros"==tostring(DzAYbnQN[1]))then return
|
|
uA5vZEb[et4qFvy]else return k7(uA5vZEb[et4qFvy],DzAYbnQN,v,iX)end end
|
|
qh0m("require-macros",{"macro-module-name"},"Load given module and use its contents as macro definitions in current scope.\nMacro module should return a table of macro functions with string keys.\nConsider using import-macros instead as it is more flexible.")
|
|
local function o4u(Zk,IJlAF,PtNV,vGN)
|
|
local AmjRAd75=AHA["make-scope"](Jzh.root.scope.parent)local PmbHJr={}if Jzh.root.options.requireAsInclude then
|
|
AmjRAd75.specials.require=AHA["require-include"]else end
|
|
for Gyrd1C,SU2WbXNN in
|
|
S.parser(S["string-stream"](Zk),IJlAF)do table.insert(PmbHJr,SU2WbXNN)end
|
|
for oC5=1,#PmbHJr do local ZDm
|
|
if(oC5 ==#PmbHJr)then ZDm={tail=true}else ZDm={nval=0}end;Jzh["propagate-options"](PtNV,ZDm)
|
|
AHA.compile1(PmbHJr[oC5],AmjRAd75,vGN,ZDm)end;return nil end
|
|
local function XB(EauWm_Mc,hF5AiG,CaPHn8,kR,DeA)Jzh.root.scope.includes[kR]="fnl/loading"local dKC3Vzv
|
|
do
|
|
local cN=assert(io.open(CaPHn8))
|
|
local function lDwx(Ki,...)cN:close()if Ki then return...else return error(...,0)end end;local function oA()
|
|
return assert(cN:read("*all")):gsub("[\13\n]*$","")end
|
|
dKC3Vzv=lDwx(_G.xpcall(oA,(package.loaded.fennel or debug).traceback))end
|
|
local G=Jzh.expr(("require(\""..kR.."\")"),"statement")
|
|
local qx6M=("package.preload[%q]"):format(kR)
|
|
local q43=(qx6M.." = "..qx6M.." or function(...)")local CEjbsJ,XL={},{}AHA.emit(CEjbsJ,q43,EauWm_Mc)
|
|
AHA.emit(CEjbsJ,XL)AHA.emit(CEjbsJ,"end",EauWm_Mc)for cxdelc,YxaPQgT in ipairs(CEjbsJ)do
|
|
table.insert(Jzh.root.chunk,YxaPQgT)end
|
|
if DeA then
|
|
o4u(dKC3Vzv,CaPHn8,hF5AiG,XL)else AHA.emit(XL,dKC3Vzv,EauWm_Mc)end;Jzh.root.scope.includes[kR]=G;return G end
|
|
local function l38u_I3T(lZT0q,PSOCXW8,mJ47Xs,pttAKe)
|
|
if
|
|
(Jzh.root.scope.includes[lZT0q]=="fnl/loading")then
|
|
AHA.assert(mJ47Xs,"circular include detected",pttAKe)return mJ47Xs(PSOCXW8)else return nil end end
|
|
O11E.include=function(Qpnu6Q,BS_TVtF,AsPHBFDJ,Aedxu)
|
|
AHA.assert((#Qpnu6Q==2),"expected one argument",Qpnu6Q)local oUneh9
|
|
do
|
|
local Lz_usB,ljsvn5Qz=pcall(i4bMH,Qpnu6Q,BS_TVtF,AsPHBFDJ,Aedxu)
|
|
if((Lz_usB==true)and(nil~=ljsvn5Qz))then
|
|
local GgNU6=ljsvn5Qz
|
|
oUneh9=Jzh.expr(string.format("%q",GgNU6),"literal")elseif true then local NPz6M=Lz_usB
|
|
oUneh9=(AHA.compile1(Qpnu6Q[2],BS_TVtF,AsPHBFDJ,{nval=1}))[1]else oUneh9=nil end end
|
|
if((oUneh9.type~="literal")or
|
|
((oUneh9[1]):byte()~=34))then if Aedxu.fallback then return
|
|
Aedxu.fallback(oUneh9)else
|
|
return AHA.assert(false,"module name must be string literal",Qpnu6Q)end else local sY=WpQBPz(("return "..
|
|
oUneh9[1]))()
|
|
local eD2N=Jzh.root.options["module-name"]local lHWMtRj;Jzh.root.options["module-name"]=sY;lHWMtRj=nil
|
|
local ooD_xGt
|
|
local function b()local Zb2=Wd1a_i(sY)
|
|
if(nil~=Zb2)then local NWZMp=Zb2
|
|
return XB(Qpnu6Q,Aedxu,NWZMp,sY,true)elseif true then local pYT=Zb2;local tZED=Wd1a_i(sY,package.path)
|
|
if tZED then return
|
|
XB(Qpnu6Q,Aedxu,tZED,sY,false)elseif Aedxu.fallback then return Aedxu.fallback(oUneh9)else
|
|
return AHA.assert(false,(
|
|
"module not found "..sY),Qpnu6Q)end else return nil end end
|
|
ooD_xGt=(
|
|
|
|
|
|
(
|
|
Jzh["member?"](sY,(Jzh.root.options.skipInclude or{}))and Aedxu.fallback(oUneh9,true))or l38u_I3T(sY,oUneh9,Aedxu.fallback,Qpnu6Q)or Jzh.root.scope.includes[sY]or b())Jzh.root.options["module-name"]=eD2N;return ooD_xGt end end
|
|
qh0m("include",{"module-name-literal"},"Like require but load the target module during compilation and embed it in the\nLua output. The module must be a string literal and resolvable at compile time.")
|
|
local function ti5b(tNb4,CUAxP,HX6Kb86)local LIG=gwje(tNb4,CUAxP,HX6Kb86)
|
|
local oLlSHKfJ=Jzh.copy(Jzh.root.options)
|
|
oLlSHKfJ.scope=AHA["make-scope"](AHA.scopes.compiler)oLlSHKfJ.allowedGlobals=V(LIG)return
|
|
assert(WpQBPz(AHA.compile(tNb4,oLlSHKfJ),LhQHR(LIG)),oLlSHKfJ["module-name"],tNb4.filename)()end
|
|
O11E.macros=function(bpr7l0,EMna5yqq,d6Ctwa)
|
|
AHA.assert(((#bpr7l0 ==2)and Jzh["table?"](bpr7l0[2])),"Expected one table argument",bpr7l0)
|
|
return k7(ti5b(bpr7l0[2],EMna5yqq,d6Ctwa),bpr7l0,EMna5yqq,d6Ctwa)end
|
|
qh0m("macros",{"{:macro-name-1 (fn [...] ...) ... :macro-name-N macro-body-N}"},"Define all functions in the given table as macros local to the current scope.")
|
|
O11E["eval-compiler"]=function(VYLNRk,_yp,k8)local l=VYLNRk[1]VYLNRk[1]=Jzh.sym("do")
|
|
local fdIV=ti5b(VYLNRk,_yp,k8)do end(VYLNRk)[1]=l;return fdIV end
|
|
qh0m("eval-compiler",{"..."},"Evaluate the body at compile-time. Use the macro system instead if possible.",true)
|
|
return
|
|
{doc=YMl,["current-global-names"]=V,["load-code"]=WpQBPz,["macro-loaded"]=uA5vZEb,["macro-searchers"]=Maun0kCg,["make-compiler-env"]=gwje,["search-module"]=Wd1a_i,["make-searcher"]=ur,["wrap-env"]=LhQHR}end
|
|
package.preload["fennel.compiler"]=package.preload["fennel.compiler"]or
|
|
function(...)
|
|
local c=require("fennel.utils")local o=require("fennel.parser")
|
|
local yK=require("fennel.friend")local MAKgn=(table.unpack or _G.unpack)local x9FArgz={}
|
|
local function GmcCQbi(cx5uK)local uo=(cx5uK or
|
|
x9FArgz.global)local ZAia0D6l;if uo then
|
|
ZAia0D6l=((uo.depth or 0)+1)else ZAia0D6l=0 end
|
|
return
|
|
{includes=setmetatable({},{__index=(uo and uo.includes)}),macros=setmetatable({},{__index=(
|
|
uo and uo.macros)}),manglings=setmetatable({},{__index=(uo and
|
|
uo.manglings)}),specials=setmetatable({},{__index=(uo and uo.specials)}),symmeta=setmetatable({},{__index=(
|
|
uo and uo.symmeta)}),unmanglings=setmetatable({},{__index=(uo and
|
|
uo.unmanglings)}),gensyms=setmetatable({},{__index=(uo and
|
|
uo.gensyms)}),autogensyms=setmetatable({},{__index=(uo and uo.autogensyms)}),vararg=(
|
|
uo and uo.vararg),depth=ZAia0D6l,hashfn=(uo and uo.hashfn),refedglobals={},parent=uo}end
|
|
local function jtHWFj7(DjicYU,aX)local griKc
|
|
if("table"==type(DjicYU))then griKc=DjicYU else griKc={}end;local oPlKdB=getmetatable(DjicYU)
|
|
local ithf=(
|
|
(oPlKdB and oPlKdB.filename)or griKc.filename or"unknown")
|
|
local EOxrAqR=((oPlKdB and oPlKdB.line)or griKc.line or"?")
|
|
local W4MTO=((oPlKdB and oPlKdB.col)or griKc.col or"?")
|
|
local uzkTxapi=tostring((c["sym?"](griKc[1])or griKc[1]or"()"))return
|
|
string.format("%s:%s:%s Compile error in '%s': %s",ithf,EOxrAqR,W4MTO,uzkTxapi,aX)end
|
|
local function NV(m2e,Id1VK,j2NNb,kiRfka8)
|
|
if not m2e then local uteD3RU=(c.root.options or{})
|
|
local _yAm0f0Y=uteD3RU["source"]local UF=uteD3RU["unfriendly"]
|
|
local gV3vGZ4X=uteD3RU["error-pinpoint"]local NGrp;if next(c["ast-source"](j2NNb))then NGrp=j2NNb else
|
|
NGrp=(kiRfka8 or{})end
|
|
if(nil==
|
|
c.hook("assert-compile",m2e,Id1VK,NGrp,c.root.reset))then
|
|
c.root.reset()
|
|
if
|
|
(UF or not yK or not _G.io or not _G.io.read)then error(jtHWFj7(NGrp,Id1VK),0)else
|
|
yK["assert-compile"](m2e,Id1VK,NGrp,_yAm0f0Y,{["error-pinpoint"]=gV3vGZ4X})end else end else end;return m2e end;x9FArgz.global=GmcCQbi()x9FArgz.global.vararg=true
|
|
x9FArgz.compiler=GmcCQbi(x9FArgz.global)x9FArgz.macro=x9FArgz.global
|
|
local tQX2JQ3q={["\7"]="\\a",["\8"]="\\b",["\9"]="\\t",["\n"]="n",["\11"]="\\v",["\12"]="\\f"}
|
|
local function iIyPus(tQpA)local function V(x799K)return("\\"..x799K:byte())end;return
|
|
string.gsub(string.gsub(string.format("%q",tQpA),".",tQX2JQ3q),"[\128-\255]",V)end
|
|
local function UDoYdga(jZ)
|
|
if c["valid-lua-identifier?"](jZ)then return jZ else local function OmVG8lf(CgZsZTK)return
|
|
string.format("_%02x",CgZsZTK:byte())end;return("__fnl_global__"..
|
|
jZ:gsub("[^%w]",OmVG8lf))end end
|
|
local function u_URqAyP(lEc)local YaAvE=string.match(lEc,"^__fnl_global__(.*)$")
|
|
if
|
|
(nil~=YaAvE)then local yf3=YaAvE;local Bcs;local function vh77(Gq)
|
|
return string.char(tonumber(Gq:sub(2),16))end
|
|
Bcs=string.gsub(yf3,"_[%da-f][%da-f]",vh77)return Bcs elseif true then local IhMea=YaAvE;return lEc else return nil end end;local nxZZC=nil;local function DMZ(JfP4Aohm)return
|
|
(not nxZZC or c["member?"](JfP4Aohm,nxZZC))end
|
|
local function ebmBtt(F6q,K0,WSUP53i,f8pHDS)if
|
|
(
|
|
WSUP53i.unmanglings[K0]and not WSUP53i.gensyms[K0])then
|
|
return ebmBtt(F6q,(F6q..f8pHDS),WSUP53i,(f8pHDS+1))else return K0 end end
|
|
local function F6(r1hTTS,WaWBNK,e4qPh_,M1)
|
|
NV(not c["multi-sym?"](r1hTTS),("unexpected multi symbol "..r1hTTS),e4qPh_)local Fe
|
|
if
|
|
((c["lua-keywords"])[r1hTTS]or r1hTTS:match("^%d"))then Fe=("_"..r1hTTS)else Fe=r1hTTS end;local RK
|
|
local function p(eXTmm)return string.format("_%02x",eXTmm:byte())end
|
|
RK=string.gsub(string.gsub(Fe,"-","_"),"[^%w_]",p)local P0VL2vrZ=ebmBtt(RK,RK,WaWBNK,0)do end
|
|
(WaWBNK.unmanglings)[P0VL2vrZ]=r1hTTS;do local xy0J=(M1 or WaWBNK.manglings)do end
|
|
(xy0J)[r1hTTS]=P0VL2vrZ end;return P0VL2vrZ end
|
|
local function Mcv4zh(kN,Je,lbp)
|
|
for qc,SnR in pairs(Je)do
|
|
NV(not kN.refedglobals[SnR],("use of global "..
|
|
qc.." is aliased by a local"),lbp)do end(kN.manglings)[qc]=SnR end;return nil end
|
|
local function Aanl(uREm,sYd4vJv)
|
|
local Tp=(sYd4vJv.manglings[uREm[1]]or UDoYdga(uREm[1]))
|
|
for dL=2,#uREm do
|
|
if c["valid-lua-identifier?"](uREm[dL])then if(
|
|
uREm["multi-sym-method-call"]and(dL==#uREm))then Tp=(Tp..
|
|
":"..uREm[dL])else
|
|
Tp=(Tp.."."..uREm[dL])end else Tp=(Tp.."["..iIyPus(uREm[dL])..
|
|
"]")end end;return Tp end
|
|
local function VvZoG6()c.root.scope["gensym-append"]=(
|
|
(c.root.scope["gensym-append"]or 0)+1)return
|
|
(
|
|
"_"..c.root.scope["gensym-append"].."_")end
|
|
local function AjTaG(cv,YQ,f)
|
|
local yDOTU=((YQ or"")..VvZoG6().. (f or""))while cv.unmanglings[yDOTU]do
|
|
yDOTU=((YQ or"")..VvZoG6().. (f or""))end
|
|
cv.unmanglings[yDOTU]=(YQ or true)do end(cv.gensyms)[yDOTU]=true;return yDOTU end
|
|
local function oJv55vky(xs3HoM,CPt)xs3HoM[1]=CPt;local x25XhH=table.remove(xs3HoM)
|
|
local gdJk_iMs=table.remove(xs3HoM)
|
|
local I=((xs3HoM["multi-sym-method-call"]and":")or".")
|
|
table.insert(xs3HoM,(gdJk_iMs..I..x25XhH))return table.concat(xs3HoM,".")end
|
|
local function ecvFfcqw(sRldmKE8,J4S6iy)local e5Hi=c["multi-sym?"](sRldmKE8)
|
|
if(nil~=e5Hi)then local glqD=e5Hi;return
|
|
oJv55vky(glqD,ecvFfcqw(glqD[1],J4S6iy))elseif true then local HndLYXOs=e5Hi;local function hFfZ()
|
|
local _jVsRVIY=AjTaG(J4S6iy,sRldmKE8:sub(1,(-2)),"auto")do end(J4S6iy.autogensyms)[sRldmKE8]=_jVsRVIY
|
|
return _jVsRVIY end;return(
|
|
J4S6iy.autogensyms[sRldmKE8]or hFfZ())else return nil end end
|
|
local function giqEv(eF5jN,BMmEIl,co,tZQ)local YplB=tostring(eF5jN)local iuAKOawa
|
|
do local Y9ajqGT8=tZQ;if(nil~=Y9ajqGT8)then
|
|
Y9ajqGT8=(Y9ajqGT8)["macro?"]else end;iuAKOawa=Y9ajqGT8 end
|
|
NV(not YplB:find("&"),"invalid character: &",eF5jN)
|
|
NV(not YplB:find("^%."),"invalid character: .",eF5jN)
|
|
NV(not(BMmEIl.specials[YplB]or
|
|
(not iuAKOawa and BMmEIl.macros[YplB])),("local %s was overshadowed by a special form or macro"):format(YplB),co)return
|
|
NV(not c["quoted?"](eF5jN),string.format("macro tried to bind %s without gensym",YplB),eF5jN)end
|
|
local function DX(z,l,ed,WipOX,GepSAE)giqEv(z,ed,WipOX)local fVwL=tostring(z)
|
|
NV(not c["multi-sym?"](fVwL),(
|
|
"unexpected multi symbol "..fVwL),WipOX)do end(ed.symmeta)[fVwL]=l;return F6(fVwL,ed,WipOX,GepSAE)end
|
|
local function Ymc47(Vdr5iR,kSubWX2,TJFj3cha)
|
|
if not TJFj3cha.hashfn then return nil elseif(Vdr5iR=="$")then return"$1"elseif kSubWX2 then
|
|
if(kSubWX2 and
|
|
(kSubWX2[1]=="$"))then kSubWX2[1]="$1"else end;return table.concat(kSubWX2,".")else return nil end end
|
|
local function KU1TZ(epF2,e,w2rce)c.hook("symbol-to-expression",epF2,e,w2rce)
|
|
local SoO=epF2[1]local cvVVLDX=c["multi-sym?"](SoO)
|
|
local adFOO=(Ymc47(SoO,cvVVLDX,e)or SoO)local hq=(cvVVLDX or{adFOO})local qhy=(
|
|
((1 <#hq)and"expression")or"sym")
|
|
local YqkxFq=e.manglings[hq[1]]if(YqkxFq and e.symmeta[hq[1]])then
|
|
e.symmeta[hq[1]]["used"]=true else end
|
|
NV(not e.macros[hq[1]],"tried to reference a macro without calling it",epF2)
|
|
NV((not e.specials[hq[1]]or("require"==hq[1])),"tried to reference a special form without calling it",epF2)
|
|
NV((not w2rce or YqkxFq or("_ENV"==hq[1])or DMZ(hq[1])),(
|
|
"unknown identifier: "..tostring(hq[1])),epF2)if(nxZZC and not YqkxFq and e.parent)then
|
|
e.parent.refedglobals[hq[1]]=true else end
|
|
return c.expr(Aanl(hq,e),qhy)end
|
|
local function InEPht(RC1zQfj,tw7,Ia)
|
|
if(type(tw7)=="table")then return table.insert(RC1zQfj,tw7)else return
|
|
table.insert(RC1zQfj,{ast=Ia,leaf=tw7})end end
|
|
local function dAkZ7FOa(cO)
|
|
if cO.leaf then return cO elseif
|
|
(
|
|
(3 <=#cO)and(cO[(#cO-2)].leaf=="do")and not cO[(#cO-1)].leaf and(
|
|
cO[#cO].leaf=="end"))then local Yim0=dAkZ7FOa(cO[(#cO-1)])local KEgdrEJ={ast=cO.ast}
|
|
for cvE=1,(#cO-3)
|
|
do table.insert(KEgdrEJ,dAkZ7FOa(cO[cvE]))end
|
|
for _ZaOK6=1,#Yim0 do table.insert(KEgdrEJ,Yim0[_ZaOK6])end;return KEgdrEJ else return c.map(cO,dAkZ7FOa)end end
|
|
local function kUC7(cnMUYf,DAbP_w)
|
|
local function IsHliUG5(x63,GD,tZs8,ECC)local Wj8Z7ASU=tZs8
|
|
if x63.leaf then
|
|
GD[Wj8Z7ASU]=((GD[Wj8Z7ASU]or"").." "..x63.leaf)else
|
|
for DPBC0cEs,L3OyIW5 in ipairs(x63)do
|
|
if(L3OyIW5.leaf or(0 <#L3OyIW5))then
|
|
local IA=c["ast-source"](L3OyIW5.ast)if(ECC==IA.filename)then
|
|
Wj8Z7ASU=math.max(Wj8Z7ASU,(IA.line or 0))else end
|
|
Wj8Z7ASU=IsHliUG5(L3OyIW5,GD,Wj8Z7ASU,ECC)else end end end;return Wj8Z7ASU end;local onTM6={}
|
|
local wmHyhAu=IsHliUG5(cnMUYf,onTM6,1,DAbP_w.filename)for ZXlUnI=1,wmHyhAu do
|
|
if(onTM6[ZXlUnI]==nil)then onTM6[ZXlUnI]=""else end end
|
|
return table.concat(onTM6,"\n")end
|
|
local function PkKH(Yzt3,A3nycin,_AEiRFt,jA)
|
|
if A3nycin.leaf then local DthGg=c["ast-source"](A3nycin.ast)
|
|
local nAh1PSh=DthGg["filename"]local U3vmAAPu=DthGg["line"]
|
|
table.insert(Yzt3,{nAh1PSh,U3vmAAPu})return A3nycin.leaf else local QSzXH
|
|
do local CD7qMWN=_AEiRFt
|
|
if(CD7qMWN==true)then QSzXH=" "elseif
|
|
(CD7qMWN==false)then QSzXH=""elseif(CD7qMWN==_AEiRFt)then QSzXH=_AEiRFt elseif(CD7qMWN==nil)then QSzXH=""else
|
|
QSzXH=nil end end
|
|
local function ruKe(n3vXu)
|
|
if(n3vXu.leaf or(0 <#n3vXu))then
|
|
local dFb_c5=PkKH(Yzt3,n3vXu,QSzXH,(jA+1))if(0 <jA)then return
|
|
(QSzXH..dFb_c5:gsub("\n",("\n"..QSzXH)))else return dFb_c5 end else return
|
|
nil end end;return table.concat(c.map(A3nycin,ruKe),"\n")end end;local GMU={}
|
|
local function RW1e(qvF9jB)local iCXsXfm=qvF9jB:gsub("\n"," ")if(#iCXsXfm<=49)then return("[fennel \""..
|
|
iCXsXfm.."\"]")else
|
|
return("[fennel \""..
|
|
iCXsXfm:sub(1,46).."...\"]")end end
|
|
local function RNgBFEJ(N3,_m6NeL)local F=dAkZ7FOa(N3)
|
|
if _m6NeL.correlate then return kUC7(F,_m6NeL),{}else local knSWmSCb={}
|
|
local hlAd5h=PkKH(knSWmSCb,F,_m6NeL.indent,0)
|
|
knSWmSCb.short_src=(_m6NeL.filename or
|
|
RW1e((_m6NeL.source or hlAd5h)))if _m6NeL.filename then knSWmSCb.key=("@".._m6NeL.filename)else
|
|
knSWmSCb.key=hlAd5h end
|
|
GMU[knSWmSCb.key]=knSWmSCb;return hlAd5h,knSWmSCb end end
|
|
local function RHynDt()local function b2W(Rws,bGa2mOf,bashk)
|
|
if Rws[bGa2mOf]then return Rws[bGa2mOf][bashk]else return nil end end
|
|
local function iJl45Gyi(fv,Feb5,rL,jpwnVCCw)
|
|
fv[Feb5]=(fv[Feb5]or{})do end(fv[Feb5])[rL]=jpwnVCCw;return Feb5 end
|
|
local function vFAMs7(uyFX,I9,...)local Hp5P=select("#",...)local nEEflJ={...}if((Hp5P%2)~=0)then
|
|
error("metadata:setall() expected even number of k/v pairs")else end
|
|
uyFX[I9]=(uyFX[I9]or{})
|
|
for dVk8=1,Hp5P,2 do uyFX[I9][nEEflJ[dVk8]]=nEEflJ[(dVk8+1)]end;return I9 end;return
|
|
setmetatable({},{__index={get=b2W,set=iJl45Gyi,setall=vFAMs7},__mode="k"})end
|
|
local function vlZT(h)return table.concat(c.map(h,tostring),", ")end
|
|
local function J4(N5jk,yKMj,h0AHFeQ,hdCy)local D=(h0AHFeQ or 1)
|
|
for DK9u0YCb=D,#N5jk do local U=N5jk[DK9u0YCb]
|
|
if(
|
|
(U.type=="expression")and(U[1]~="nil"))then
|
|
InEPht(yKMj,string.format("do local _ = %s end",tostring(U)),hdCy)elseif(U.type=="statement")then local h11S=tostring(U)local aog;if
|
|
(h11S:byte()==40)then aog=("do end "..h11S)else aog=h11S end
|
|
InEPht(yKMj,aog,hdCy)else end end;return nil end
|
|
local function LJ25_(Upy_Mt,XJUBj,h_P,qzvtR)
|
|
if h_P.nval then local ht9=h_P.nval;local zF4A=#Upy_Mt
|
|
if(ht9 ~=zF4A)then
|
|
if(ht9 <zF4A)then
|
|
J4(Upy_Mt,XJUBj,(ht9+1),qzvtR)for oH0K6DZg=(ht9+1),zF4A do Upy_Mt[oH0K6DZg]=nil end else
|
|
for AEY7dKrs=(#Upy_Mt+1),ht9
|
|
do Upy_Mt[AEY7dKrs]=c.expr("nil","literal")end end else end else end;if h_P.tail then
|
|
InEPht(XJUBj,string.format("return %s",vlZT(Upy_Mt)),qzvtR)else end
|
|
if h_P.target then local Q5=vlZT(Upy_Mt)local function x()if
|
|
(Q5 =="")then return"nil"else return Q5 end end
|
|
InEPht(XJUBj,string.format("%s = %s",h_P.target,x()),qzvtR)else end;if(h_P.tail or h_P.target)then return{returned=true}else local dVi6_P=Upy_Mt
|
|
dVi6_P["returned"]=true;return dVi6_P end end
|
|
local function OLj4enm5(M2fQsJF,tddLbjM)local t6Q6pok
|
|
do local vvXwPCvj=c["sym?"](M2fQsJF[1])
|
|
if(vvXwPCvj~=nil)then
|
|
local b_=tostring(vvXwPCvj)
|
|
if(b_~=nil)then t6Q6pok=tddLbjM.macros[b_]else t6Q6pok=b_ end else t6Q6pok=vvXwPCvj end end;local G=c["multi-sym?"](M2fQsJF[1])
|
|
if
|
|
(not t6Q6pok and G)then local yl7conr=c["get-in"](tddLbjM.macros,G)
|
|
NV((not
|
|
tddLbjM.macros[G[1]]or(type(yl7conr)=="function")),"macro not found in imported macro module",M2fQsJF)return yl7conr else return t6Q6pok end end
|
|
local function FQg2K(FWAIkjT,eWL7fHK2,S79K1)local fhfqGa2_=FWAIkjT;local dQc=fhfqGa2_["filename"]
|
|
local I86srgkM=fhfqGa2_["line"]local v=fhfqGa2_["bytestart"]local EK32N4wh=fhfqGa2_["byteend"]
|
|
do
|
|
local MwQfI=c["ast-source"](S79K1)
|
|
if
|
|
(("table"==type(S79K1))and(dQc~=MwQfI.filename))then
|
|
MwQfI.filename,MwQfI.line,MwQfI["from-macro?"]=dQc,I86srgkM,true;MwQfI.bytestart,MwQfI.byteend=v,EK32N4wh else end end;return("table"==type(S79K1))end
|
|
local function OLgj(BT_T,JC,q2rs9pTJ)
|
|
if(q2rs9pTJ and c["list?"](q2rs9pTJ))then for g=1,c.maxn(q2rs9pTJ)
|
|
do local T=q2rs9pTJ[g]
|
|
if(T==nil)then q2rs9pTJ[g]=c.sym("nil")else end end else end;return BT_T,JC,q2rs9pTJ end
|
|
local function rYNRAyG(HIg,eI)local function _T(...)return HIg(eI(...))end;return _T end
|
|
local function NocqXl(qK)local mnkmJQ=false;for nMao_eYE,d12vfJ in pairs(x9FArgz.global.macros)do if mnkmJQ then break end
|
|
mnkmJQ=(d12vfJ==qK)end;return mnkmJQ end
|
|
local function yQ(tytmwlxc,OA,uQHs)local M
|
|
if c["list?"](tytmwlxc)then M=OLj4enm5(tytmwlxc,OA)else M=nil end
|
|
if(M==false)then return tytmwlxc elseif(nil~=M)then local Xwnj=M;local X=x9FArgz.macro;local q0u
|
|
x9FArgz.macro=OA;q0u=nil;local zp7rS,pQk=nil,nil
|
|
local function tGaZiY()return Xwnj(MAKgn(tytmwlxc,2))end;local function YDlJrk()
|
|
if NocqXl(Xwnj)then return tostring else return debug.traceback end end
|
|
zp7rS,pQk=xpcall(tGaZiY,YDlJrk())local NQBP
|
|
do local q=tytmwlxc;local function tUAV(...)return FQg2K(q,...)end;NQBP=tUAV end;c["walk-tree"](pQk,rYNRAyG(NQBP,OLgj))
|
|
x9FArgz.macro=X;NV(zp7rS,pQk,tytmwlxc)if(uQHs or not pQk)then return pQk else
|
|
return yQ(pQk,OA)end elseif true then local xv=M;return tytmwlxc else return nil end end
|
|
local function EwFK(ginI,Wlq9,ecX,sX3K5d,RUn)
|
|
local p0=(RUn(ginI,Wlq9,ecX,sX3K5d)or c.expr("nil","literal"))local L
|
|
if("table"~=type(p0))then L=c.expr(p0,"expression")else L=p0 end;local J;if c["expr?"](L)then J={L}else J=L end;if not J.returned then return
|
|
LJ25_(J,ecX,sX3K5d,ginI)elseif(sX3K5d.tail or sX3K5d.target)then
|
|
return{returned=true}else return J end end
|
|
local function hktG(FK8Vu,af6z,qwS5Kv8Y,qHLkk,RHbe,fr)local x5rjM79={}
|
|
local gHZ4=(RHbe(FK8Vu[1],af6z,qwS5Kv8Y,{nval=1}))[1]
|
|
NV((c["sym?"](FK8Vu[1])or c["list?"](FK8Vu[1])or(
|
|
"string"==type(FK8Vu[1]))),(
|
|
"cannot call literal value "..tostring(FK8Vu[1])),FK8Vu)
|
|
for cDCm3L=2,fr do local qIrrbtNR;local f;if(cDCm3L~=fr)then f=1 else f=nil end
|
|
qIrrbtNR=RHbe(FK8Vu[cDCm3L],af6z,qwS5Kv8Y,{nval=f})table.insert(x5rjM79,qIrrbtNR[1])
|
|
if(cDCm3L==fr)then
|
|
for wMlh=2,#qIrrbtNR
|
|
do table.insert(x5rjM79,qIrrbtNR[wMlh])end else J4(qIrrbtNR,qwS5Kv8Y,2,FK8Vu[cDCm3L])end end;local qzzd2;if("string"==type(FK8Vu[1]))then qzzd2="(%s)(%s)"else
|
|
qzzd2="%s(%s)"end
|
|
local a55z=string.format(qzzd2,tostring(gHZ4),vlZT(x5rjM79))
|
|
return LJ25_({c.expr(a55z,"statement")},qwS5Kv8Y,qHLkk,FK8Vu)end
|
|
local function mdnF1t7H(vqUAUF,XyUcN2,b,e,kRR0gCs)c.hook("call",vqUAUF,XyUcN2)local NaPmL1D0=#vqUAUF
|
|
local dSaums=vqUAUF[1]local S=c["multi-sym?"](dSaums)
|
|
local i=(c["sym?"](dSaums)and
|
|
XyUcN2.specials[tostring(dSaums)])
|
|
NV((0 <NaPmL1D0),"expected a function, macro, or special to call",vqUAUF)
|
|
if i then return EwFK(vqUAUF,XyUcN2,b,e,i)elseif
|
|
(S and S["multi-sym-method-call"])then
|
|
local lG=table.concat({MAKgn(S,1,(#S-1))},".")local z_Tcg40=S[#S]
|
|
local v99Eubm_=c.list(c.sym(":",vqUAUF),c.sym(lG,vqUAUF),z_Tcg40,select(2,MAKgn(vqUAUF)))return kRR0gCs(v99Eubm_,XyUcN2,b,e)else return
|
|
hktG(vqUAUF,XyUcN2,b,e,kRR0gCs,NaPmL1D0)end end
|
|
local function Ipu2m(L,OW,Pk,jZC)local aANg
|
|
if OW.hashfn then aANg="use $... in hashfn"else aANg="unexpected vararg"end;NV(OW.vararg,aANg,L)return
|
|
LJ25_({c.expr("...","varg")},Pk,jZC,L)end
|
|
local function pw(gJERvk,C,ulnCs,I1PompP)local kFfd=c["multi-sym?"](gJERvk)
|
|
NV(not(kFfd and
|
|
kFfd["multi-sym-method-call"]),"multisym method calls may only be in call position",gJERvk)local ptZu;if(gJERvk[1]=="nil")then ptZu=c.expr("nil","literal")else
|
|
ptZu=KU1TZ(gJERvk,C,true)end;return
|
|
LJ25_({ptZu},ulnCs,I1PompP,gJERvk)end
|
|
local function bEVb7wKP(DE)local Du4=string.gsub(tostring(DE),",",".")return Du4 end
|
|
local function t5(SSAn4IhM,hAc48KE,ar,Ba)local CEJh
|
|
do local y=type(SSAn4IhM)
|
|
if(y=="nil")then CEJh=tostring elseif(y=="boolean")then
|
|
CEJh=tostring elseif(y=="string")then CEJh=iIyPus elseif(y=="number")then CEJh=bEVb7wKP else CEJh=nil end end;return
|
|
LJ25_({c.expr(CEJh(SSAn4IhM),"literal")},ar,Ba)end
|
|
local function W(n,R,smU7,c5AhRP,g6eSS)
|
|
local function iSB4(PspqBYWi)
|
|
if((type(PspqBYWi)=="string")and
|
|
c["valid-lua-identifier?"](PspqBYWi))then
|
|
return PspqBYWi else local aKa=g6eSS(PspqBYWi,R,smU7,{nval=1})local aB50mWe=aKa[1]return("["..
|
|
tostring(aB50mWe).."]")end end;local t3={}local fK9GSH1H
|
|
do local r={}local kij3KeD=#r
|
|
for Am,hTuL in ipairs(n)do local gNb4;do
|
|
local KiIGeo=((nil~=n[(Am+1)])and 1)do end(t3)[Am]=true
|
|
gNb4=vlZT(g6eSS(hTuL,R,smU7,{nval=KiIGeo}))end;if(nil~=gNb4)then
|
|
kij3KeD=(kij3KeD+1)do end(r)[kij3KeD]=gNb4 else end end;fK9GSH1H=r end
|
|
do local mF1ld_=fK9GSH1H;local X=#mF1ld_
|
|
for U8k,k_chsz6 in c.stablepairs(n)do local iUxhGdT
|
|
if not t3[U8k]then
|
|
local rPKPQif_=g6eSS(n[U8k],R,smU7,{nval=1})local J0j1SU=rPKPQif_[1]
|
|
iUxhGdT=string.format("%s = %s",iSB4(U8k),tostring(J0j1SU))else iUxhGdT=nil end
|
|
if(nil~=iUxhGdT)then X=(X+1)do end(mF1ld_)[X]=iUxhGdT else end end end;return
|
|
LJ25_({c.expr(("{"..table.concat(fK9GSH1H,", ").."}"),"expression")},smU7,c5AhRP,n)end
|
|
local function bR(DCDWGkDl,E5Nj,llO8EB,Jvnrey)local owikY=(Jvnrey or{})local N=yQ(DCDWGkDl,E5Nj)
|
|
if c["list?"](N)then return
|
|
mdnF1t7H(N,E5Nj,llO8EB,owikY,bR)elseif c["varg?"](N)then
|
|
return Ipu2m(N,E5Nj,llO8EB,owikY)elseif c["sym?"](N)then return pw(N,E5Nj,llO8EB,owikY)elseif
|
|
(type(N)=="table")then return W(N,E5Nj,llO8EB,owikY,bR)elseif
|
|
(
|
|
(type(N)=="nil")or
|
|
(type(N)=="boolean")or(type(N)=="number")or(type(N)=="string"))then return t5(N,E5Nj,llO8EB,owikY)else return
|
|
NV(false,("could not compile value of type "..type(N)),N)end end
|
|
local function j(t020SI,y5,Oo3,cg2kN,zCRI,Cv)local lTO4YUOr=(Cv or{})local O=lTO4YUOr;local Ct=O["isvar"]
|
|
local h9c8Ovm=O["declaration"]local IYPxIPBY=O["forceglobal"]local jYuK=O["forceset"]
|
|
local co=O["symtype"]local ak_o86=("_".. (co or"dst"))local _kZceDj;if h9c8Ovm then
|
|
_kZceDj="local %s = %s"else _kZceDj="%s = %s"end;local x6lv={}
|
|
local function zPB2j5(heekSOxE,hfFER4)
|
|
local wKVPCR=heekSOxE[1]
|
|
NV(not
|
|
(lTO4YUOr.nomulti and c["multi-sym?"](wKVPCR)),("unexpected multi symbol "..wKVPCR),hfFER4)
|
|
if h9c8Ovm then return DX(heekSOxE,nil,cg2kN,heekSOxE,x6lv)else local kLzrcX=(
|
|
c["multi-sym?"](wKVPCR)or{wKVPCR})
|
|
local T0t27=cg2kN.symmeta[kLzrcX[1]]
|
|
NV(not wKVPCR:find(":"),"cannot set method sym",heekSOxE)
|
|
if((#kLzrcX==1)and not jYuK)then
|
|
NV(not
|
|
(IYPxIPBY and T0t27),string.format("global %s conflicts with local",tostring(heekSOxE)),heekSOxE)
|
|
NV(not(T0t27 and not T0t27.var),("expected var "..wKVPCR),heekSOxE)else end
|
|
NV((T0t27 or not lTO4YUOr.noundef or DMZ(kLzrcX[1])),(
|
|
"expected local "..kLzrcX[1]),heekSOxE)
|
|
if IYPxIPBY then
|
|
NV(not cg2kN.symmeta[cg2kN.unmanglings[wKVPCR]],(
|
|
"global "..wKVPCR.." conflicts with local"),heekSOxE)do end(cg2kN.manglings)[wKVPCR]=UDoYdga(wKVPCR)do end
|
|
(cg2kN.unmanglings)[UDoYdga(wKVPCR)]=wKVPCR;if nxZZC then table.insert(nxZZC,wKVPCR)else end else end;return KU1TZ(heekSOxE,cg2kN)[1]end end
|
|
local function Vbha15(hH7AQO8)local oKL
|
|
local function xkSmP6pc(eKu)if cg2kN.manglings[eKu]then return eKu else return"nil"end end;oKL=c.map(hH7AQO8,xkSmP6pc)
|
|
local TWh=table.concat(oKL,", ")local iKtr1rn=table.concat(hH7AQO8,", ")local lIpLR=zCRI[#zCRI]
|
|
local itYH_s=#zCRI;local auwI=bR(y5,cg2kN,zCRI,{target=iKtr1rn})
|
|
if h9c8Ovm then
|
|
for EJkoz9TG=itYH_s,#zCRI do if(
|
|
zCRI[EJkoz9TG]==lIpLR)then itYH_s=EJkoz9TG else end end
|
|
if
|
|
((#zCRI== (itYH_s+1))and zCRI[#zCRI].leaf)then
|
|
zCRI[#zCRI]["leaf"]=("local "..zCRI[#zCRI].leaf)elseif(TWh=="nil")then
|
|
table.insert(zCRI,(itYH_s+1),{ast=Oo3,leaf=("local "..iKtr1rn)})else
|
|
table.insert(zCRI,(itYH_s+1),{ast=Oo3,leaf=("local "..iKtr1rn.." = "..TWh)})end else end;return auwI end
|
|
local function ed87(PFts,Kmx8KY,u,Sw)local h=zPB2j5(PFts,u)giqEv(PFts,cg2kN,PFts)if Sw then Vbha15({h})else
|
|
InEPht(zCRI,_kZceDj:format(h,vlZT(Kmx8KY)),PFts)end;if h9c8Ovm then
|
|
cg2kN.symmeta[tostring(PFts)]={var=Ct}return nil else return nil end end
|
|
local cQpXgEU="function (t, k, e)\n local mt = getmetatable(t)\n if 'table' == type(mt) and mt.__fennelrest then\n return mt.__fennelrest(t, k)\n elseif e then\n local rest = {}\n for k, v in pairs(t) do\n if not e[k] then rest[k] = v end\n end\n return rest\n else\n return {(table.unpack or unpack)(t, k)}\n end\n end"
|
|
local function Un(YAGQ,QpbS,X,zMYQn,e44sGdEP)local JiNz;local g6f0msRL
|
|
do local zCIa={}local JGaFbCP=#zCIa
|
|
for jS,qqwBy in ipairs(zMYQn)do
|
|
local tkXDi5H=string.format("[%s] = true",iIyPus(qqwBy))if(nil~=tkXDi5H)then JGaFbCP=(JGaFbCP+1)do end
|
|
(zCIa)[JGaFbCP]=tkXDi5H else end end;g6f0msRL=zCIa end;JiNz=table.concat(g6f0msRL,", ")
|
|
local RN=c.expr(string.format(string.gsub(("("..cQpXgEU..
|
|
")(%s, %s, {%s})"),"\n%s*"," "),YAGQ,tostring(QpbS),JiNz),"expression")return e44sGdEP(QpbS,{RN},X)end
|
|
local function D20xd6lP(aZ,GUV6o,Ryrka,Dv0ij)local Zq3F=("("..cQpXgEU..")(%s, %s)")
|
|
local jTc7jO=string.format(string.gsub(Zq3F,"\n%s*"," "),aZ,GUV6o)local VJvN=c.expr(jTc7jO,"expression")
|
|
NV((c["sequence?"](Ryrka)and(nil==Ryrka[(
|
|
GUV6o+2)])),"expected rest argument before last parameter",Ryrka)return Dv0ij(Ryrka[(GUV6o+1)],{VJvN},Ryrka)end
|
|
local function wp(d5GIIXgv,KI,KzaQmB,GmzMFiB)local q7EKMsXa=AjTaG(cg2kN,ak_o86)local q
|
|
do local QeuDq;if KzaQmB then
|
|
QeuDq=vlZT(bR(y5,cg2kN,zCRI))else QeuDq=vlZT(KI)end;if(QeuDq=="")then q="nil"elseif
|
|
(nil~=QeuDq)then local WKxwJ3v=QeuDq;q=WKxwJ3v else q=nil end end;local pgSM2={}
|
|
InEPht(zCRI,string.format("local %s = %s",q7EKMsXa,q),d5GIIXgv)
|
|
for e5k35Eaj,ciF6Ity7 in c.stablepairs(d5GIIXgv)do
|
|
if
|
|
not(("number"==type(e5k35Eaj))and
|
|
tostring(d5GIIXgv[(
|
|
e5k35Eaj-1)]):find("^&"))then
|
|
if
|
|
(c["sym?"](e5k35Eaj)and(tostring(e5k35Eaj)=="&"))then Un(q7EKMsXa,ciF6Ity7,d5GIIXgv,pgSM2,GmzMFiB)elseif
|
|
(
|
|
c["sym?"](ciF6Ity7)and(tostring(ciF6Ity7)=="&"))then D20xd6lP(q7EKMsXa,e5k35Eaj,d5GIIXgv,GmzMFiB)elseif
|
|
(
|
|
c["sym?"](e5k35Eaj)and(tostring(e5k35Eaj)=="&as"))then
|
|
ed87(ciF6Ity7,{c.expr(tostring(q7EKMsXa))},d5GIIXgv)elseif
|
|
(c["sequence?"](d5GIIXgv)and(tostring(ciF6Ity7)=="&as"))then local Yioa,jqmrXZN,rrhjem=select(e5k35Eaj,MAKgn(d5GIIXgv))
|
|
NV((nil==rrhjem),"expected &as argument before last parameter",d5GIIXgv)
|
|
ed87(jqmrXZN,{c.expr(tostring(q7EKMsXa))},d5GIIXgv)else local LuhmtOo;if(type(e5k35Eaj)=="string")then
|
|
LuhmtOo=iIyPus(e5k35Eaj)else LuhmtOo=e5k35Eaj end
|
|
local KoVtk1=c.expr(string.format("%s[%s]",q7EKMsXa,LuhmtOo),"expression")if(type(e5k35Eaj)=="string")then
|
|
table.insert(pgSM2,e5k35Eaj)else end
|
|
GmzMFiB(ciF6Ity7,{KoVtk1},d5GIIXgv)end else end end;return nil end
|
|
local function ex0q(GA35ewy,Go,woCOxKH6,WE_F3BIp)local Zi6U,yPu={},{}
|
|
for avu,AZEX5w in ipairs(GA35ewy)do
|
|
if c["sym?"](AZEX5w)then
|
|
table.insert(Zi6U,zPB2j5(AZEX5w,Go))else local yy0EEYQ=AjTaG(cg2kN,ak_o86)table.insert(Zi6U,yy0EEYQ)
|
|
do end(yPu)[avu]={AZEX5w,c.expr(yy0EEYQ,"sym")}end end
|
|
NV(GA35ewy[1],"must provide at least one value",GA35ewy)
|
|
NV(woCOxKH6,"can't nest multi-value destructuring",GA35ewy)Vbha15(Zi6U)if h9c8Ovm then
|
|
for vR8xV,JXNn in ipairs(GA35ewy)do if c["sym?"](JXNn)then
|
|
cg2kN.symmeta[tostring(JXNn)]={var=Ct}else end end else end;for QJ,u4tU3kYo in
|
|
c.stablepairs(yPu)do
|
|
WE_F3BIp(u4tU3kYo[1],{u4tU3kYo[2]},GA35ewy)end;return nil end
|
|
local function Q(q5gGB,m,CnC_MjCI,X7r)
|
|
if
|
|
(c["sym?"](q5gGB)and(q5gGB[1]~="nil"))then ed87(q5gGB,m,CnC_MjCI,X7r)elseif c["table?"](q5gGB)then
|
|
wp(q5gGB,m,X7r,Q)elseif c["list?"](q5gGB)then ex0q(q5gGB,CnC_MjCI,X7r,Q)else
|
|
NV(false,string.format("unable to bind %s %s",type(q5gGB),tostring(q5gGB)),(
|
|
((
|
|
type((CnC_MjCI)[2])=="table")and(CnC_MjCI)[2])or CnC_MjCI))end;if X7r then return{returned=true}else return nil end end;local LJLY=Q(t020SI,nil,Oo3,true)
|
|
c.hook("destructure",y5,t020SI,cg2kN,lTO4YUOr)Mcv4zh(cg2kN,x6lv,Oo3)return LJLY end
|
|
local function vj8X8(v1M,jMZowtY,F2Ag,B5)
|
|
B5.fallback=function(t7JvZV8,YkP6u)if
|
|
(not YkP6u and("literal"==t7JvZV8.type))then
|
|
c.warn(("include module not found, falling back to require: %s"):format(tostring(t7JvZV8)))else end;return
|
|
c.expr(string.format("require(%s)",tostring(t7JvZV8)),"statement")end
|
|
return x9FArgz.global.specials.include(v1M,jMZowtY,F2Ag,B5)end
|
|
local function yEPu9(SFR,Pbo)local qmUhVMk=c.copy(Pbo)local cp=nxZZC
|
|
local YsQ6AR=(qmUhVMk.scope or GmcCQbi(x9FArgz.global))local MHzfC8Da={}local GP6v={}do end
|
|
(function(fLu_u8rB,K7kcm09M,...)
|
|
return fLu_u8rB[K7kcm09M](fLu_u8rB,...)end)(c.root,"set-reset")nxZZC=qmUhVMk.allowedGlobals;if(qmUhVMk.indent==nil)then
|
|
qmUhVMk.indent=" "else end;if qmUhVMk.requireAsInclude then
|
|
YsQ6AR.specials.require=vj8X8 else end
|
|
c.root.chunk,c.root.scope,c.root.options=GP6v,YsQ6AR,qmUhVMk;for l,LSQ44 in o.parser(SFR,qmUhVMk.filename,qmUhVMk)do
|
|
table.insert(MHzfC8Da,LSQ44)end
|
|
for MQ=1,#MHzfC8Da do
|
|
local Kqs=bR(MHzfC8Da[MQ],YsQ6AR,GP6v,{nval=(((MQ<
|
|
#MHzfC8Da)and 0)or nil),tail=(MQ==
|
|
#MHzfC8Da)})J4(Kqs,GP6v,nil,MHzfC8Da[MQ])if(MQ==#MHzfC8Da)then
|
|
c.hook("chunk",MHzfC8Da[MQ],YsQ6AR)else end end;nxZZC=cp;c.root.reset()return RNgBFEJ(GP6v,qmUhVMk)end
|
|
local function quzRC6(_83FZ,fCIdb)local g6O=(fCIdb or{})return
|
|
yEPu9(o["string-stream"](_83FZ,g6O),g6O)end
|
|
local function iEYTX(HDh,iTiEO)local VJW6T=c.copy(iTiEO)local fb6Qq=nxZZC;local RfOt={}local SN6a=(VJW6T.scope or
|
|
GmcCQbi(x9FArgz.global))do end
|
|
(function(OqTYUcdr,J,...)return
|
|
OqTYUcdr[J](OqTYUcdr,...)end)(c.root,"set-reset")nxZZC=VJW6T.allowedGlobals
|
|
if(VJW6T.indent==nil)then VJW6T.indent=" "else end
|
|
if VJW6T.requireAsInclude then SN6a.specials.require=vj8X8 else end;c.root.chunk,c.root.scope,c.root.options=RfOt,SN6a,VJW6T
|
|
local WcA3=bR(HDh,SN6a,RfOt,{tail=true})J4(WcA3,RfOt,nil,HDh)c.hook("chunk",HDh,SN6a)nxZZC=fb6Qq
|
|
c.root.reset()return RNgBFEJ(RfOt,VJW6T)end
|
|
local function Sp(S0DENK1F)
|
|
if
|
|
((S0DENK1F.what=="C")and S0DENK1F.name)then
|
|
return string.format(" [C]: in function '%s'",S0DENK1F.name)elseif(S0DENK1F.what=="C")then return" [C]: in ?"else
|
|
local J=GMU[S0DENK1F.source]
|
|
if(J and J[S0DENK1F.currentline])then
|
|
if
|
|
((
|
|
J[S0DENK1F.currentline][1]or"unknown")~="unknown")then
|
|
S0DENK1F.short_src=GMU[("@"..J[S0DENK1F.currentline][1])].short_src else S0DENK1F.short_src=J.short_src end
|
|
S0DENK1F.currentline=(J[S0DENK1F.currentline][2]or-1)else end
|
|
if(S0DENK1F.what=="Lua")then
|
|
local function e5()if S0DENK1F.name then return
|
|
("'"..S0DENK1F.name.."'")else return"?"end end;return
|
|
string.format(" %s:%d: in function %s",S0DENK1F.short_src,S0DENK1F.currentline,e5())elseif
|
|
(S0DENK1F.short_src=="(tail call)")then return" (tail call)"else return
|
|
string.format(" %s:%d: in main chunk",S0DENK1F.short_src,S0DENK1F.currentline)end end end
|
|
local function AwIAH(vQu79UOU,N)local S0vTJW=tostring((vQu79UOU or""))
|
|
if
|
|
(
|
|
(
|
|
S0vTJW:find("^%g+:%d+:%d+ Compile error:.*")or S0vTJW:find("^%g+:%d+:%d+ Parse error:.*"))and not c["debug-on?"]("trace"))then return S0vTJW else local UABGh_2={}
|
|
if
|
|
(S0vTJW:find("^%g+:%d+:%d+ Compile error:")or
|
|
S0vTJW:find("^%g+:%d+:%d+ Parse error:"))then table.insert(UABGh_2,S0vTJW)else
|
|
local PHzMfa=S0vTJW:gsub("^[^:]*:%d+:%s+","runtime error: ")table.insert(UABGh_2,PHzMfa)end;table.insert(UABGh_2,"stack traceback:")
|
|
local r,GS4d49=false,(N or 2)
|
|
while not r do
|
|
do local pW5znfH=debug.getinfo(GS4d49,"Sln")if(pW5znfH==nil)then r=true elseif(
|
|
nil~=pW5znfH)then local OVcB0=pW5znfH
|
|
table.insert(UABGh_2,Sp(OVcB0))else end end;GS4d49=(GS4d49+1)end;return table.concat(UABGh_2,"\n")end end
|
|
local function U2q(qCFu_,q)
|
|
local function S(t4xJg,_F)if(type(t4xJg)=="number")then return t4xJg,q(_F)else
|
|
return qCFu_(t4xJg),q(_F)end end;return S end
|
|
local function NPXkKDrL(pagqb,jP)local KukhqhF={}local tbFyKhq,ItPQjEL1="",""
|
|
for uKeh,BPf in ipairs(pagqb)do
|
|
table.insert(KukhqhF,uKeh)tbFyKhq=(tbFyKhq..ItPQjEL1 ..BPf)ItPQjEL1=jP end
|
|
for Qz020OHY,s9g in c.stablepairs(pagqb)do if not KukhqhF[Qz020OHY]then
|
|
tbFyKhq=(tbFyKhq..ItPQjEL1 .."["..Qz020OHY..
|
|
"]".."="..s9g)ItPQjEL1=jP else end end;return tbFyKhq end
|
|
local function B5GZm(N4bio,aYX,x,HZL9a)local function KE(m)return B5GZm(m,aYX,x,HZL9a)end
|
|
if
|
|
c["varg?"](N4bio)then
|
|
NV(not HZL9a,"quoted ... may only be used at compile time",N4bio)return"_VARARG"elseif c["sym?"](N4bio)then local A9L5;if N4bio.filename then
|
|
A9L5=string.format("%q",N4bio.filename)else A9L5="nil"end
|
|
local l95c=tostring(N4bio)
|
|
NV(not HZL9a,"symbols may only be used at compile time",N4bio)
|
|
if(l95c:find("#$")or l95c:find("#[:.]"))then
|
|
return string.format("sym('%s', {filename=%s, line=%s})",ecvFfcqw(l95c,aYX),A9L5,(
|
|
N4bio.line or"nil"))else return
|
|
string.format("sym('%s', {quoted=true, filename=%s, line=%s})",l95c,A9L5,(N4bio.line or"nil"))end elseif
|
|
(c["list?"](N4bio)and c["sym?"](N4bio[1])and(
|
|
tostring(N4bio[1])=="unquote"))then local Xy4=N4bio[2]local Ij868=MAKgn(bR(Xy4,aYX,x))return Ij868[1]elseif
|
|
c["list?"](N4bio)then local N3R3hAdM;local function nh()return nil end
|
|
N3R3hAdM=c.kvmap(N4bio,U2q(nh,KE))local KPYd;if N4bio.filename then KPYd=string.format("%q",N4bio.filename)else
|
|
KPYd="nil"end
|
|
NV(not HZL9a,"lists may only be used at compile time",N4bio)
|
|
return
|
|
string.format(("setmetatable({filename=%s, line=%s, bytestart=%s, %s}"..", getmetatable(list()))"),KPYd,(
|
|
N4bio.line or"nil"),(N4bio.bytestart or"nil"),NPXkKDrL(N3R3hAdM,", "))elseif c["sequence?"](N4bio)then local HAXKQ=c.kvmap(N4bio,U2q(KE,KE))
|
|
local On=getmetatable(N4bio)local doWI
|
|
if On.filename then doWI=string.format("%q",On.filename)else doWI="nil"end;local ZLVJZ;if On then ZLVJZ=On.line else ZLVJZ="nil"end
|
|
return
|
|
string.format("setmetatable({%s}, {filename=%s, line=%s, sequence=%s})",NPXkKDrL(HAXKQ,", "),doWI,ZLVJZ,"(getmetatable(sequence()))['sequence']")elseif(type(N4bio)=="table")then
|
|
local ULZrlPf=c.kvmap(N4bio,U2q(KE,KE))local L5x1dCG=getmetatable(N4bio)local XPAFqHX;if L5x1dCG.filename then
|
|
XPAFqHX=string.format("%q",L5x1dCG.filename)else XPAFqHX="nil"end
|
|
local function yMPEU05()if L5x1dCG then
|
|
return L5x1dCG.line else return"nil"end end;return
|
|
string.format("setmetatable({%s}, {filename=%s, line=%s})",NPXkKDrL(ULZrlPf,", "),XPAFqHX,yMPEU05())elseif
|
|
(type(N4bio)=="string")then return iIyPus(N4bio)else return tostring(N4bio)end end
|
|
return
|
|
{compile=iEYTX,compile1=bR,["compile-stream"]=yEPu9,["compile-string"]=quzRC6,["check-binding-valid"]=giqEv,emit=InEPht,destructure=j,["require-include"]=vj8X8,autogensym=ecvFfcqw,gensym=AjTaG,["do-quote"]=B5GZm,["global-mangling"]=UDoYdga,["global-unmangling"]=u_URqAyP,["apply-manglings"]=Mcv4zh,macroexpand=yQ,["declare-local"]=DX,["make-scope"]=GmcCQbi,["keep-side-effects"]=J4,["symbol-to-expression"]=KU1TZ,assert=NV,scopes=x9FArgz,traceback=AwIAH,metadata=RHynDt(),sourcemap=GMU}end
|
|
package.preload["fennel.friend"]=package.preload["fennel.friend"]or
|
|
function(...)
|
|
local FA=require("fennel.utils")local PRn,x3Iv=pcall(require,"utf8")
|
|
local PUNI={["unexpected multi symbol (.*)"]={"removing periods or colons from %s"},["use of global (.*) is aliased by a local"]={"renaming local %s","refer to the global using _G.%s instead of directly"},["local (.*) was overshadowed by a special form or macro"]={"renaming local %s"},["global (.*) conflicts with local"]={"renaming local %s"},["expected var (.*)"]={"declaring %s using var instead of let/local","introducing a new local instead of changing the value of %s"},["expected macros to be table"]={"ensuring your macro definitions return a table"},["expected each macro to be function"]={"ensuring that the value for each key in your macros table contains a function","avoid defining nested macro tables"},["macro not found in macro module"]={"checking the keys of the imported macro module's returned table"},["macro tried to bind (.*) without gensym"]={"changing to %s# when introducing identifiers inside macros"},["unknown identifier: (.*)"]={"looking to see if there's a typo","using the _G table instead, eg. _G.%s if you really want a global","moving this code to somewhere that %s is in scope","binding %s as a local in the scope of this code"},["expected a function.* to call"]={"removing the empty parentheses","using square brackets if you want an empty table"},["cannot call literal value"]={"checking for typos","checking for a missing function name","making sure to use prefix operators, not infix"},["unexpected vararg"]={"putting \"...\" at the end of the fn parameters if the vararg was intended"},["multisym method calls may only be in call position"]={"using a period instead of a colon to reference a table's fields","putting parens around this"},["unused local (.*)"]={"renaming the local to _%s if it is meant to be unused","fixing a typo so %s is used","disabling the linter which checks for unused locals"},["expected parameters"]={"adding function parameters as a list of identifiers in brackets"},["unable to bind (.*)"]={"replacing the %s with an identifier"},["expected rest argument before last parameter"]={"moving & to right before the final identifier when destructuring"},["expected vararg as last parameter"]={"moving the \"...\" to the end of the parameter list"},["expected symbol for function parameter: (.*)"]={"changing %s to an identifier instead of a literal value"},["could not compile value of type "]={"debugging the macro you're calling to return a list or table"},["expected local"]={"looking for a typo","looking for a local which is used out of its scope"},["expected body expression"]={"putting some code in the body of this form after the bindings"},["expected binding and iterator"]={"making sure you haven't omitted a local name or iterator"},["expected binding sequence"]={"placing a table here in square brackets containing identifiers to bind"},["expected even number of name/value bindings"]={"finding where the identifier or value is missing"},["may only be used at compile time"]={"moving this to inside a macro if you need to manipulate symbols/lists","using square brackets instead of parens to construct a table"},["unexpected closing delimiter (.)"]={"deleting %s","adding matching opening delimiter earlier"},["mismatched closing delimiter (.), expected (.)"]={"replacing %s with %s","deleting %s","adding matching opening delimiter earlier"},["expected even number of values in table literal"]={"removing a key","adding a value"},["expected whitespace before opening delimiter"]={"adding whitespace"},["invalid character: (.)"]={"deleting or replacing %s","avoiding reserved characters like \", \\, ', ~, ;, @, `, and comma"},["could not read number (.*)"]={"removing the non-digit character","beginning the identifier with a non-digit if it is not meant to be a number"},["can't start multisym segment with a digit"]={"removing the digit","adding a non-digit before the digit"},["malformed multisym"]={"ensuring each period or colon is not followed by another period or colon"},["method must be last component"]={"using a period instead of a colon for field access","removing segments after the colon","making the method call, then looking up the field on the result"},["$ and $... in hashfn are mutually exclusive"]={"modifying the hashfn so it only contains $... or $, $1, $2, $3, etc"},["tried to reference a macro without calling it"]={"renaming the macro so as not to conflict with locals"},["tried to reference a special form without calling it"]={"making sure to use prefix operators, not infix","wrapping the special in a function if you need it to be first class"},["missing subject"]={"adding an item to operate on"},["expected even number of pattern/body pairs"]={"checking that every pattern has a body to go with it","adding _ before the final body"},["expected at least one pattern/body pair"]={"adding a pattern and a body to execute when the pattern matches"},["unexpected arguments"]={"removing an argument","checking for typos"},["unexpected iterator clause"]={"removing an argument","checking for typos"}}local yglXRC=(table.unpack or _G.unpack)
|
|
local function mL(BJAK9Ks)local G2f6K0ep=nil
|
|
for O,s5h1F in
|
|
pairs(PUNI)do if G2f6K0ep then break end;local MNKK={BJAK9Ks:match(O)}
|
|
if
|
|
(0 <#MNKK)then local c={}local WH_XN=#c;for TZ,cTLR in ipairs(s5h1F)do
|
|
local dyWt=cTLR:format(yglXRC(MNKK))
|
|
if(nil~=dyWt)then WH_XN=(WH_XN+1)do end(c)[WH_XN]=dyWt else end end
|
|
G2f6K0ep=c else G2f6K0ep=nil end end;return G2f6K0ep end
|
|
local function Yri1Q(HssZ,E8Y8nr,Djh)
|
|
if Djh then
|
|
local xwn07_=string.gmatch((Djh.."\n"),"(.-)(\13?\n)")for dSxSJBHV=2,E8Y8nr do xwn07_()end;return xwn07_()else
|
|
local DvX4m=assert(io.open(HssZ))
|
|
local function EHkocd4(TF,...)DvX4m:close()if TF then return...else return error(...,0)end end
|
|
local function _fppKHWE()for G=2,E8Y8nr do DvX4m:read()end;return DvX4m:read()end;return
|
|
EHkocd4(_G.xpcall(_fppKHWE,(package.loaded.fennel or debug).traceback))end end
|
|
local function GI(DD7M1,Yd7Ju,F8undt)
|
|
if((F8undt<Yd7Ju)or(#DD7M1 <Yd7Ju)or
|
|
(#DD7M1 <F8undt))then return""elseif PRn then return
|
|
string.sub(DD7M1,x3Iv.offset(DD7M1,Yd7Ju),(
|
|
(x3Iv.offset(DD7M1,(
|
|
F8undt+1))or(x3Iv.len(DD7M1)+1))-1))else return
|
|
string.sub(DD7M1,Yd7Ju,math.min(F8undt,DD7M1:len()))end end
|
|
local function D(EFurB,fu76gq,l,YoBDM)
|
|
if
|
|
(
|
|
(YoBDM and(false==YoBDM["error-pinpoint"]))or
|
|
(os and os.getenv and os.getenv("NO_COLOR")))then return EFurB else local pL3X=(YoBDM or{})local VE4b=pL3X["error-pinpoint"]local r=(l or
|
|
fu76gq)local A7KNyC;if PRn then A7KNyC=x3Iv.len(EFurB)else
|
|
A7KNyC=string.len(EFurB)end
|
|
local vlF=(VE4b or{"\27[7m","\27[0m"})local A2x77Y=vlF[1]local TQz_=vlF[2]return
|
|
(GI(EFurB,1,fu76gq)..
|
|
A2x77Y..
|
|
GI(EFurB,(fu76gq+1),(r+1))..TQz_..GI(EFurB,(r+2),A7KNyC))end end
|
|
local function az(wLu6,MKSXwx,e76S8esN,X)local RAV=MKSXwx;local PbAL=RAV["filename"]local R_sPv=RAV["line"]
|
|
local eW=RAV["col"]local A3qe=RAV["endcol"]
|
|
local Y0y3jy9,HVk=pcall(Yri1Q,PbAL,R_sPv,e76S8esN)local Zy={wLu6,""}
|
|
if(Y0y3jy9 and HVk)then if eW then
|
|
table.insert(Zy,D(HVk,eW,A3qe,X))else table.insert(Zy,HVk)end else end;for DAty,oGG6AgYL in ipairs((mL(wLu6)or{}))do
|
|
table.insert(Zy,("* Try %s."):format(oGG6AgYL))end
|
|
return table.concat(Zy,"\n")end
|
|
local function HH(Ii,Jlhri4nq,jEuzZr,ATTgv,ajs26)
|
|
if not Ii then local qepF=FA["ast-source"](jEuzZr)
|
|
local DH4e=qepF["filename"]local XDtCsQ=qepF["line"]local Ky=qepF["col"]
|
|
error(az(("%s:%s:%s Compile error: %s"):format((
|
|
DH4e or"unknown"),(XDtCsQ or"?"),(Ky or"?"),Jlhri4nq),FA["ast-source"](jEuzZr),ATTgv,ajs26),0)else end;return Ii end
|
|
local function H(OibFuU,M1,j9bvMVL,BW,pfjF_e,fMF)return
|
|
error(az(("%s:%s:%s Parse error: %s"):format(M1,j9bvMVL,BW,OibFuU),{filename=M1,line=j9bvMVL,col=BW},pfjF_e,fMF),0)end;return{["assert-compile"]=HH,["parse-error"]=H}end
|
|
package.preload["fennel.parser"]=package.preload["fennel.parser"]or
|
|
function(...)
|
|
local A0ui_xDj=require("fennel.utils")local RtYZO=require("fennel.friend")
|
|
local ytsM1v=(table.unpack or _G.unpack)
|
|
local function vUM(QqBGI)local Ea1Ji,upw,ljxE8="",1,false
|
|
local function a0(pzJ)
|
|
if not ljxE8 then
|
|
if(upw<=#Ea1Ji)then
|
|
local v18fj=Ea1Ji:byte(upw)upw=(upw+1)return v18fj else local zpl=QqBGI(pzJ)local function IAA()local YgPmARR=zpl
|
|
return(YgPmARR~="")end
|
|
if((nil~=zpl)and IAA())then local M_eB5=zpl
|
|
Ea1Ji=M_eB5;upw=2;return Ea1Ji:byte()elseif true then local xny=zpl;ljxE8=true;return nil else return nil end end else return nil end end;local function BOvRs()Ea1Ji=""return nil end;return a0,BOvRs end
|
|
local function oh(mA0vj,x_Xh6D4u)local t=mA0vj:gsub("^#!",";;")
|
|
if x_Xh6D4u then x_Xh6D4u.source=t else end;local HEdMn87=1
|
|
local function J38BR2Q()local _g=t:byte(HEdMn87)HEdMn87=(HEdMn87+1)return _g end;return J38BR2Q end
|
|
local rnqUUVeM={[40]=41,[41]=true,[91]=93,[93]=true,[123]=125,[125]=true}
|
|
local function rOWFI0fU(J)local UrkN
|
|
if("number"==type(J))then UrkN=J else UrkN=string.byte(J)end
|
|
return
|
|
(
|
|
|
|
|
|
(32 <UrkN)and not rnqUUVeM[UrkN]and(UrkN~=127)and(UrkN~=34)and(UrkN~=39)and(UrkN~=126)and(UrkN~=59)and(UrkN~=44)and
|
|
(UrkN~=64)and
|
|
(UrkN~=96))end
|
|
local o3c6Rl={[35]="hashfn",[39]="quote",[44]="unquote",[96]="quote"}
|
|
local function T79c3QKh(tQZqIO1Q)
|
|
return
|
|
(
|
|
(function(NKHrge,mtkunlsA,jX4E)
|
|
return(NKHrge<mtkunlsA)and(mtkunlsA<jX4E)end)(1,tQZqIO1Q,127)or
|
|
(function(FI,j3P2lF2s,Xjco)return(FI<j3P2lF2s)and(j3P2lF2s<Xjco)end)(192,tQZqIO1Q,247))end
|
|
local function YBYPED(Gfcij3U,mS,y8A5iORL)local YE7pNsM=y8A5iORL;local GMXQ9pjP=YE7pNsM["source"]
|
|
local sPo=YE7pNsM["unfriendly"]local Cw2=YE7pNsM["comments"]local rSfPYb=YE7pNsM;local vUI={}
|
|
local W,Dvm,ThzhHC8,oD,jBA=1,0,0,0,nil
|
|
local function NUH(dJU6X6US)if T79c3QKh(dJU6X6US)then ThzhHC8=(ThzhHC8-1)else end;if(dJU6X6US==
|
|
10)then W,ThzhHC8=(W-1),oD else end;Dvm=(Dvm-1)
|
|
jBA=dJU6X6US;return nil end
|
|
local function xUshN()local WR=nil;if jBA then WR,jBA=jBA,nil else
|
|
WR=Gfcij3U({["stack-size"]=#vUI})end;Dvm=(Dvm+1)if
|
|
(WR and T79c3QKh(WR))then ThzhHC8=(ThzhHC8+1)else end;if(WR==10)then
|
|
W,ThzhHC8,oD=(W+1),0,ThzhHC8 else end;return WR end
|
|
local function oqTajz2H(XBTYDl)
|
|
local function i_Q5oQcn()local RSQH_ps=rSfPYb.whitespace;if(nil~=RSQH_ps)then
|
|
RSQH_ps=(RSQH_ps)[XBTYDl]else end;return RSQH_ps end;return
|
|
((XBTYDl==32)or
|
|
(function(xxZyIs,V,n8MwvK)return(xxZyIs<=V)and(V<=n8MwvK)end)(9,XBTYDl,13)or i_Q5oQcn())end
|
|
local function u(rs7w,z)local RSx=(ThzhHC8+ (z or-1))
|
|
if
|
|
(nil==
|
|
A0ui_xDj["hook-opts"]("parse-error",rSfPYb,rs7w,mS,(
|
|
W or"?"),RSx,GMXQ9pjP,A0ui_xDj.root.reset))then A0ui_xDj.root.reset()
|
|
if
|
|
(sPo or not _G.io or not _G.io.read)then return
|
|
error(string.format("%s:%s:%s Parse error: %s",mS,(W or"?"),RSx,rs7w),0)else return
|
|
RtYZO["parse-error"](rs7w,mS,(W or"?"),RSx,GMXQ9pjP,rSfPYb)end else return nil end end
|
|
local function GqRU()local Y9SrT,KgjuC5D,dLXo=true;local function a(pDWGL)pDWGL.byteend,pDWGL.endcol=Dvm,(ThzhHC8-1)
|
|
return nil end
|
|
local function e30(owl)local xuZmDL=vUI[#vUI]
|
|
if
|
|
(xuZmDL==nil)then dLXo,KgjuC5D,Y9SrT=owl,true,false;return nil elseif
|
|
(
|
|
(_G.type(xuZmDL)=="table")and(nil~= (xuZmDL).prefix))then local k3dt=(xuZmDL).prefix;local FbsHOx;do local eRFA=table.remove(vUI)
|
|
a(eRFA)FbsHOx=eRFA end
|
|
local Nmpf7Y=A0ui_xDj.list(A0ui_xDj.sym(k3dt,FbsHOx),owl)for N,e in pairs(FbsHOx)do Nmpf7Y[N]=e end;return e30(Nmpf7Y)elseif
|
|
(nil~=xuZmDL)then local pMSHZVp=xuZmDL;Y9SrT=false;return table.insert(pMSHZVp,owl)else return nil end end
|
|
local function d()local sRHJY=A0ui_xDj.map(vUI,"closer")local O6T9;if(#vUI==1)then O6T9=""else
|
|
O6T9="s"end;return
|
|
u(string.format("expected closing delimiter%s %s",O6T9,string.char(ytsM1v(sRHJY))))end
|
|
local function LU(bIMk4I)
|
|
if(bIMk4I and oqTajz2H(bIMk4I))then Y9SrT=true
|
|
return LU(xUshN())elseif(not bIMk4I and(0 <#vUI))then return d()else return bIMk4I end end
|
|
local function se(yw,U_)
|
|
if(yw and(10 ~=yw))then local function Mly4wFY()local T=U_
|
|
table.insert(T,string.char(yw))return T end
|
|
return se(xUshN(),Mly4wFY())elseif Cw2 then NUH(10)return
|
|
e30(A0ui_xDj.comment(table.concat(U_),{line=W,filename=mS}))else return nil end end
|
|
local function TDDCrC(b5HOXLHA)if not Y9SrT then
|
|
u(("expected whitespace before opening delimiter "..string.char(b5HOXLHA)))else end;return
|
|
table.insert(vUI,{bytestart=Dvm,closer=rnqUUVeM[b5HOXLHA],filename=mS,line=W,col=(
|
|
ThzhHC8-1)})end;local function ju(RgjJr)return
|
|
e30(setmetatable(RgjJr,getmetatable(A0ui_xDj.list())))end
|
|
local function VqvcJ4y(NqDxE)
|
|
local V=A0ui_xDj.sequence(ytsM1v(NqDxE))
|
|
for qKl_GZlm,nVn_8 in pairs(NqDxE)do getmetatable(V)[qKl_GZlm]=nVn_8 end;return e30(V)end
|
|
local function i(Xnk9Je,Oq1Dc,Av7Qv47)local y7LV0xwa=(Xnk9Je)[Oq1Dc]
|
|
if(nil~=y7LV0xwa)then local HDBjSc=y7LV0xwa;return
|
|
table.insert(HDBjSc,Av7Qv47)elseif true then local GX_f=y7LV0xwa;Xnk9Je[Oq1Dc]={Av7Qv47}return nil else
|
|
return nil end end
|
|
local function SM3OK(VdAu,dm)
|
|
if A0ui_xDj["comment?"](VdAu[dm])then return SM3OK(VdAu,(dm+1))elseif(
|
|
A0ui_xDj.sym(":")==VdAu[dm])then
|
|
return tostring(VdAu[(dm+1)])else return VdAu[dm]end end
|
|
local function E(S4nF)local ZZUqo={keys={},values={},last={}}while
|
|
A0ui_xDj["comment?"](S4nF[#S4nF])do
|
|
table.insert(ZZUqo.last,1,table.remove(S4nF))end;local YFHpCTL=false
|
|
for i7xH25eD,ndx in ipairs(S4nF)do
|
|
if not
|
|
A0ui_xDj["comment?"](ndx)then YFHpCTL=not YFHpCTL elseif YFHpCTL then
|
|
i(ZZUqo.values,SM3OK(S4nF,i7xH25eD),ndx)else i(ZZUqo.keys,SM3OK(S4nF,i7xH25eD),ndx)end end
|
|
for kNwL4W3Z=#S4nF,1,-1 do if A0ui_xDj["comment?"](S4nF[kNwL4W3Z])then
|
|
table.remove(S4nF,kNwL4W3Z)else end end;return ZZUqo end
|
|
local function cfbT(CmZ)local vOkOVV=E(CmZ)local TS={}local L54qaLo4={}if((#CmZ%2)~=0)then Dvm=(Dvm-1)
|
|
u("expected even number of values in table literal")else end
|
|
setmetatable(L54qaLo4,CmZ)
|
|
for GmQ=1,#CmZ,2 do
|
|
if
|
|
((tostring(CmZ[GmQ])==":")and
|
|
A0ui_xDj["sym?"](CmZ[(GmQ+1)])and A0ui_xDj["sym?"](CmZ[GmQ]))then CmZ[GmQ]=tostring(CmZ[(GmQ+1)])else end;L54qaLo4[CmZ[GmQ]]=CmZ[(GmQ+1)]
|
|
table.insert(TS,CmZ[GmQ])end;CmZ.comments=vOkOVV;CmZ.keys=TS;return e30(L54qaLo4)end
|
|
local function Oc0(GUtSmak1)local CjH=table.remove(vUI)if(CjH==nil)then
|
|
u(("unexpected closing delimiter "..
|
|
string.char(GUtSmak1)))else end
|
|
if(CjH.closer and
|
|
(CjH.closer~=GUtSmak1))then
|
|
u(("mismatched closing delimiter "..
|
|
|
|
string.char(GUtSmak1)..", expected "..string.char(CjH.closer)))else end;a(CjH)if(GUtSmak1 ==41)then return ju(CjH)elseif(GUtSmak1 ==93)then
|
|
return VqvcJ4y(CjH)else return cfbT(CjH)end end
|
|
local function kDAL(OQvQV,Fq5,RdWG30y)table.insert(OQvQV,Fq5)local ya6fjL5s
|
|
do local Yaqj6a1U={RdWG30y,Fq5}
|
|
if
|
|
(
|
|
(
|
|
_G.type(Yaqj6a1U)=="table")and((Yaqj6a1U)[1]=="base")and((Yaqj6a1U)[2]==92))then ya6fjL5s="backslash"elseif
|
|
((_G.type(Yaqj6a1U)=="table")and(
|
|
(Yaqj6a1U)[1]=="base")and
|
|
((Yaqj6a1U)[2]==34))then ya6fjL5s="done"elseif
|
|
((_G.type(Yaqj6a1U)=="table")and(
|
|
(Yaqj6a1U)[1]=="backslash")and(
|
|
(Yaqj6a1U)[2]==10))then table.remove(OQvQV,(#OQvQV-1))ya6fjL5s="base"elseif true then
|
|
local JRmILN12=Yaqj6a1U;ya6fjL5s="base"else ya6fjL5s=nil end end;if(Fq5 and(ya6fjL5s~="done"))then return
|
|
kDAL(OQvQV,xUshN(),ya6fjL5s)else return Fq5 end end
|
|
local function t0B6TI5G(lKkTr)return
|
|
({[7]="\\a",[8]="\\b",[9]="\\t",[10]="\\n",[11]="\\v",[12]="\\f",[13]="\\r"})[lKkTr:byte()]end
|
|
local function R()table.insert(vUI,{closer=34})local uAXL8_j_={34}if not
|
|
kDAL(uAXL8_j_,xUshN(),"base")then d()else end;table.remove(vUI)
|
|
local yFO69so=string.char(ytsM1v(uAXL8_j_))local gA7xA3=yFO69so:gsub("[\7-\13]",t0B6TI5G)
|
|
local SRnCezB=(
|
|
rawget(_G,"loadstring")or load)(("return "..gA7xA3))
|
|
if(nil~=SRnCezB)then local CDE8lC1=SRnCezB;return e30(CDE8lC1())elseif
|
|
(SRnCezB==nil)then
|
|
return u(("Invalid string: "..yFO69so))else return nil end end
|
|
local function sPnDE(pj)
|
|
table.insert(vUI,{prefix=o3c6Rl[pj],filename=mS,line=W,bytestart=Dvm,col=(ThzhHC8-1)})local hB=xUshN()
|
|
if
|
|
(oqTajz2H(hB)or(true==rnqUUVeM[hB]))then
|
|
if(pj~=35)then u("invalid whitespace after quoting prefix")else end;table.remove(vUI)e30(A0ui_xDj.sym("#"))else end;return NUH(hB)end
|
|
local function WWX(cNoUE6,Vd_v5M3)
|
|
if(Vd_v5M3 and rOWFI0fU(Vd_v5M3))then
|
|
table.insert(cNoUE6,Vd_v5M3)return WWX(cNoUE6,xUshN())else if Vd_v5M3 then NUH(Vd_v5M3)else end
|
|
return cNoUE6 end end
|
|
local function Ox(IK4Wj8_)
|
|
local RZG3T=(not IK4Wj8_:find("^_")and IK4Wj8_:gsub("_",""))
|
|
if IK4Wj8_:match("^%d")then
|
|
e30((tonumber(RZG3T)or
|
|
u(("could not read number \""..IK4Wj8_.."\""))))return true else local TCtx2=tonumber(RZG3T)
|
|
if(nil~=TCtx2)then local It7Dy=TCtx2;e30(It7Dy)return
|
|
true elseif true then local NJ8=TCtx2;return false else return nil end end end
|
|
local function G(N)local function n(S)
|
|
return(N:find(S)-A0ui_xDj.len(N)-1)end
|
|
if
|
|
(N:match("^~")and(N~="~="))then return u("invalid character: ~")elseif N:match("%.[0-9]")then return
|
|
u((
|
|
"can't start multisym segment with a digit: "..N),n("%.[0-9]"))elseif(
|
|
N:match("[%.:][%.:]")and(N~="..")and(N~="$..."))then return
|
|
u(("malformed multisym: "..N),n("[%.:][%.:]"))elseif((N~=":")and N:match(":$"))then
|
|
return u((
|
|
"malformed multisym: "..N),n(":$"))elseif N:match(":.+[%.:]")then return
|
|
u(("method must be last component of multisym: "..N),n(":.+[%.:]"))else return N end end
|
|
local function Hqp(IXch)local A1={bytestart=Dvm,filename=mS,line=W,col=(ThzhHC8-1)}
|
|
local k=string.char(ytsM1v(WWX({IXch},xUshN())))a(A1)
|
|
if(k=="true")then return e30(true)elseif(k=="false")then return e30(false)elseif
|
|
(k=="...")then return e30(A0ui_xDj.varg(A1))elseif k:match("^:.+$")then return
|
|
e30(k:sub(2))elseif not Ox(k)then return e30(A0ui_xDj.sym(G(k),A1))else return
|
|
nil end end
|
|
local function t(duCs0)
|
|
if not duCs0 then elseif(duCs0 ==59)then se(xUshN(),{";"})elseif(
|
|
type(rnqUUVeM[duCs0])=="number")then TDDCrC(duCs0)elseif rnqUUVeM[duCs0]then
|
|
Oc0(duCs0)elseif(duCs0 ==34)then R(duCs0)elseif o3c6Rl[duCs0]then sPnDE(duCs0)elseif(rOWFI0fU(duCs0)or(duCs0 ==
|
|
string.byte("~")))then
|
|
Hqp(duCs0)elseif
|
|
not A0ui_xDj["hook-opts"]("illegal-char",rSfPYb,duCs0,xUshN,NUH,e30)then
|
|
u(("invalid character: "..string.char(duCs0)))else end
|
|
if not duCs0 then return nil elseif KgjuC5D then return true,dLXo else return t(LU(xUshN()))end end;return t(LU(xUshN()))end;local function xthjd62S()vUI,W,Dvm,ThzhHC8,jBA={},1,0,0,nil;return nil end;return GqRU,
|
|
xthjd62S end
|
|
local function HXSQj(Bc,q7,Z)local Tq1rEK=(q7 or"unknown")
|
|
local LtX=(Z or A0ui_xDj.root.options or{})
|
|
assert(("string"==type(Tq1rEK)),"expected filename as second argument to parser")
|
|
if("string"==type(Bc))then
|
|
return YBYPED(oh(Bc,LtX),Tq1rEK,LtX)else return YBYPED(Bc,Tq1rEK,LtX)end end
|
|
return{granulate=vUM,parser=HXSQj,["string-stream"]=oh,["sym-char?"]=rOWFI0fU}end;local MrHR4XLm
|
|
package.preload["fennel.view"]=package.preload["fennel.view"]or
|
|
function(...)
|
|
local rvqZ={number=1,boolean=2,string=3,table=4,["function"]=5,userdata=6,thread=7}
|
|
local Q={["one-line?"]=false,["detect-cycles?"]=true,["empty-as-sequence?"]=false,["metamethod?"]=true,["prefer-colon?"]=false,["escape-newlines?"]=false,["utf8?"]=true,["line-length"]=80,depth=128,["max-sparse-gap"]=10}local DBscvI=pairs;local QYSYtlA7D=ipairs
|
|
local function wXFw(J9EX6KR)local US=getmetatable(J9EX6KR)
|
|
if
|
|
(
|
|
(_G.type(US)=="table")and(nil~= (US).__pairs))then local IqpOgU=(US).__pairs;return IqpOgU(J9EX6KR)elseif true then local mIp=US
|
|
return DBscvI(J9EX6KR)else return nil end end
|
|
local function qvEX8(ngnH4)local gGN=getmetatable(ngnH4)
|
|
if((_G.type(gGN)=="table")and(nil~=
|
|
(gGN).__ipairs))then
|
|
local Ir=(gGN).__ipairs;return Ir(ngnH4)elseif true then local R11=gGN;return QYSYtlA7D(ngnH4)else return nil end end
|
|
local function B(bK)local c=getmetatable(bK)
|
|
if((_G.type(c)=="table")and
|
|
(nil~= (c).__len))then local wb27heKC=(c).__len
|
|
return wb27heKC(bK)elseif true then local gP=c;return#bK else return nil end end
|
|
local function FITD(ONBn8)local zniyb=Q[ONBn8]
|
|
if(zniyb==nil)then return
|
|
error(("option '%s' doesn't have a default value, use the :after key to set it"):format(tostring(ONBn8)))elseif(nil~=zniyb)then
|
|
local j6aujQ=zniyb;return j6aujQ else return nil end end
|
|
local function sF(E80TCIY,e6np)local wjDpD=E80TCIY[e6np]local nX_qpC=wjDpD
|
|
if
|
|
(
|
|
(_G.type(nX_qpC)=="table")and(nil~= (nX_qpC).once))then local BS=(nX_qpC).once;return BS elseif true then local y_rvNds=nX_qpC;return wjDpD else return nil end end
|
|
local function YBNTETc8(q4uUj28)local Bcw={}
|
|
for F,VElp in wXFw(q4uUj28)do local OR,wYy=nil,nil
|
|
local function Y5c1Gsjp()local BtO_Z=VElp
|
|
if
|
|
(
|
|
(_G.type(BtO_Z)=="table")and(nil~= (BtO_Z).after))then local u4=(BtO_Z).after;return u4 else local function mZWfn44Y()return VElp.once end
|
|
if
|
|
((
|
|
_G.type(BtO_Z)=="table")and mZWfn44Y())then return FITD(F)elseif true then local mVua=BtO_Z;return VElp else return nil end end end;OR,wYy=F,Y5c1Gsjp()if((OR~=nil)and(wYy~=nil))then
|
|
Bcw[OR]=wYy else end end;return Bcw end
|
|
local function x(UL,DP)local _=UL;local YRJ_EUS5=_[1]local Wj=DP;local jq8Qkr9=Wj[1]local u2zyZTi=type(YRJ_EUS5)
|
|
local PVt=type(jq8Qkr9)
|
|
if((u2zyZTi==PVt)and
|
|
((u2zyZTi=="string")or(u2zyZTi=="number")))then return
|
|
(YRJ_EUS5 <jq8Qkr9)else local A=rvqZ[u2zyZTi]local IC2fit8f=rvqZ[PVt]
|
|
if(A and IC2fit8f)then return(
|
|
A<IC2fit8f)elseif A then return true elseif IC2fit8f then return false else return(u2zyZTi<PVt)end end end
|
|
local function fs2GTy(xK)local M=0
|
|
if(0 <B(xK))then local RAC5_q=0
|
|
for mDqsw,lGhscR0 in qvEX8(xK)do local N=lGhscR0;local I1w=N[1]if
|
|
(M< (I1w-RAC5_q))then M=(I1w-RAC5_q)else end;RAC5_q=I1w end else end;return M end
|
|
local function jbng(AmrR8)local MAtU9tFR={}local y9xoTS=0
|
|
for wuJFkK2,OCx in qvEX8(AmrR8)do local K95=OCx;local tYN=K95[1]y9xoTS=(y9xoTS+1)while(
|
|
y9xoTS<tYN)do table.insert(MAtU9tFR,y9xoTS)
|
|
y9xoTS=(y9xoTS+1)end end
|
|
for e84YWET,yegq in qvEX8(MAtU9tFR)do table.insert(AmrR8,yegq,{yegq})end;return nil end
|
|
local function l(bzjvciby,Rxul)local hI=false;local nb_7={}local _Qke_JB=table.insert
|
|
for dWbXq,eybr1_af in wXFw(bzjvciby)do
|
|
if(
|
|
(type(dWbXq)~="number")or(dWbXq<1))then hI=true else end;_Qke_JB(nb_7,{dWbXq,eybr1_af})end;table.sort(nb_7,x)
|
|
if not hI then if
|
|
(Rxul["max-sparse-gap"]<fs2GTy(nb_7))then hI=true else jbng(nb_7)end else end
|
|
if(B(nb_7)==0)then return nb_7,"empty"else
|
|
local function dpblsOQ1()if hI then return"table"else return"seq"end end;return nb_7,dpblsOQ1()end end
|
|
local function _KX1(IGR4x,kaHCl)
|
|
if(type(IGR4x)=="table")then
|
|
if not kaHCl[IGR4x]then kaHCl[IGR4x]=1
|
|
for hFj,L3IPm5 in
|
|
wXFw(IGR4x)do _KX1(hFj,kaHCl)_KX1(L3IPm5,kaHCl)end else
|
|
kaHCl[IGR4x]=((kaHCl[IGR4x]or 0)+1)end else end;return kaHCl end
|
|
local function P9G1_4TY(eFkbXT5,YwT)local ElF7xZnB=(YwT or{len=0})local sHuwdku=(ElF7xZnB.len+1)
|
|
if not
|
|
(ElF7xZnB)[eFkbXT5]then ElF7xZnB[eFkbXT5]=sHuwdku;ElF7xZnB.len=sHuwdku else end;return ElF7xZnB end
|
|
local function pD5w88(WxP,cCZLvI,Nk5)
|
|
if("table"==type(WxP))then cCZLvI[WxP]=true
|
|
local cUbIFh,S=next(WxP,Nk5)
|
|
if((nil~=cUbIFh)and(nil~=S))then local k3sjc1x0=cUbIFh;local lrrG=S;return
|
|
(
|
|
|
|
cCZLvI[k3sjc1x0]or pD5w88(k3sjc1x0,cCZLvI)or cCZLvI[lrrG]or pD5w88(lrrG,cCZLvI)or
|
|
pD5w88(WxP,cCZLvI,k3sjc1x0))else return nil end else return nil end end
|
|
local function uU8uhAPI(f2cg0k3,i5DJoU)return
|
|
(sF(i5DJoU,"detect-cycles?")and pD5w88(f2cg0k3,{})and
|
|
P9G1_4TY(f2cg0k3,i5DJoU.seen)and(1 <
|
|
(i5DJoU.appearances[f2cg0k3]or 0)))end
|
|
local function WYtvTGIw(MulH,q)local PLoy4usv
|
|
if q then PLoy4usv=(B(tostring(q))+2)else PLoy4usv=1 end;return(MulH+PLoy4usv)end;local VPVZ=nil
|
|
local function mCXoek(kEW02m,e6Huazc,Qdun,vzP,vb,Jt,AbX3)
|
|
local Cbn=("\n"..string.rep(" ",vzP))local E
|
|
local function wprCKD0()if("seq"==vb)then return"["else return"{"end end;E=((Jt or"")..wprCKD0())local R;if("seq"==vb)then R="]"else
|
|
R="}"end
|
|
local SE2mQB=(E..table.concat(kEW02m," ")..R)
|
|
if
|
|
(not sF(e6Huazc,"one-line?")and
|
|
(Qdun or(e6Huazc["line-length"]<
|
|
(vzP+B(SE2mQB)))or AbX3))then local function AyiyY()if AbX3 then return Cbn else return""end end
|
|
return(E..
|
|
table.concat(kEW02m,Cbn)..AyiyY()..R)else return SE2mQB end end
|
|
local function UmceFQB1(g)local MAuWbkoO=0;for cbA in string.gmatch(g,"[%z\1-\127\192-\247]")do
|
|
MAuWbkoO=(MAuWbkoO+1)end;return MAuWbkoO end
|
|
local function _Pr(e9)if("table"==type(e9))then local M6=e9[1]
|
|
return(("string"==type(M6))and(nil~=
|
|
M6:find("^;")))else return false end end
|
|
local function j_K0s(KBcj4Yv8,LJGx,ajLL,ZF)local lK0Ti0LJ=false;local rwzqpmi=ajLL.seen[KBcj4Yv8]
|
|
if
|
|
(ajLL.depth<=ajLL.level)then return"{...}"elseif(rwzqpmi and sF(ajLL,"detect-cycles?"))then return(
|
|
"@"..rwzqpmi.."{...}")else
|
|
local bMVOVayW=uU8uhAPI(KBcj4Yv8,ajLL)
|
|
local WLF=(bMVOVayW and ajLL.seen[KBcj4Yv8])local Ot=WYtvTGIw(ZF,WLF)local uOyc7;if sF(ajLL,"utf8?")then uOyc7=UmceFQB1 else
|
|
local function Ssqzca(B67TL11)return#B67TL11 end;uOyc7=Ssqzca end;local aXOURvRZ;if
|
|
bMVOVayW then aXOURvRZ=("@"..WLF)else aXOURvRZ=""end;local raCdp
|
|
do
|
|
local m5uAxF=YBNTETc8(ajLL)local F={}local C=#F
|
|
for zMlYy,HAOHW in qvEX8(LJGx)do local H=HAOHW;local nde=H[1]local Bq=H[2]local kWEEiV6g
|
|
do
|
|
local TDqhP=VPVZ(nde,m5uAxF,(Ot+1),true)
|
|
local C0lZsXfi=VPVZ(Bq,m5uAxF,(Ot+uOyc7(TDqhP)+1))
|
|
lK0Ti0LJ=(lK0Ti0LJ or TDqhP:find("\n")or C0lZsXfi:find("\n"))kWEEiV6g=(TDqhP.." "..C0lZsXfi)end
|
|
if(nil~=kWEEiV6g)then C=(C+1)do end(F)[C]=kWEEiV6g else end end;raCdp=F end
|
|
return mCXoek(raCdp,ajLL,lK0Ti0LJ,Ot,"table",aXOURvRZ,false)end end
|
|
local function qhWPu(m,DyW,WpvT5m98,emkAp)local _XRPNjK=false;local eII=WpvT5m98.seen[m]
|
|
if
|
|
(WpvT5m98.depth<=WpvT5m98.level)then return"[...]"elseif
|
|
(eII and sF(WpvT5m98,"detect-cycles?"))then return("@"..eII.."[...]")else
|
|
local Vsl0=uU8uhAPI(m,WpvT5m98)local fMppEj7=(Vsl0 and WpvT5m98.seen[m])
|
|
local V0yuyaY=WYtvTGIw(emkAp,fMppEj7)local L;if Vsl0 then L=("@"..fMppEj7)else L=""end
|
|
local EvZ6=_Pr(m[#m])local g
|
|
do local fdOPRM1=YBNTETc8(WpvT5m98)local FHT91={}local PpK8F=#FHT91
|
|
for J,pZY in qvEX8(DyW)do
|
|
local z2=pZY;local M=z2[1]local sXW=z2[2]local CznVN;do local y5q=VPVZ(sXW,fdOPRM1,V0yuyaY)
|
|
_XRPNjK=(_XRPNjK or
|
|
y5q:find("\n")or y5q:find("^;"))CznVN=y5q end
|
|
if
|
|
(nil~=CznVN)then PpK8F=(PpK8F+1)do end(FHT91)[PpK8F]=CznVN else end end;g=FHT91 end;return mCXoek(g,WpvT5m98,_XRPNjK,V0yuyaY,"seq",L,EvZ6)end end
|
|
local function Qa8Bfz(sqN,b,z,p6)
|
|
if(B(sqN)==0)then
|
|
if sF(b,"empty-as-sequence?")then return"[]"else return"{}"end else local DrFC;local HgV
|
|
do local Fldd={}local atAab=#Fldd;for h,X in qvEX8(sqN)do local uVc=X:gsub("^%s+","")
|
|
if
|
|
(nil~=uVc)then atAab=(atAab+1)do end(Fldd)[atAab]=uVc else end end;HgV=Fldd end;DrFC=table.concat(HgV," ")
|
|
if
|
|
(not sF(b,"one-line?")and
|
|
(p6 or
|
|
DrFC:find("\n")or(b["line-length"]< (z+B(DrFC)))))then return
|
|
table.concat(sqN,("\n"..string.rep(" ",z)))else return DrFC end end end
|
|
local function b0(HZM4DFRJ,UcP,b,w)
|
|
if(b.depth<=b.level)then
|
|
if sF(b,"empty-as-sequence?")then return"[...]"else return"{...}"end else local koFmC;local function I(li)return uU8uhAPI(li,b)end
|
|
b["visible-cycle?"]=I;koFmC=nil;local Dcu,Ndm1xBYc=nil,nil;do local phqeo=YBNTETc8(b)
|
|
Dcu,Ndm1xBYc=UcP(HZM4DFRJ,VPVZ,phqeo,w)end;b["visible-cycle?"]=nil
|
|
local GH0tzvu=type(Dcu)
|
|
if(GH0tzvu=="string")then return Dcu elseif(GH0tzvu=="table")then return
|
|
Qa8Bfz(Dcu,b,w,Ndm1xBYc)elseif true then local U=GH0tzvu;return
|
|
error("__fennelview metamethod must return a table of lines")else return nil end end end
|
|
local function b81Fw(SFFm,TE,Th5BpD4B)TE.level=(TE.level+1)local gaWBjVL9
|
|
do local v
|
|
if sF(TE,"metamethod?")then local TmJv1=SFFm
|
|
if
|
|
(nil~=TmJv1)then local ZRapQFix=getmetatable(TmJv1)if(nil~=ZRapQFix)then
|
|
v=(ZRapQFix).__fennelview else v=ZRapQFix end else v=TmJv1 end else v=nil end
|
|
if(nil~=v)then local bHQ4G=v;gaWBjVL9=b0(SFFm,bHQ4G,TE,Th5BpD4B)elseif true then local dR96ZM=v
|
|
local mA3DdzFd,CE0prxRC=l(SFFm,TE)
|
|
if(true and(CE0prxRC=="empty"))then local Bff=mA3DdzFd;if
|
|
sF(TE,"empty-as-sequence?")then gaWBjVL9="[]"else gaWBjVL9="{}"end elseif(
|
|
(nil~=mA3DdzFd)and(CE0prxRC=="table"))then
|
|
local wE7=mA3DdzFd;gaWBjVL9=j_K0s(SFFm,wE7,TE,Th5BpD4B)elseif((nil~=mA3DdzFd)and
|
|
(CE0prxRC=="seq"))then local H2rM5=mA3DdzFd
|
|
gaWBjVL9=qhWPu(SFFm,H2rM5,TE,Th5BpD4B)else gaWBjVL9=nil end else gaWBjVL9=nil end end;TE.level=(TE.level-1)return gaWBjVL9 end
|
|
local function umz(TKmgwuo)local q=string.gsub(tostring(TKmgwuo),",",".")return q end
|
|
local function JXCg(n2R)return n2R:find("^[-%w?^_!$%&*+./@|<=>]+$")end
|
|
local K9fi_VCl={{["min-byte"]=0,["max-byte"]=127,["min-code"]=0,["max-code"]=127,len=1},{["min-byte"]=192,["max-byte"]=223,["min-code"]=128,["max-code"]=2047,len=2},{["min-byte"]=224,["max-byte"]=239,["min-code"]=2048,["max-code"]=65535,len=3},{["min-byte"]=240,["max-byte"]=247,["min-code"]=65536,["max-code"]=1114111,len=4}}
|
|
local function xknmF(nM1Z9cl)
|
|
local function w(UcyAum,dYsjmqdo)local k=K9fi_VCl;local Ur_nfNU=string.byte(UcyAum,dYsjmqdo)local YF8Nredr
|
|
do
|
|
local tyx_Qk=nil
|
|
for urZP,ayXNm in qvEX8(k)do if tyx_Qk then break end
|
|
tyx_Qk=(Ur_nfNU and
|
|
(function(Iq9D_7Yo,OMesxhmz,Q9BrppG)return(Iq9D_7Yo<=OMesxhmz)and
|
|
(OMesxhmz<=Q9BrppG)end)(ayXNm["min-byte"],Ur_nfNU,ayXNm["max-byte"])and
|
|
ayXNm)end;YF8Nredr=tyx_Qk end;local wFF9q_B
|
|
local function KLNU()local D9E4D;if YF8Nredr then
|
|
D9E4D=(Ur_nfNU-YF8Nredr["min-byte"])else D9E4D=nil end
|
|
for hhiP24bV=(dYsjmqdo+1),(
|
|
dYsjmqdo+YF8Nredr.len+-1)do
|
|
local O34P1h=string.byte(UcyAum,hhiP24bV)
|
|
D9E4D=(O34P1h and D9E4D and
|
|
(function(M,oW2YQpc,EX1c04A)
|
|
return(M<=oW2YQpc)and(oW2YQpc<=EX1c04A)end)(128,O34P1h,191)and((D9E4D*64)+
|
|
(O34P1h-128)))end;return D9E4D end;wFF9q_B=(YF8Nredr and KLNU())
|
|
if
|
|
(wFF9q_B and
|
|
(function(svWLk,H6V,vZece1k)return(svWLk<=H6V)and
|
|
(H6V<=vZece1k)end)(YF8Nredr["min-code"],wFF9q_B,YF8Nredr["max-code"])and not
|
|
(function(ZUrs,cJ9n_wGv,oNrtf_)return
|
|
(ZUrs<=cJ9n_wGv)and(cJ9n_wGv<=oNrtf_)end)(55296,wFF9q_B,57343))then return YF8Nredr.len else return nil end end;local UTW=1;local hYYhQ={}
|
|
while(UTW<=#nM1Z9cl)do
|
|
local HtgpP=(
|
|
string.find(nM1Z9cl,"[\128-\255]",UTW)or(#nM1Z9cl+1))local lyBbtwn=w(nM1Z9cl,HtgpP)
|
|
table.insert(hYYhQ,string.sub(nM1Z9cl,UTW,(
|
|
HtgpP+ (lyBbtwn or 0)+-1)))if(not lyBbtwn and(HtgpP<=#nM1Z9cl))then
|
|
table.insert(hYYhQ,string.format("\\%03d",string.byte(nM1Z9cl,HtgpP)))else end;if lyBbtwn then
|
|
UTW=(HtgpP+lyBbtwn)else UTW=(HtgpP+1)end end;return table.concat(hYYhQ)end
|
|
local function Z69(biFy,Kp,o4A)local M9=B(biFy)
|
|
local rzBY2CSb=((M9 <2)or
|
|
(sF(Kp,"escape-newlines?")and(M9 <
|
|
(Kp["line-length"]-o4A))))local eJbv;local BUVM8;if rzBY2CSb then BUVM8="\\n"else BUVM8="\n"end;local function k(Kl1YC,b8)return
|
|
("\\%03d"):format(b8:byte())end
|
|
eJbv=setmetatable({["\7"]="\\a",["\8"]="\\b",["\12"]="\\f",["\11"]="\\v",["\13"]="\\r",["\9"]="\\t",["\\"]="\\\\",["\""]="\\\"",["\n"]=BUVM8},{__index=k})
|
|
local x5=("\""..biFy:gsub("[%c\\\"]",eJbv).."\"")if sF(Kp,"utf8?")then return xknmF(x5)else return x5 end end
|
|
local function i(bGdXdZ,iIoI)local F
|
|
do local UFS7={}
|
|
for rsqKt,e in wXFw(Q)do local qIYmlZUV,ae8WUke=rsqKt,e;if
|
|
((qIYmlZUV~=nil)and(ae8WUke~=nil))then UFS7[qIYmlZUV]=ae8WUke else end end;F=UFS7 end;local qRV={level=0,appearances=_KX1(bGdXdZ,{}),seen={len=0}}for EU8,B6 in wXFw((
|
|
iIoI or{}))do F[EU8]=B6 end;for KJgE8hd,ufBK in wXFw(qRV)do
|
|
F[KJgE8hd]=ufBK end;return F end
|
|
local function IDjuB(cZ,maaag,Bi35M,ZjzhK)local tihCL=(Bi35M or 0)local r=(maaag or i(cZ))local ZDeC;if r.preprocess then
|
|
ZDeC=r.preprocess(cZ,r)else ZDeC=cZ end;local HZlrFcs=type(ZDeC)
|
|
local function O()
|
|
local QD=getmetatable(ZDeC)if(nil~=QD)then return(QD).__fennelview else return QD end end
|
|
if((HZlrFcs=="table")or
|
|
((HZlrFcs=="userdata")and O()))then
|
|
return b81Fw(ZDeC,r,tihCL)elseif(HZlrFcs=="number")then return umz(ZDeC)else
|
|
local function hcbBcU()
|
|
if(ZjzhK~=nil)then return ZjzhK elseif("function"==
|
|
type(r["prefer-colon?"]))then
|
|
return r["prefer-colon?"](ZDeC)else return sF(r,"prefer-colon?")end end
|
|
if
|
|
((HZlrFcs=="string")and JXCg(ZDeC)and hcbBcU())then return(":"..ZDeC)elseif(HZlrFcs=="string")then return Z69(ZDeC,r,tihCL)elseif
|
|
((
|
|
HZlrFcs=="boolean")or(HZlrFcs=="nil"))then return tostring(ZDeC)else return
|
|
("#<"..tostring(ZDeC)..">")end end end;VPVZ=IDjuB
|
|
local function xoF(OkdSp2,zO7D8g2)return VPVZ(OkdSp2,i(OkdSp2,zO7D8g2),0)end;return xoF end
|
|
package.preload["fennel.utils"]=package.preload["fennel.utils"]or
|
|
function(...)
|
|
local ywRB55Y3=require("fennel.view")local uUc5YN="1.3.0"
|
|
local function tBlx5J()return
|
|
(
|
|
(nil~=_G.jit)and(type(_G.jit)=="table")and(nil~=_G.jit.on)and
|
|
(nil~=_G.jit.off)and
|
|
(type(_G.jit.version_num)=="number"))end
|
|
local function BJLlq()local ZfJ
|
|
if(_G.jit.os=="OSX")then ZfJ="macOS"else ZfJ=_G.jit.os end;return
|
|
(_G.jit.version.." "..ZfJ.."/".._G.jit.arch)end
|
|
local function DsnW()return
|
|
(
|
|
|
|
(nil~=_G.fengari)and(type(_G.fengari)=="table")and(nil~=_G.fengari.VERSION)and
|
|
(type(_G.fengari.VERSION_NUM)=="number"))end;local function f0qgvqD()return
|
|
(_G.fengari.RELEASE.." (".._VERSION..")")end;local function r()
|
|
if tBlx5J()then
|
|
return BJLlq()elseif DsnW()then return f0qgvqD()else return("PUC ".._VERSION)end end
|
|
local function IYCyS()return("Fennel "..uUc5YN..
|
|
" on "..r())end;local function rgNe(kZ)
|
|
if(_G.io and _G.io.stderr)then return
|
|
(_G.io.stderr):write(("--WARNING: %s\n"):format(tostring(kZ)))else return nil end end
|
|
local wMf06P3R
|
|
do local G,UV=pcall(require,"utf8")
|
|
if
|
|
((G==true)and(nil~=UV))then local Vmk7fAg=UV;wMf06P3R=Vmk7fAg.len elseif true then local kDtxd5=G;wMf06P3R=string.len else wMf06P3R=nil end end
|
|
local function dzghhciK(CR5bl6Nk,BjIQON,MLLs29h)
|
|
for Umpt,NVyj in ipairs(getmetatable(CR5bl6Nk).keys)do if(CR5bl6Nk[NVyj]and not
|
|
MLLs29h[NVyj])then MLLs29h[NVyj]=true
|
|
table.insert(BjIQON,NVyj)else end end;for Nt3 in pairs(CR5bl6Nk)do
|
|
if not MLLs29h[Nt3]then table.insert(BjIQON,Nt3)else end end;return BjIQON end
|
|
local function PwmycU9j(UPRQV)local OuKZ9r5_b;local AE;do local ZXC=getmetatable(UPRQV)
|
|
if(nil~=ZXC)then ZXC=(ZXC).keys else end;AE=ZXC end
|
|
if AE then
|
|
OuKZ9r5_b=dzghhciK(UPRQV,{},{})else local mPFtR
|
|
do local cwH={}local L8qe=#cwH
|
|
for w0n in pairs(UPRQV)do local Fulc=w0n;if(nil~=Fulc)then L8qe=(L8qe+1)
|
|
do end(cwH)[L8qe]=Fulc else end end;mPFtR=cwH end;local function NK3P(ZEnxqQUU,vKS)
|
|
return(tostring(ZEnxqQUU)<tostring(vKS))end;table.sort(mPFtR,NK3P)
|
|
OuKZ9r5_b=mPFtR end;local NrE
|
|
do local i={}
|
|
for dLf2jPq,i8Md in ipairs(OuKZ9r5_b)do
|
|
local qEYllmGl,kidu9L1=i8Md,OuKZ9r5_b[(dLf2jPq+1)]if((qEYllmGl~=nil)and(kidu9L1 ~=nil))then
|
|
i[qEYllmGl]=kidu9L1 else end end;NrE=i end;local function gAxTFh(h,YTj)local f;if(YTj==nil)then f=OuKZ9r5_b[1]else f=NrE[YTj]end
|
|
return f,h[f]end;return gAxTFh,UPRQV,nil end
|
|
local function RALLLsy(szuBLiJ,lldG,YQTxGz)
|
|
assert(("table"==type(szuBLiJ)),"get-in expects path to be a table")
|
|
if(0 ==#lldG)then return YQTxGz else local niC
|
|
do local noG=szuBLiJ;for njXSViBs,ppmAJ in ipairs(lldG)do
|
|
if(nil==noG)then break end;local h1=type(noG)
|
|
if(h1 =="table")then noG=noG[ppmAJ]else noG=nil end end
|
|
niC=noG end
|
|
if(nil~=niC)then local RwJd=niC;return RwJd elseif true then local geS0=niC;return YQTxGz else return nil end end end
|
|
local function eUVcEqV3(yYbGcrR,qOa_Ko,aeT)local GVDHI=(aeT or{})local F5qHLf
|
|
if(type(qOa_Ko)=="function")then
|
|
F5qHLf=qOa_Ko else local function O_F(_R7vx)return(_R7vx)[qOa_Ko]end;F5qHLf=O_F end
|
|
for UUsIt,PeXzzb in ipairs(yYbGcrR)do local PS=F5qHLf(PeXzzb)if(nil~=PS)then local HjTf4=PS
|
|
table.insert(GVDHI,HjTf4)else end end;return GVDHI end
|
|
local function J9A3WWhJ(kq1wF,oJ,jbu_UOWn)local Un3W=(jbu_UOWn or{})local gb
|
|
if(type(oJ)=="function")then gb=oJ else local function s(CLqUm)return
|
|
(CLqUm)[oJ]end;gb=s end
|
|
for C,AAY in PwmycU9j(kq1wF)do local H,s=gb(C,AAY)if((nil~=H)and(nil~=s))then
|
|
local Zk6TOK=H;local L51e=s;Un3W[Zk6TOK]=L51e elseif(nil~=H)then local rK067tHi=H
|
|
table.insert(Un3W,rK067tHi)else end end;return Un3W end
|
|
local function O(KKXynV,QfEQ)local j=(QfEQ or{})for b31H,q2e in pairs((KKXynV or{}))do local LmtHYt,YL=b31H,q2e
|
|
if(
|
|
(LmtHYt~=nil)and(YL~=nil))then j[LmtHYt]=YL else end end;return j end
|
|
local function wt4K(KPpwX,dhMu65,xIEL0)local c=dhMu65[(xIEL0 or 1)]
|
|
if(c==KPpwX)then return true elseif(c==nil)then
|
|
return nil elseif true then local YNJ=c
|
|
return wt4K(KPpwX,dhMu65,((xIEL0 or 1)+1))else return nil end end
|
|
local function Zz(PRI)local MK08=0
|
|
for TWuTU_S in pairs(PRI)do if("number"==type(TWuTU_S))then
|
|
MK08=math.max(MK08,TWuTU_S)else MK08=MK08 end end;return MK08 end;local function t(i_,gByFT)local vj=true
|
|
for S,Oj in ipairs(gByFT)do if not vj then break end;vj=i_(Oj)end;return vj end
|
|
local function qveu(TAK01)
|
|
assert((
|
|
type(TAK01)=="table"),"allpairs expects a table")local BhME7zKa=TAK01;local hW={}
|
|
local function d(fDTdRtv,wOUo)local Z,REZciXm=next(BhME7zKa,wOUo)
|
|
if hW[Z]then return d(nil,Z)elseif Z then
|
|
hW[Z]=true;return Z,REZciXm else local vet06dX=getmetatable(BhME7zKa)
|
|
if(
|
|
(_G.type(vet06dX)=="table")and true)then local LSJ=(vet06dX).__index
|
|
if("table"==
|
|
type(LSJ))then BhME7zKa=LSJ;return d(BhME7zKa)else return nil end else return nil end end end;return d end;local function r33Uk(TX7wgl2)return TX7wgl2[1]end;local K8pEP=nil
|
|
local function ZzS4pmQf(nLhs,BePns,a,YAaqAxth)local Kv1={}local GBq2DiO
|
|
if BePns then local function tZwJ5kGy(n)return
|
|
BePns(n,a,YAaqAxth)end;GBq2DiO=tZwJ5kGy else GBq2DiO=ywRB55Y3 end;local YuK=Zz(nLhs)
|
|
for nKd=1,YuK do Kv1[nKd]=(
|
|
((nLhs[nKd]==nil)and K8pEP)or nLhs[nKd])end
|
|
return("("..
|
|
table.concat(eUVcEqV3(Kv1,GBq2DiO)," ",1,YuK)..")")end;local function HlqK3O(_ix1)return _ix1,true end
|
|
local function ak(dTQygQp,G0jFU0N)return
|
|
(
|
|
(r33Uk(dTQygQp)==r33Uk(G0jFU0N))and
|
|
(getmetatable(dTQygQp)==getmetatable(G0jFU0N)))end
|
|
local function nJAHY(_pcAkYZw,k)return(_pcAkYZw[1]<tostring(k))end
|
|
local gdwDZ7K8={__fennelview=r33Uk,__tostring=r33Uk,__eq=ak,__lt=nJAHY,"SYMBOL"}local n8;local function Abj_oS(h7dX)return tostring(r33Uk(h7dX))end
|
|
n8={__tostring=Abj_oS,"EXPR"}local y={__fennelview=ZzS4pmQf,__tostring=ZzS4pmQf,"LIST"}
|
|
local N={__fennelview=HlqK3O,__tostring=r33Uk,__eq=ak,__lt=nJAHY,"COMMENT"}local It78KVqm={"SEQUENCE"}
|
|
local eVtr7R={__fennelview=r33Uk,__tostring=r33Uk,"VARARG"}local PK;local function xwvh9TWh()return nil end
|
|
PK=((os and os.getenv)or xwvh9TWh)
|
|
local function nao(m)local YQEy=(PK("FENNEL_DEBUG")or"")return((YQEy=="all")or
|
|
YQEy:find(m))end;local function hshvQ4(...)return setmetatable({...},y)end
|
|
local function zkEfU2aq(b,BpzDEg)local BpCsj
|
|
do
|
|
local A={b}
|
|
for WmxYa4Y,FzCqUI in pairs((BpzDEg or{}))do local jc,BYw=nil,nil;if
|
|
(type(WmxYa4Y)=="string")then jc,BYw=WmxYa4Y,FzCqUI else jc,BYw=nil end;if(
|
|
(jc~=nil)and(BYw~=nil))then A[jc]=BYw else end end;BpCsj=A end;return setmetatable(BpCsj,gdwDZ7K8)end;K8pEP=zkEfU2aq("nil")
|
|
local function g(...)
|
|
local function Wc819r(KuR,ExwYzLq,h8DoQ,IKSbGTVl)local OmFTJ_x5
|
|
do local NF=h8DoQ
|
|
NF["empty-as-sequence?"]={once=true,after=h8DoQ["empty-as-sequence?"]}
|
|
NF["metamethod?"]={once=false,after=h8DoQ["metamethod?"]}OmFTJ_x5=NF end;return ExwYzLq(KuR,OmFTJ_x5,IKSbGTVl)end
|
|
return setmetatable({...},{sequence=It78KVqm,__fennelview=Wc819r})end
|
|
local function xPkHq(os0TDkQC,uqBQ9dTh)return setmetatable({type=uqBQ9dTh,os0TDkQC},n8)end
|
|
local function RzY6je9(u,YnP)local Eg=(YnP or{})local KgxF=Eg["filename"]local j_cIt=Eg["line"]return
|
|
setmetatable({filename=KgxF,line=j_cIt,u},N)end
|
|
local function DgN(i)local o
|
|
do local YqXHrgg={"..."}
|
|
for RqhnbJhs,eFI in pairs((i or{}))do local iL27y2w,o9=nil,nil;if
|
|
(type(RqhnbJhs)=="string")then iL27y2w,o9=RqhnbJhs,eFI else iL27y2w,o9=nil end;if((
|
|
iL27y2w~=nil)and(o9 ~=nil))then
|
|
YqXHrgg[iL27y2w]=o9 else end end;o=YqXHrgg end;return setmetatable(o,eVtr7R)end
|
|
local function az(_Prk6Jm_)return
|
|
((type(_Prk6Jm_)=="table")and
|
|
(getmetatable(_Prk6Jm_)==n8)and _Prk6Jm_)end
|
|
local function FMQ(HfLnH2m)return
|
|
((type(HfLnH2m)=="table")and
|
|
(getmetatable(HfLnH2m)==eVtr7R)and HfLnH2m)end
|
|
local function xHs(NYPzbv6hL)return
|
|
((type(NYPzbv6hL)=="table")and
|
|
(getmetatable(NYPzbv6hL)==y)and NYPzbv6hL)end;local function epujP2(zp)
|
|
return(
|
|
(type(zp)=="table")and(getmetatable(zp)==gdwDZ7K8)and zp)end
|
|
local function RU(ovq)
|
|
local Btx=(
|
|
(type(ovq)=="table")and getmetatable(ovq))return
|
|
(Btx and(Btx.sequence==It78KVqm)and ovq)end;local function eeiQ(mtmN)
|
|
return(
|
|
(type(mtmN)=="table")and(getmetatable(mtmN)==N)and mtmN)end
|
|
local function Knl(U6)return
|
|
(
|
|
|
|
(type(U6)=="table")and not
|
|
FMQ(U6)and(getmetatable(U6)~=y)and(getmetatable(U6)~=gdwDZ7K8)and not eeiQ(U6)and U6)end
|
|
local function JaOvVR5(BTixF)return(type(BTixF)=="string")end
|
|
local function q1f0Oc2T(JeGvp)
|
|
if epujP2(JeGvp)then return q1f0Oc2T(tostring(JeGvp))elseif
|
|
(type(JeGvp)~="string")then return false else
|
|
local function cTPe07ea()local FtNgLV3={}
|
|
for xb3cZqz in JeGvp:gmatch("[^%.%:]+[%.%:]?")do
|
|
local ALLM=xb3cZqz:sub((-1))
|
|
if(ALLM==":")then FtNgLV3["multi-sym-method-call"]=true else end;if((ALLM==":")or(ALLM=="."))then FtNgLV3[(#FtNgLV3+1)]=xb3cZqz:sub(1,(
|
|
-2))else
|
|
FtNgLV3[(#FtNgLV3+1)]=xb3cZqz end end;return((0 <#FtNgLV3)and FtNgLV3)end
|
|
return
|
|
(
|
|
|
|
(JeGvp:match("%.")or JeGvp:match(":"))and not
|
|
JeGvp:match("%.%.")and(JeGvp:byte()~=
|
|
string.byte("."))and(JeGvp:byte((-1))~=string.byte("."))and cTPe07ea())end end;local function ud5HPbcv(zzlLc)return zzlLc.quoted end
|
|
local function wk1(v05sOls6)return
|
|
(
|
|
(type(v05sOls6)=="string")or(type(v05sOls6)=="integer")or(
|
|
type(v05sOls6)=="number")or(
|
|
epujP2(v05sOls6)and not q1f0Oc2T(v05sOls6)))end
|
|
local function VQJ(KxAor2)
|
|
if(Knl(KxAor2)or RU(KxAor2))then return
|
|
(getmetatable(KxAor2)or{})elseif("table"==type(KxAor2))then return KxAor2 else return{}end end
|
|
local function AIijmsE(xnwyE,QWX8_lf,M3LR3tn)
|
|
local function Erbj(d4LZ,dLmX,tmAdfrX3,rWwH)
|
|
if QWX8_lf(tmAdfrX3,rWwH,dLmX)then
|
|
for WZV9gJ,MWkVn1 in d4LZ(rWwH)do Erbj(d4LZ,rWwH,WZV9gJ,MWkVn1)end;return nil else return nil end end;Erbj((M3LR3tn or pairs),nil,nil,xnwyE)
|
|
return xnwyE end
|
|
local qWK_3JzI={"and","break","do","else","elseif","end","false","for","function","if","in","local","nil","not","or","repeat","return","then","true","until","while","goto"}
|
|
for U3tvJtO,tAn_s in ipairs(qWK_3JzI)do qWK_3JzI[tAn_s]=U3tvJtO end;local function nb43hxtA(Rl)return
|
|
(Rl:match("^[%a_][%w_]*$")and not qWK_3JzI[Rl])end
|
|
local Up={"allowedGlobals","indent","correlate","useMetadata","env","compiler-env","compilerEnv"}
|
|
local function kq6F_y(zKTBQ,Bwjp3Zb)for JKwYNF,vZ in ipairs(Up)do Bwjp3Zb[vZ]=zKTBQ[vZ]end;return Bwjp3Zb end;local uB;local function EbTdnc6_()end
|
|
uB={chunk=nil,scope=nil,options=nil,reset=EbTdnc6_}
|
|
uB["set-reset"]=function(aGXjGx)local TpP=aGXjGx;local Szm5J41=TpP["chunk"]local Kx0f6LwY=TpP["scope"]
|
|
local U=TpP["options"]local KQoCWF6y=TpP["reset"]
|
|
uB.reset=function()
|
|
uB.chunk,uB.scope,uB.options,uB.reset=Szm5J41,Kx0f6LwY,U,KQoCWF6y;return nil end;return uB.reset end;local KKl={}
|
|
local function J_(EDZ)local rQSUS=EDZ;local U9fgafbB=rQSUS["name"]local SVDqS=rQSUS["versions"]
|
|
local WVWl=rQSUS
|
|
if
|
|
(
|
|
not wt4K(uUc5YN:gsub("-dev",""),(SVDqS or{}))and not KKl[WVWl])then KKl[WVWl]=true;return
|
|
rgNe(string.format("plugin %s does not support Fennel version %s",(U9fgafbB or"unknown"),uUc5YN))else return nil end end
|
|
local function sLgV(qsG8aH2,J3DYNYlZ,...)local Dv26;local function w1V4n(...)local Bc7kn4=J3DYNYlZ
|
|
if(nil~=Bc7kn4)then Bc7kn4=(Bc7kn4).plugins else end;return Bc7kn4 end;local function OaCu_(...)
|
|
local be3Cfi=uB.options;if(nil~=be3Cfi)then be3Cfi=(be3Cfi).plugins else end
|
|
return be3Cfi end;Dv26=(w1V4n(...)or
|
|
OaCu_(...))
|
|
if Dv26 then local HJY=nil
|
|
for o,FDkG25 in ipairs(Dv26)do if HJY then break end
|
|
J_(FDkG25)local kDfLP=FDkG25[qsG8aH2]if(nil~=kDfLP)then local DP2oc6Nu=kDfLP
|
|
HJY=DP2oc6Nu(...)else HJY=nil end end;return HJY else return nil end end;local function W(b0N,...)return sLgV(b0N,uB.options,...)end
|
|
return
|
|
{warn=rgNe,allpairs=qveu,stablepairs=PwmycU9j,copy=O,["get-in"]=RALLLsy,kvmap=J9A3WWhJ,map=eUVcEqV3,["walk-tree"]=AIijmsE,["member?"]=wt4K,maxn=Zz,["every?"]=t,list=hshvQ4,sequence=g,sym=zkEfU2aq,varg=DgN,expr=xPkHq,comment=RzY6je9,["comment?"]=eeiQ,["expr?"]=az,["list?"]=xHs,["multi-sym?"]=q1f0Oc2T,["sequence?"]=RU,["sym?"]=epujP2,["table?"]=Knl,["varg?"]=FMQ,["quoted?"]=ud5HPbcv,["string?"]=JaOvVR5,["idempotent-expr?"]=wk1,["valid-lua-identifier?"]=nb43hxtA,["lua-keywords"]=qWK_3JzI,hook=W,["hook-opts"]=sLgV,["propagate-options"]=kq6F_y,root=uB,["debug-on?"]=nao,["ast-source"]=VQJ,version=uUc5YN,["runtime-version"]=IYCyS,len=wMf06P3R,path=table.concat({"./?.fnl","./?/init.fnl",PK("FENNEL_PATH")},";"),["macro-path"]=table.concat({"./?.fnl","./?/init-macros.fnl","./?/init.fnl",PK("FENNEL_MACRO_PATH")},";")}end;MrHR4XLm=require("fennel.utils")
|
|
local Y=require("fennel.parser")local Mm=require("fennel.compiler")
|
|
local CD=require("fennel.specials")local vwkjf=require("fennel.repl")
|
|
local wcsc=require("fennel.view")
|
|
local function ASw(V,QBrhtH)
|
|
if(V=="_COMPILER")then
|
|
local p6an=CD["make-compiler-env"](nil,Mm.scopes.compiler,{},QBrhtH)if(QBrhtH.allowedGlobals==nil)then
|
|
QBrhtH.allowedGlobals=CD["current-global-names"](p6an)else end
|
|
return CD["wrap-env"](p6an)else return(V and CD["wrap-env"](V))end end
|
|
local function Ku(dh6fW,lEsr)local NalT=MrHR4XLm.copy(dh6fW)if
|
|
(NalT.allowedGlobals==nil)then
|
|
NalT.allowedGlobals=CD["current-global-names"](NalT.env)else end
|
|
if(not NalT.filename and
|
|
not NalT.source)then NalT.source=lEsr else end;if(NalT.env=="_COMPILER")then
|
|
NalT.scope=Mm["make-scope"](Mm.scopes.compiler)else end;return NalT end
|
|
local function K(tIrMMuh1,X,...)local P=Ku(X,tIrMMuh1)local SDpQWorN=ASw(P.env,P)
|
|
local AD=Mm["compile-string"](tIrMMuh1,P)local KYeUsAQT;local function tTPXe(...)
|
|
if P.filename then return("@"..P.filename)else return tIrMMuh1 end end
|
|
KYeUsAQT=CD["load-code"](AD,SDpQWorN,tTPXe(...))P.filename=nil;return KYeUsAQT(...)end
|
|
local function Fb(KjWEUr,d,...)local j4PSgY=MrHR4XLm.copy(d)
|
|
local NqMzi=assert(io.open(KjWEUr,"rb"))
|
|
local jw1H_k=assert(NqMzi:read("*all"),("Could not read "..KjWEUr))NqMzi:close()j4PSgY.filename=KjWEUr
|
|
return K(jw1H_k,j4PSgY,...)end
|
|
local function XSbn()
|
|
local liIoYEJd={"when","with-open","collect","icollect","fcollect","lambda","\206\187","macro","match","match-try","case","case-try","accumulate","faccumulate","doto"}
|
|
local h8KDei6f={"collect","icollect","fcollect","each","for","let","with-open","accumulate","faccumulate"}
|
|
local JX={"fn","lambda","\206\187","var","local","macro","macros","global"}local BrSRAw={}
|
|
for VfLV6h1,E5 in pairs(Mm.scopes.global.specials)do
|
|
local rsIIW=(Mm.metadata[E5]or{})do end
|
|
(BrSRAw)[VfLV6h1]={["special?"]=true,["body-form?"]=rsIIW["fnl/body-form?"],["binding-form?"]=MrHR4XLm["member?"](VfLV6h1,h8KDei6f),["define?"]=MrHR4XLm["member?"](VfLV6h1,JX)}end
|
|
for iAeh,WfS in pairs(Mm.scopes.global.macros)do
|
|
BrSRAw[iAeh]={["macro?"]=true,["body-form?"]=MrHR4XLm["member?"](iAeh,liIoYEJd),["binding-form?"]=MrHR4XLm["member?"](iAeh,h8KDei6f),["define?"]=MrHR4XLm["member?"](iAeh,JX)}end
|
|
for af8j5i,J1ny in pairs(_G)do local jgdc=type(J1ny)
|
|
if(jgdc=="function")then
|
|
BrSRAw[af8j5i]={["global?"]=true,["function?"]=true}elseif(jgdc=="table")then
|
|
for XMIKS,nh0e in pairs(J1ny)do if(("function"==type(nh0e))and
|
|
(af8j5i~="_G"))then
|
|
BrSRAw[(af8j5i.."."..XMIKS)]={["function?"]=true,["global?"]=true}else end end;BrSRAw[af8j5i]={["global?"]=true}else end end;return BrSRAw end
|
|
local FkyzO={list=MrHR4XLm.list,["list?"]=MrHR4XLm["list?"],sym=MrHR4XLm.sym,["sym?"]=MrHR4XLm["sym?"],["multi-sym?"]=MrHR4XLm["multi-sym?"],sequence=MrHR4XLm.sequence,["sequence?"]=MrHR4XLm["sequence?"],["table?"]=MrHR4XLm["table?"],comment=MrHR4XLm.comment,["comment?"]=MrHR4XLm["comment?"],varg=MrHR4XLm.varg,["varg?"]=MrHR4XLm["varg?"],["sym-char?"]=Y["sym-char?"],parser=Y.parser,compile=Mm.compile,["compile-string"]=Mm["compile-string"],["compile-stream"]=Mm["compile-stream"],eval=K,repl=vwkjf,view=wcsc,dofile=Fb,["load-code"]=CD["load-code"],doc=CD.doc,metadata=Mm.metadata,traceback=Mm.traceback,version=MrHR4XLm.version,["runtime-version"]=MrHR4XLm["runtime-version"],["ast-source"]=MrHR4XLm["ast-source"],path=MrHR4XLm.path,["macro-path"]=MrHR4XLm["macro-path"],["macro-loaded"]=CD["macro-loaded"],["macro-searchers"]=CD["macro-searchers"],["search-module"]=CD["search-module"],["make-searcher"]=CD["make-searcher"],searcher=CD["make-searcher"](),syntax=XSbn,gensym=Mm.gensym,scope=Mm["make-scope"],mangle=Mm["global-mangling"],unmangle=Mm["global-unmangling"],compile1=Mm.compile1,["string-stream"]=Y["string-stream"],granulate=Y.granulate,loadCode=CD["load-code"],make_searcher=CD["make-searcher"],makeSearcher=CD["make-searcher"],searchModule=CD["search-module"],macroPath=MrHR4XLm["macro-path"],macroSearchers=CD["macro-searchers"],macroLoaded=CD["macro-loaded"],compileStream=Mm["compile-stream"],compileString=Mm["compile-string"],stringStream=Y["string-stream"],runtimeVersion=MrHR4XLm["runtime-version"]}
|
|
FkyzO.install=function(jgjGmjJ4)
|
|
table.insert((package.searchers or package.loaders),CD["make-searcher"](jgjGmjJ4))return FkyzO end;MrHR4XLm["fennel-module"]=FkyzO
|
|
do local IGiruNd="fennel.macros"local tjTQb4m;local function U9vs8w()
|
|
return FkyzO end;package.preload[IGiruNd]=U9vs8w
|
|
tjTQb4m=nil;local KPHc6Aeq
|
|
do
|
|
local Lx=CD["make-compiler-env"](nil,Mm.scopes.compiler,{})do end(Lx)["utils"]=MrHR4XLm;Lx["fennel"]=FkyzO;KPHc6Aeq=Lx end
|
|
local kB6a=K([===[;; These macros are awkward because their definition cannot rely on the any
|
|
;; built-in macros, only special forms. (no when, no icollect, etc)
|
|
|
|
(fn copy [t]
|
|
(let [out []]
|
|
(each [_ v (ipairs t)] (table.insert out v))
|
|
(setmetatable out (getmetatable t))))
|
|
|
|
(fn ->* [val ...]
|
|
"Thread-first macro.
|
|
Take the first value and splice it into the second form as its first argument.
|
|
The value of the second form is spliced into the first arg of the third, etc."
|
|
(var x val)
|
|
(each [_ e (ipairs [...])]
|
|
(let [elt (if (list? e) (copy e) (list e))]
|
|
(table.insert elt 2 x)
|
|
(set x elt)))
|
|
x)
|
|
|
|
(fn ->>* [val ...]
|
|
"Thread-last macro.
|
|
Same as ->, except splices the value into the last position of each form
|
|
rather than the first."
|
|
(var x val)
|
|
(each [_ e (ipairs [...])]
|
|
(let [elt (if (list? e) (copy e) (list e))]
|
|
(table.insert elt x)
|
|
(set x elt)))
|
|
x)
|
|
|
|
(fn -?>* [val ?e ...]
|
|
"Nil-safe thread-first macro.
|
|
Same as -> except will short-circuit with nil when it encounters a nil value."
|
|
(if (= nil ?e)
|
|
val
|
|
(let [el (if (list? ?e) (copy ?e) (list ?e))
|
|
tmp (gensym)]
|
|
(table.insert el 2 tmp)
|
|
`(let [,tmp ,val]
|
|
(if (not= nil ,tmp)
|
|
(-?> ,el ,...)
|
|
,tmp)))))
|
|
|
|
(fn -?>>* [val ?e ...]
|
|
"Nil-safe thread-last macro.
|
|
Same as ->> except will short-circuit with nil when it encounters a nil value."
|
|
(if (= nil ?e)
|
|
val
|
|
(let [el (if (list? ?e) (copy ?e) (list ?e))
|
|
tmp (gensym)]
|
|
(table.insert el tmp)
|
|
`(let [,tmp ,val]
|
|
(if (not= ,tmp nil)
|
|
(-?>> ,el ,...)
|
|
,tmp)))))
|
|
|
|
(fn ?dot [tbl ...]
|
|
"Nil-safe table look up.
|
|
Same as . (dot), except will short-circuit with nil when it encounters
|
|
a nil value in any of subsequent keys."
|
|
(let [head (gensym :t)
|
|
lookups `(do
|
|
(var ,head ,tbl)
|
|
,head)]
|
|
(each [_ k (ipairs [...])]
|
|
;; Kinda gnarly to reassign in place like this, but it emits the best lua.
|
|
;; With this impl, it emits a flat, concise, and readable set of ifs
|
|
(table.insert lookups (# lookups) `(if (not= nil ,head)
|
|
(set ,head (. ,head ,k)))))
|
|
lookups))
|
|
|
|
(fn doto* [val ...]
|
|
"Evaluate val and splice it into the first argument of subsequent forms."
|
|
(assert (not= val nil) "missing subject")
|
|
(let [rebind? (or (not (sym? val))
|
|
(multi-sym? val))
|
|
name (if rebind? (gensym) val)
|
|
form (if rebind? `(let [,name ,val]) `(do))]
|
|
(each [_ elt (ipairs [...])]
|
|
(let [elt (if (list? elt) (copy elt) (list elt))]
|
|
(table.insert elt 2 name)
|
|
(table.insert form elt)))
|
|
(table.insert form name)
|
|
form))
|
|
|
|
(fn when* [condition body1 ...]
|
|
"Evaluate body for side-effects only when condition is truthy."
|
|
(assert body1 "expected body")
|
|
`(if ,condition
|
|
(do
|
|
,body1
|
|
,...)))
|
|
|
|
(fn with-open* [closable-bindings ...]
|
|
"Like `let`, but invokes (v:close) on each binding after evaluating the body.
|
|
The body is evaluated inside `xpcall` so that bound values will be closed upon
|
|
encountering an error before propagating it."
|
|
(let [bodyfn `(fn []
|
|
,...)
|
|
closer `(fn close-handlers# [ok# ...]
|
|
(if ok# ... (error ... 0)))
|
|
traceback `(. (or package.loaded.fennel debug) :traceback)]
|
|
(for [i 1 (length closable-bindings) 2]
|
|
(assert (sym? (. closable-bindings i))
|
|
"with-open only allows symbols in bindings")
|
|
(table.insert closer 4 `(: ,(. closable-bindings i) :close)))
|
|
`(let ,closable-bindings
|
|
,closer
|
|
(close-handlers# (_G.xpcall ,bodyfn ,traceback)))))
|
|
|
|
(fn extract-into [iter-tbl]
|
|
(var (into iter-out found?) (values [] (copy iter-tbl)))
|
|
(for [i (length iter-tbl) 2 -1]
|
|
(let [item (. iter-tbl i)]
|
|
(if (or (= `&into item)
|
|
(= :into item))
|
|
(do
|
|
(assert (not found?) "expected only one &into clause")
|
|
(set found? true)
|
|
(set into (. iter-tbl (+ i 1)))
|
|
(table.remove iter-out i)
|
|
(table.remove iter-out i)))))
|
|
(assert (or (not found?) (sym? into) (table? into) (list? into))
|
|
"expected table, function call, or symbol in &into clause")
|
|
(values into iter-out))
|
|
|
|
(fn collect* [iter-tbl key-expr value-expr ...]
|
|
"Return a table made by running an iterator and evaluating an expression that
|
|
returns key-value pairs to be inserted sequentially into the table. This can
|
|
be thought of as a table comprehension. The body should provide two expressions
|
|
(used as key and value) or nil, which causes it to be omitted.
|
|
|
|
For example,
|
|
(collect [k v (pairs {:apple \"red\" :orange \"orange\"})]
|
|
(values v k))
|
|
returns
|
|
{:red \"apple\" :orange \"orange\"}
|
|
|
|
Supports an &into clause after the iterator to put results in an existing table.
|
|
Supports early termination with an &until clause."
|
|
(assert (and (sequence? iter-tbl) (<= 2 (length iter-tbl)))
|
|
"expected iterator binding table")
|
|
(assert (not= nil key-expr) "expected key and value expression")
|
|
(assert (= nil ...)
|
|
"expected 1 or 2 body expressions; wrap multiple expressions with do")
|
|
(let [kv-expr (if (= nil value-expr) key-expr `(values ,key-expr ,value-expr))
|
|
(into iter) (extract-into iter-tbl)]
|
|
`(let [tbl# ,into]
|
|
(each ,iter
|
|
(let [(k# v#) ,kv-expr]
|
|
(if (and (not= k# nil) (not= v# nil))
|
|
(tset tbl# k# v#))))
|
|
tbl#)))
|
|
|
|
(fn seq-collect [how iter-tbl value-expr ...]
|
|
"Common part between icollect and fcollect for producing sequential tables.
|
|
|
|
Iteration code only differs in using the for or each keyword, the rest
|
|
of the generated code is identical."
|
|
(assert (not= nil value-expr) "expected table value expression")
|
|
(assert (= nil ...)
|
|
"expected exactly one body expression. Wrap multiple expressions in do")
|
|
(let [(into iter) (extract-into iter-tbl)]
|
|
`(let [tbl# ,into]
|
|
;; believe it or not, using a var here has a pretty good performance
|
|
;; boost: https://p.hagelb.org/icollect-performance.html
|
|
(var i# (length tbl#))
|
|
(,how ,iter
|
|
(let [val# ,value-expr]
|
|
(when (not= nil val#)
|
|
(set i# (+ i# 1))
|
|
(tset tbl# i# val#))))
|
|
tbl#)))
|
|
|
|
(fn icollect* [iter-tbl value-expr ...]
|
|
"Return a sequential table made by running an iterator and evaluating an
|
|
expression that returns values to be inserted sequentially into the table.
|
|
This can be thought of as a table comprehension. If the body evaluates to nil
|
|
that element is omitted.
|
|
|
|
For example,
|
|
(icollect [_ v (ipairs [1 2 3 4 5])]
|
|
(when (not= v 3)
|
|
(* v v)))
|
|
returns
|
|
[1 4 16 25]
|
|
|
|
Supports an &into clause after the iterator to put results in an existing table.
|
|
Supports early termination with an &until clause."
|
|
(assert (and (sequence? iter-tbl) (<= 2 (length iter-tbl)))
|
|
"expected iterator binding table")
|
|
(seq-collect 'each iter-tbl value-expr ...))
|
|
|
|
(fn fcollect* [iter-tbl value-expr ...]
|
|
"Return a sequential table made by advancing a range as specified by
|
|
for, and evaluating an expression that returns values to be inserted
|
|
sequentially into the table. This can be thought of as a range
|
|
comprehension. If the body evaluates to nil that element is omitted.
|
|
|
|
For example,
|
|
(fcollect [i 1 10 2]
|
|
(when (not= i 3)
|
|
(* i i)))
|
|
returns
|
|
[1 25 49 81]
|
|
|
|
Supports an &into clause after the range to put results in an existing table.
|
|
Supports early termination with an &until clause."
|
|
(assert (and (sequence? iter-tbl) (< 2 (length iter-tbl)))
|
|
"expected range binding table")
|
|
(seq-collect 'for iter-tbl value-expr ...))
|
|
|
|
(fn accumulate-impl [for? iter-tbl body ...]
|
|
(assert (and (sequence? iter-tbl) (<= 4 (length iter-tbl)))
|
|
"expected initial value and iterator binding table")
|
|
(assert (not= nil body) "expected body expression")
|
|
(assert (= nil ...)
|
|
"expected exactly one body expression. Wrap multiple expressions with do")
|
|
(let [[accum-var accum-init] iter-tbl
|
|
iter (sym (if for? "for" "each"))] ; accumulate or faccumulate?
|
|
`(do
|
|
(var ,accum-var ,accum-init)
|
|
(,iter ,[(unpack iter-tbl 3)]
|
|
(set ,accum-var ,body))
|
|
,(if (list? accum-var)
|
|
(list (sym :values) (unpack accum-var))
|
|
accum-var))))
|
|
|
|
(fn accumulate* [iter-tbl body ...]
|
|
"Accumulation macro.
|
|
|
|
It takes a binding table and an expression as its arguments. In the binding
|
|
table, the first form starts out bound to the second value, which is an initial
|
|
accumulator. The rest are an iterator binding table in the format `each` takes.
|
|
|
|
It runs through the iterator in each step of which the given expression is
|
|
evaluated, and the accumulator is set to the value of the expression. It
|
|
eventually returns the final value of the accumulator.
|
|
|
|
For example,
|
|
(accumulate [total 0
|
|
_ n (pairs {:apple 2 :orange 3})]
|
|
(+ total n))
|
|
returns 5"
|
|
(accumulate-impl false iter-tbl body ...))
|
|
|
|
(fn faccumulate* [iter-tbl body ...]
|
|
"Identical to accumulate, but after the accumulator the binding table is the
|
|
same as `for` instead of `each`. Like collect to fcollect, will iterate over a
|
|
numerical range like `for` rather than an iterator."
|
|
(accumulate-impl true iter-tbl body ...))
|
|
|
|
(fn double-eval-safe? [x type]
|
|
(or (= :number type) (= :string type) (= :boolean type)
|
|
(and (sym? x) (not (multi-sym? x)))))
|
|
|
|
(fn partial* [f ...]
|
|
"Return a function with all arguments partially applied to f."
|
|
(assert f "expected a function to partially apply")
|
|
(let [bindings []
|
|
args []]
|
|
(each [_ arg (ipairs [...])]
|
|
(if (double-eval-safe? arg (type arg))
|
|
(table.insert args arg)
|
|
(let [name (gensym)]
|
|
(table.insert bindings name)
|
|
(table.insert bindings arg)
|
|
(table.insert args name))))
|
|
(let [body (list f (unpack args))]
|
|
(table.insert body _VARARG)
|
|
;; only use the extra let if we need double-eval protection
|
|
(if (= 0 (length bindings))
|
|
`(fn [,_VARARG] ,body)
|
|
`(let ,bindings
|
|
(fn [,_VARARG] ,body))))))
|
|
|
|
(fn pick-args* [n f]
|
|
"Create a function of arity n that applies its arguments to f.
|
|
|
|
For example,
|
|
(pick-args 2 func)
|
|
expands to
|
|
(fn [_0_ _1_] (func _0_ _1_))"
|
|
(if (and _G.io _G.io.stderr)
|
|
(_G.io.stderr:write
|
|
"-- WARNING: pick-args is deprecated and will be removed in the future.\n"))
|
|
(assert (and (= (type n) :number) (= n (math.floor n)) (<= 0 n))
|
|
(.. "Expected n to be an integer literal >= 0, got " (tostring n)))
|
|
(let [bindings []]
|
|
(for [i 1 n]
|
|
(tset bindings i (gensym)))
|
|
`(fn ,bindings
|
|
(,f ,(unpack bindings)))))
|
|
|
|
(fn pick-values* [n ...]
|
|
"Evaluate to exactly n values.
|
|
|
|
For example,
|
|
(pick-values 2 ...)
|
|
expands to
|
|
(let [(_0_ _1_) ...]
|
|
(values _0_ _1_))"
|
|
(assert (and (= :number (type n)) (<= 0 n) (= n (math.floor n)))
|
|
(.. "Expected n to be an integer >= 0, got " (tostring n)))
|
|
(let [let-syms (list)
|
|
let-values (if (= 1 (select "#" ...)) ... `(values ,...))]
|
|
(for [i 1 n]
|
|
(table.insert let-syms (gensym)))
|
|
(if (= n 0) `(values)
|
|
`(let [,let-syms ,let-values]
|
|
(values ,(unpack let-syms))))))
|
|
|
|
(fn lambda* [...]
|
|
"Function literal with nil-checked arguments.
|
|
Like `fn`, but will throw an exception if a declared argument is passed in as
|
|
nil, unless that argument's name begins with a question mark."
|
|
(let [args [...]
|
|
has-internal-name? (sym? (. args 1))
|
|
arglist (if has-internal-name? (. args 2) (. args 1))
|
|
docstring-position (if has-internal-name? 3 2)
|
|
has-docstring? (and (< docstring-position (length args))
|
|
(= :string (type (. args docstring-position))))
|
|
arity-check-position (- 4 (if has-internal-name? 0 1)
|
|
(if has-docstring? 0 1))
|
|
empty-body? (< (length args) arity-check-position)]
|
|
(fn check! [a]
|
|
(if (table? a)
|
|
(each [_ a (pairs a)]
|
|
(check! a))
|
|
(let [as (tostring a)]
|
|
(and (not (as:match "^?")) (not= as "&") (not= as "_")
|
|
(not= as "...") (not= as "&as")))
|
|
(table.insert args arity-check-position
|
|
`(_G.assert (not= nil ,a)
|
|
,(: "Missing argument %s on %s:%s" :format
|
|
(tostring a)
|
|
(or a.filename :unknown)
|
|
(or a.line "?"))))))
|
|
|
|
(assert (= :table (type arglist)) "expected arg list")
|
|
(each [_ a (ipairs arglist)]
|
|
(check! a))
|
|
(if empty-body?
|
|
(table.insert args (sym :nil)))
|
|
`(fn ,(unpack args))))
|
|
|
|
(fn macro* [name ...]
|
|
"Define a single macro."
|
|
(assert (sym? name) "expected symbol for macro name")
|
|
(local args [...])
|
|
`(macros {,(tostring name) (fn ,(unpack args))}))
|
|
|
|
(fn macrodebug* [form return?]
|
|
"Print the resulting form after performing macroexpansion.
|
|
With a second argument, returns expanded form as a string instead of printing."
|
|
(let [handle (if return? `do `print)]
|
|
`(,handle ,(view (macroexpand form _SCOPE)))))
|
|
|
|
(fn import-macros* [binding1 module-name1 ...]
|
|
"Bind a table of macros from each macro module according to a binding form.
|
|
Each binding form can be either a symbol or a k/v destructuring table.
|
|
Example:
|
|
(import-macros mymacros :my-macros ; bind to symbol
|
|
{:macro1 alias : macro2} :proj.macros) ; import by name"
|
|
(assert (and binding1 module-name1 (= 0 (% (select "#" ...) 2)))
|
|
"expected even number of binding/modulename pairs")
|
|
(for [i 1 (select "#" binding1 module-name1 ...) 2]
|
|
;; delegate the actual loading of the macros to the require-macros
|
|
;; special which already knows how to set up the compiler env and stuff.
|
|
;; this is weird because require-macros is deprecated but it works.
|
|
(let [(binding modname) (select i binding1 module-name1 ...)
|
|
scope (get-scope)
|
|
;; if the module-name is an expression (and not just a string) we
|
|
;; patch our expression to have the correct source filename so
|
|
;; require-macros can pass it down when resolving the module-name.
|
|
expr `(import-macros ,modname)
|
|
filename (if (list? modname) (. modname 1 :filename) :unknown)
|
|
_ (tset expr :filename filename)
|
|
macros* (_SPECIALS.require-macros expr scope {} binding)]
|
|
(if (sym? binding)
|
|
;; bind whole table of macros to table bound to symbol
|
|
(tset scope.macros (. binding 1) macros*)
|
|
;; 1-level table destructuring for importing individual macros
|
|
(table? binding)
|
|
(each [macro-name [import-key] (pairs binding)]
|
|
(assert (= :function (type (. macros* macro-name)))
|
|
(.. "macro " macro-name " not found in module "
|
|
(tostring modname)))
|
|
(tset scope.macros import-key (. macros* macro-name))))))
|
|
nil)
|
|
|
|
{:-> ->*
|
|
:->> ->>*
|
|
:-?> -?>*
|
|
:-?>> -?>>*
|
|
:?. ?dot
|
|
:doto doto*
|
|
:when when*
|
|
:with-open with-open*
|
|
:collect collect*
|
|
:icollect icollect*
|
|
:fcollect fcollect*
|
|
:accumulate accumulate*
|
|
:faccumulate faccumulate*
|
|
:partial partial*
|
|
:lambda lambda*
|
|
:λ lambda*
|
|
:pick-args pick-args*
|
|
:pick-values pick-values*
|
|
:macro macro*
|
|
:macrodebug macrodebug*
|
|
:import-macros import-macros*}
|
|
]===],{env=KPHc6Aeq,scope=Mm.scopes.compiler,useMetadata=true,filename="src/fennel/macros.fnl",moduleName=IGiruNd})local Z53B
|
|
for PtID,j in pairs(kB6a)do Mm.scopes.global.macros[PtID]=j end;Z53B=nil
|
|
local _5pPpX=K([===[;;; Pattern matching
|
|
;; This is separated out so we can use the "core" macros during the
|
|
;; implementation of pattern matching.
|
|
|
|
(fn copy [t] (collect [k v (pairs t)] k v))
|
|
|
|
(fn with [opts k]
|
|
(doto (copy opts) (tset k true)))
|
|
|
|
(fn without [opts k]
|
|
(doto (copy opts) (tset k nil)))
|
|
|
|
(fn case-values [vals pattern unifications case-pattern opts]
|
|
(let [condition `(and)
|
|
bindings []]
|
|
(each [i pat (ipairs pattern)]
|
|
(let [(subcondition subbindings) (case-pattern [(. vals i)] pat
|
|
unifications (without opts :multival?))]
|
|
(table.insert condition subcondition)
|
|
(icollect [_ b (ipairs subbindings) &into bindings] b)))
|
|
(values condition bindings)))
|
|
|
|
(fn case-table [val pattern unifications case-pattern opts]
|
|
(let [condition `(and (= (_G.type ,val) :table))
|
|
bindings []]
|
|
(each [k pat (pairs pattern)]
|
|
(if (= pat `&)
|
|
(let [rest-pat (. pattern (+ k 1))
|
|
rest-val `(select ,k ((or table.unpack _G.unpack) ,val))
|
|
subcondition (case-table `(pick-values 1 ,rest-val)
|
|
rest-pat unifications case-pattern
|
|
(without opts :multival?))]
|
|
(if (not (sym? rest-pat))
|
|
(table.insert condition subcondition))
|
|
(assert (= nil (. pattern (+ k 2)))
|
|
"expected & rest argument before last parameter")
|
|
(table.insert bindings rest-pat)
|
|
(table.insert bindings [rest-val]))
|
|
(= k `&as)
|
|
(do
|
|
(table.insert bindings pat)
|
|
(table.insert bindings val))
|
|
(and (= :number (type k)) (= `&as pat))
|
|
(do
|
|
(assert (= nil (. pattern (+ k 2)))
|
|
"expected &as argument before last parameter")
|
|
(table.insert bindings (. pattern (+ k 1)))
|
|
(table.insert bindings val))
|
|
;; don't process the pattern right after &/&as; already got it
|
|
(or (not= :number (type k)) (and (not= `&as (. pattern (- k 1)))
|
|
(not= `& (. pattern (- k 1)))))
|
|
(let [subval `(. ,val ,k)
|
|
(subcondition subbindings) (case-pattern [subval] pat
|
|
unifications
|
|
(without opts :multival?))]
|
|
(table.insert condition subcondition)
|
|
(icollect [_ b (ipairs subbindings) &into bindings] b))))
|
|
(values condition bindings)))
|
|
|
|
(fn case-guard [vals condition guards unifications case-pattern opts]
|
|
(if (= 0 (length guards))
|
|
(case-pattern vals condition unifications opts)
|
|
(let [(pcondition bindings) (case-pattern vals condition unifications opts)
|
|
condition `(and ,(unpack guards))]
|
|
(values `(and ,pcondition
|
|
(let ,bindings
|
|
,condition)) bindings))))
|
|
|
|
(fn symbols-in-pattern [pattern]
|
|
"gives the set of symbols inside a pattern"
|
|
(if (list? pattern)
|
|
(let [result {}]
|
|
(each [_ child-pattern (ipairs pattern)]
|
|
(collect [name symbol (pairs (symbols-in-pattern child-pattern)) &into result]
|
|
name symbol))
|
|
result)
|
|
(sym? pattern)
|
|
(if (and (not= pattern `or)
|
|
(not= pattern `where)
|
|
(not= pattern `?)
|
|
(not= pattern `nil))
|
|
{(tostring pattern) pattern}
|
|
{})
|
|
(= (type pattern) :table)
|
|
(let [result {}]
|
|
(each [key-pattern value-pattern (pairs pattern)]
|
|
(collect [name symbol (pairs (symbols-in-pattern key-pattern)) &into result]
|
|
name symbol)
|
|
(collect [name symbol (pairs (symbols-in-pattern value-pattern)) &into result]
|
|
name symbol))
|
|
result)
|
|
{}))
|
|
|
|
(fn symbols-in-every-pattern [pattern-list infer-unification?]
|
|
"gives a list of symbols that are present in every pattern in the list"
|
|
(let [?symbols (accumulate [?symbols nil
|
|
_ pattern (ipairs pattern-list)]
|
|
(let [in-pattern (symbols-in-pattern pattern)]
|
|
(if ?symbols
|
|
(do
|
|
(each [name symbol (pairs ?symbols)]
|
|
(when (not (. in-pattern name))
|
|
(tset ?symbols name nil)))
|
|
?symbols)
|
|
in-pattern)))]
|
|
(icollect [_ symbol (pairs (or ?symbols {}))]
|
|
(if (not (and infer-unification?
|
|
(in-scope? symbol)))
|
|
symbol))))
|
|
|
|
(fn case-or [vals pattern guards unifications case-pattern opts]
|
|
(let [pattern [(unpack pattern 2)]
|
|
bindings (symbols-in-every-pattern pattern opts.infer-unification?)] ;; TODO opts.infer-unification instead of opts.unification?
|
|
(if (= 0 (length bindings))
|
|
;; no bindings special case generates simple code
|
|
(let [condition
|
|
(icollect [i subpattern (ipairs pattern) &into `(or)]
|
|
(let [(subcondition subbindings) (case-pattern vals subpattern unifications opts)]
|
|
subcondition))]
|
|
(values
|
|
(if (= 0 (length guards))
|
|
condition
|
|
`(and ,condition ,(unpack guards)))
|
|
[]))
|
|
;; case with bindings is handled specially, and returns three values instead of two
|
|
(let [matched? (gensym :matched?)
|
|
bindings-mangled (icollect [_ binding (ipairs bindings)]
|
|
(gensym (tostring binding)))
|
|
pre-bindings `(if)]
|
|
(each [i subpattern (ipairs pattern)]
|
|
(let [(subcondition subbindings) (case-guard vals subpattern guards {} case-pattern opts)]
|
|
(table.insert pre-bindings subcondition)
|
|
(table.insert pre-bindings `(let ,subbindings
|
|
(values true ,(unpack bindings))))))
|
|
(values matched?
|
|
[`(,(unpack bindings)) `(values ,(unpack bindings-mangled))]
|
|
[`(,matched? ,(unpack bindings-mangled)) pre-bindings])))))
|
|
|
|
(fn case-pattern [vals pattern unifications opts top-level?]
|
|
"Take the AST of values and a single pattern and returns a condition
|
|
to determine if it matches as well as a list of bindings to
|
|
introduce for the duration of the body if it does match."
|
|
|
|
;; This function returns the following values (multival):
|
|
;; a "condition", which is an expression that determines whether the
|
|
;; pattern should match,
|
|
;; a "bindings", which bind all of the symbols used in a pattern
|
|
;; an optional "pre-bindings", which is a list of bindings that happen
|
|
;; before the condition and bindings are evaluated. These should only
|
|
;; come from a (case-or). In this case there should be no recursion:
|
|
;; the call stack should be case-condition > case-pattern > case-or
|
|
;;
|
|
;; Here are the expected flags in the opts table:
|
|
;; :infer-unification? boolean - if the pattern should guess when to unify (ie, match -> true, case -> false)
|
|
;; :multival? boolean - if the pattern can contain multivals (in order to disallow patterns like [(1 2)])
|
|
;; :in-where? boolean - if the pattern is surrounded by (where) (where opts into more pattern features)
|
|
;; :legacy-guard-allowed? boolean - if the pattern should allow `(a ? b) patterns
|
|
|
|
;; we have to assume we're matching against multiple values here until we
|
|
;; know we're either in a multi-valued clause (in which case we know the #
|
|
;; of vals) or we're not, in which case we only care about the first one.
|
|
(let [[val] vals]
|
|
(if (and (sym? pattern)
|
|
(or (= pattern `nil)
|
|
(and opts.infer-unification?
|
|
(in-scope? pattern)
|
|
(not= pattern `_))
|
|
(and opts.infer-unification?
|
|
(multi-sym? pattern)
|
|
(in-scope? (. (multi-sym? pattern) 1)))))
|
|
(values `(= ,val ,pattern) [])
|
|
;; unify a local we've seen already
|
|
(and (sym? pattern) (. unifications (tostring pattern)))
|
|
(values `(= ,(. unifications (tostring pattern)) ,val) [])
|
|
;; bind a fresh local
|
|
(sym? pattern)
|
|
(let [wildcard? (: (tostring pattern) :find "^_")]
|
|
(if (not wildcard?) (tset unifications (tostring pattern) val))
|
|
(values (if (or wildcard? (string.find (tostring pattern) "^?")) true
|
|
`(not= ,(sym :nil) ,val)) [pattern val]))
|
|
;; opt-in unify with (=)
|
|
(and (list? pattern)
|
|
(= (. pattern 1) `=)
|
|
(sym? (. pattern 2)))
|
|
(let [bind (. pattern 2)]
|
|
(assert-compile (= 2 (length pattern)) "(=) should take only one argument" pattern)
|
|
(assert-compile (not opts.infer-unification?) "(=) cannot be used inside of match" pattern)
|
|
(assert-compile opts.in-where? "(=) must be used in (where) patterns" pattern)
|
|
(assert-compile (and (sym? bind) (not= bind `nil) "= has to bind to a symbol" bind))
|
|
(values `(= ,val ,bind) []))
|
|
;; where-or clause
|
|
(and (list? pattern) (= (. pattern 1) `where) (list? (. pattern 2)) (= (. pattern 2 1) `or))
|
|
(do
|
|
(assert-compile top-level? "can't nest (where) pattern" pattern)
|
|
(case-or vals (. pattern 2) [(unpack pattern 3)] unifications case-pattern (with opts :in-where?)))
|
|
;; where clause
|
|
(and (list? pattern) (= (. pattern 1) `where))
|
|
(do
|
|
(assert-compile top-level? "can't nest (where) pattern" pattern)
|
|
(case-guard vals (. pattern 2) [(unpack pattern 3)] unifications case-pattern (with opts :in-where?)))
|
|
;; or clause (not allowed on its own)
|
|
(and (list? pattern) (= (. pattern 1) `or))
|
|
(do
|
|
(assert-compile top-level? "can't nest (or) pattern" pattern)
|
|
;; This assertion can be removed to make patterns more permissive
|
|
(assert-compile false "(or) must be used in (where) patterns" pattern)
|
|
(case-or vals pattern [] unifications case-pattern opts))
|
|
;; guard clause
|
|
(and (list? pattern) (= (. pattern 2) `?))
|
|
(do
|
|
(assert-compile opts.legacy-guard-allowed? "legacy guard clause not supported in case" pattern)
|
|
(case-guard vals (. pattern 1) [(unpack pattern 3)] unifications case-pattern opts))
|
|
;; multi-valued patterns (represented as lists)
|
|
(list? pattern)
|
|
(do
|
|
(assert-compile opts.multival? "can't nest multi-value destructuring" pattern)
|
|
(case-values vals pattern unifications case-pattern opts))
|
|
;; table patterns
|
|
(= (type pattern) :table)
|
|
(case-table val pattern unifications case-pattern opts)
|
|
;; literal value
|
|
(values `(= ,val ,pattern) []))))
|
|
|
|
(fn add-pre-bindings [out pre-bindings]
|
|
"Decide when to switch from the current `if` AST to a new one"
|
|
(if pre-bindings
|
|
;; `out` no longer needs to grow.
|
|
;; Instead, a new tail `if` AST is introduced, which is where the rest of
|
|
;; the clauses will get appended. This way, all future clauses have the
|
|
;; pre-bindings in scope.
|
|
(let [tail `(if)]
|
|
(table.insert out true)
|
|
(table.insert out `(let ,pre-bindings ,tail))
|
|
tail)
|
|
;; otherwise, keep growing the current `if` AST.
|
|
out))
|
|
|
|
(fn case-condition [vals clauses match?]
|
|
"Construct the actual `if` AST for the given match values and clauses."
|
|
;; root is the original `if` AST.
|
|
;; out is the `if` AST that is currently being grown.
|
|
(let [root `(if)]
|
|
(faccumulate [out root
|
|
i 1 (length clauses) 2]
|
|
(let [pattern (. clauses i)
|
|
body (. clauses (+ i 1))
|
|
(condition bindings pre-bindings) (case-pattern vals pattern {}
|
|
{:multival? true
|
|
:infer-unification? match?
|
|
:legacy-guard-allowed? match?}
|
|
true)
|
|
out (add-pre-bindings out pre-bindings)]
|
|
;; grow the `if` AST by one extra condition
|
|
(table.insert out condition)
|
|
(table.insert out `(let ,bindings
|
|
,body))
|
|
out))
|
|
root))
|
|
|
|
(fn count-case-multival [pattern]
|
|
"Identify the amount of multival values that a pattern requires."
|
|
(if (and (list? pattern) (= (. pattern 2) `?))
|
|
(count-case-multival (. pattern 1))
|
|
(and (list? pattern) (= (. pattern 1) `where))
|
|
(count-case-multival (. pattern 2))
|
|
(and (list? pattern) (= (. pattern 1) `or))
|
|
(accumulate [longest 0
|
|
_ child-pattern (ipairs pattern)]
|
|
(math.max longest (count-case-multival child-pattern)))
|
|
(list? pattern)
|
|
(length pattern)
|
|
1))
|
|
|
|
(fn case-val-syms [clauses]
|
|
"What is the length of the largest multi-valued clause? return a list of that
|
|
many gensyms."
|
|
(let [patterns (fcollect [i 1 (length clauses) 2]
|
|
(. clauses i))
|
|
sym-count (accumulate [longest 0
|
|
_ pattern (ipairs patterns)]
|
|
(math.max longest (count-case-multival pattern)))]
|
|
(fcollect [i 1 sym-count &into (list)]
|
|
(gensym))))
|
|
|
|
(fn case-impl [match? val ...]
|
|
"The shared implementation of case and match."
|
|
(assert (not= val nil) "missing subject")
|
|
(assert (= 0 (math.fmod (select :# ...) 2))
|
|
"expected even number of pattern/body pairs")
|
|
(assert (not= 0 (select :# ...))
|
|
"expected at least one pattern/body pair")
|
|
(let [clauses [...]
|
|
vals (case-val-syms clauses)]
|
|
;; protect against multiple evaluation of the value, bind against as
|
|
;; many values as we ever match against in the clauses.
|
|
(list `let [vals val] (case-condition vals clauses match?))))
|
|
|
|
(fn case* [val ...]
|
|
"Perform pattern matching on val. See reference for details.
|
|
|
|
Syntax:
|
|
|
|
(case data-expression
|
|
pattern body
|
|
(where pattern guards*) body
|
|
(or pattern patterns*) body
|
|
(where (or pattern patterns*) guards*) body
|
|
;; legacy:
|
|
(pattern ? guards*) body)"
|
|
(case-impl false val ...))
|
|
|
|
(fn match* [val ...]
|
|
"Perform pattern matching on val, automatically unifying on variables in
|
|
local scope. See reference for details.
|
|
|
|
Syntax:
|
|
|
|
(match data-expression
|
|
pattern body
|
|
(where pattern guards*) body
|
|
(or pattern patterns*) body
|
|
(where (or pattern patterns*) guards*) body
|
|
;; legacy:
|
|
(pattern ? guards*) body)"
|
|
(case-impl true val ...))
|
|
|
|
(fn case-try-step [how expr else pattern body ...]
|
|
(if (= nil pattern body)
|
|
expr
|
|
;; unlike regular match, we can't know how many values the value
|
|
;; might evaluate to, so we have to capture them all in ... via IIFE
|
|
;; to avoid double-evaluation.
|
|
`((fn [...]
|
|
(,how ...
|
|
,pattern ,(case-try-step how body else ...)
|
|
,(unpack else)))
|
|
,expr)))
|
|
|
|
(fn case-try-impl [how expr pattern body ...]
|
|
(let [clauses [pattern body ...]
|
|
last (. clauses (length clauses))
|
|
catch (if (= `catch (and (= :table (type last)) (. last 1)))
|
|
(let [[_ & e] (table.remove clauses)] e) ; remove `catch sym
|
|
[`_# `...])]
|
|
(assert (= 0 (math.fmod (length clauses) 2))
|
|
"expected every pattern to have a body")
|
|
(assert (= 0 (math.fmod (length catch) 2))
|
|
"expected every catch pattern to have a body")
|
|
(case-try-step how expr catch (unpack clauses))))
|
|
|
|
(fn case-try* [expr pattern body ...]
|
|
"Perform chained pattern matching for a sequence of steps which might fail.
|
|
|
|
The values from the initial expression are matched against the first pattern.
|
|
If they match, the first body is evaluated and its values are matched against
|
|
the second pattern, etc.
|
|
|
|
If there is a (catch pat1 body1 pat2 body2 ...) form at the end, any mismatch
|
|
from the steps will be tried against these patterns in sequence as a fallback
|
|
just like a normal match. If there is no catch, the mismatched values will be
|
|
returned as the value of the entire expression."
|
|
(case-try-impl `case expr pattern body ...))
|
|
|
|
(fn match-try* [expr pattern body ...]
|
|
"Perform chained pattern matching for a sequence of steps which might fail.
|
|
|
|
The values from the initial expression are matched against the first pattern.
|
|
If they match, the first body is evaluated and its values are matched against
|
|
the second pattern, etc.
|
|
|
|
If there is a (catch pat1 body1 pat2 body2 ...) form at the end, any mismatch
|
|
from the steps will be tried against these patterns in sequence as a fallback
|
|
just like a normal match. If there is no catch, the mismatched values will be
|
|
returned as the value of the entire expression."
|
|
(case-try-impl `match expr pattern body ...))
|
|
|
|
{:case case*
|
|
:case-try case-try*
|
|
:match match*
|
|
:match-try match-try*}
|
|
]===],{env=KPHc6Aeq,scope=Mm.scopes.compiler,allowedGlobals=false,useMetadata=true,filename="src/fennel/match.fnl",moduleName=IGiruNd})
|
|
for aP,oUuAO4X6 in pairs(_5pPpX)do Mm.scopes.global.macros[aP]=oUuAO4X6 end;package.preload[IGiruNd]=nil end;local iJYISVW=FkyzO
|
|
local function K(q2lIy)
|
|
is_passed,out=pcall(function()return iJYISVW.eval(q2lIy)end,function(n62)return
|
|
n62 end)lua=""out=tostring(out)preview=out:gsub("\n.*","")if is_passed then
|
|
lua=iJYISVW.compileString(q2lIy)end
|
|
return{is_passed=is_passed,preview=preview,out=out,lua=lua}end
|
|
return
|
|
{{CodeBlock=function(_NgKSEFg)
|
|
if _NgKSEFg.classes:includes("eval")then local ydBwQ3=_NgKSEFg.text
|
|
print("⚙️ ",ydBwQ3)local Jo7L=K(ydBwQ3)
|
|
print("",Jo7L["is_passed"],"→",Jo7L["preview"])if _NgKSEFg.classes:includes("replace")then return
|
|
pandoc.CodeBlock(Jo7L["out"],{code=ydBwQ3})end end end}} |