diff --git a/arvo/ames.hoon b/arvo/ames.hoon index b4c8ba64a..2a6b74458 100644 --- a/arvo/ames.hoon +++ b/arvo/ames.hoon @@ -225,7 +225,7 @@ 0w0 :: 54, ~wyd, Curtis Yarvin (sator) 0w0 :: 55, ~tep, Curtis Yarvin (sator) 0w0 :: 56, ~bes, Curtis Yarvin (sator) - 0w0 :: 57, ~dex, Curtis Yarvin (sator) + 0w0 :: 57, ~dex, Jared Hance (aestas) 0w0 :: 58, ~sef, Curtis Yarvin (sator) 0w0 :: 59, ~wyc, Curtis Yarvin (sator) 0w0 :: 60, ~bur, Curtis Yarvin (sator) @@ -240,7 +240,7 @@ 0w0 :: 69, ~pet, Curtis Yarvin (sator) 0w0 :: 70, ~rul, Curtis Yarvin (sator) 0w0 :: 71, ~syn, Curtis Yarvin (sator) - 0w0 :: 72, ~reg, Curtis Yarvin (sator) + 0w0 :: 72, ~reg, Henry Ault (aestas) 0w0 :: 73, ~tyd, Curtis Yarvin (sator) 0w0 :: 74, ~sup, Curtis Yarvin (sator) 0w0 :: 75, ~sem, ~boswed-nibnyd (fidelis) @@ -255,9 +255,9 @@ 0w2x.~ldho.Oo7kE.QqNSx.XteFh :: 84, ~web, Ar Vicco (donum) 0w0 :: 85, ~sum, Curtis Yarvin (sator) 0w0 :: 86, ~mut, Curtis Yarvin (sator) - 0w0 :: 87, ~nyx, urbit.org (civitas) + 0w0 :: 87, ~nyx, Curtis Yarvin (sator) 0w30.UUr19.iBPlD.wfyJD.2CWPv :: 88, ~rex, Ben Davenport (angelus) - 0w0 :: 89, ~teb, urbit.org (civitas) + 0w0 :: 89, ~teb, Curtis Yarvin (sator) 0w0 :: 90, ~fus, urbit.org (civitas) 0w0 :: 91, ~hep, urbit.org (civitas) 0w0 :: 92, ~ben, urbit.org (civitas) @@ -277,7 +277,7 @@ 0w0 :: 106, ~bet, urbit.org (civitas) 0w0 :: 107, ~bel, urbit.org (civitas) 0w0 :: 108, ~tux, Chen Zheng (angelus) - 0w0 :: 109, ~tug, urbit.org (civitas) + 0w0 :: 109, ~tug, Philip Monk (aestas) 0w0 :: 110, ~myr, urbit.org (civitas) 0w0 :: 111, ~pel, urbit.org (civitas) 0w0 :: 112, ~syp, urbit.org (civitas) @@ -316,7 +316,7 @@ 0w0 :: 145, ~leb, ~nosryl-tarpem (fidelis) 0w0 :: 146, ~dux, urbit.org (civitas) 0w0 :: 147, ~ryn, urbit.org (civitas) - 0w0 :: 148, ~num, urbit.org (civitas) + 0w0 :: 148, ~num, Tlon (gleba) 0w0 :: 149, ~pyx, ~racbes-solmun (fidelis) 0w2g.gLmg4.MtrHQ.A5VmH.WPk6G :: 150, ~ryg, Dan Haffey (fortuna) 0w0 :: 151, ~ryx, Tlon (gleba) @@ -415,7 +415,7 @@ 0w0 :: 244, ~byr, Tlon (gleba) 0w0 :: 245, ~sen, Tlon (gleba) 0w0 :: 246, ~weg, Tlon (gleba) - 0w0 :: 247, ~fyr, Tlon (gleba) + 0wU.VWcJa.TR1rQ.ONSCN.Mi5TW :: 247, ~fyr, Anton Dyudin (aestas) 0w0 :: 248, ~mur, Tlon (gleba) 0w0 :: 249, ~tel, Tlon (gleba) 0w0 :: 250, ~rep, Tlon (gleba) @@ -439,7 +439,7 @@ vix=(bex +((cut 0 [25 2] mag))) :: width of sender tay=(cut 0 [27 5] mag) :: message type == - ?> =(0 vez) + ?> =(7 vez) ?> =(chk (end 0 20 (mug bod))) :+ [(end 3 wix bod) (cut 3 [wix vix] bod)] (kins tay) @@ -459,7 +459,7 @@ =+ tay=(ksin q.kec) %+ mix %+ can 0 - :~ [3 0] + :~ [3 7] [20 (mug bod)] [2 yax] [2 qax] @@ -1047,7 +1047,7 @@ ++ gnaw :: gnaw:am |= [kay=cape ryn=lane pac=rock] :: process packet ^- [p=(list boon) q=fort] - ?. =(0 (end 0 3 pac)) [~ fox] + ?. =(7 (end 0 3 pac)) [~ fox] =+ kec=(bite pac) ?: (goop p.p.kec) [~ fox] ?. (~(has by urb.ton.fox) q.p.kec) @@ -1342,7 +1342,7 @@ +>(..la (tuck p.fud q.fud r.fud)) :: %buck - =. +> ?.(=(%full aut) +> cock) + =. +> ?.(=(%full aut) +> cock) :: finish key exch +>(..la (tock p.fud q.fud r.fud)) :: %bond @@ -1819,7 +1819,7 @@ :: ~& [%knap soq num pax] =+ ^= fuy =< zork =< zank - %+ ~(rack am [now fox]) soq :- pax + %^ ~(rack am [now fox]) soq pax ?-(+<.sih %mean `p.+.sih, %nice ~) => %_(. fox q.fuy) =| out=(list move) diff --git a/arvo/clay.hoon b/arvo/clay.hoon index 10bc985ba..71ca2ed34 100644 --- a/arvo/clay.hoon +++ b/arvo/clay.hoon @@ -2,7 +2,7 @@ :: |= pit=vase => |% -++ cult (map duct rave) :: subscriptions +++ cult (map duct rove) :: subscriptions ++ dojo ,[p=cult q=dome] :: domestic desk state ++ gift :: out result <-$ $% [%ergo p=@p q=@tas r=@ud] :: version update @@ -20,6 +20,7 @@ [%wart p=sock q=@tas r=path s=*] :: network request [%warp p=sock q=riff] :: file request == :: +++ moot ,[p=case q=case r=path s=(map path lobe)] :: ++ move ,[p=duct q=(mold note gift)] :: local move ++ nako $: gar=(map ,@ud tako) :: new ids let=@ud :: next id @@ -74,6 +75,7 @@ hez=(unit duct) :: sync duch dos=(map desk dojo) :: native desk == :: +++ rove (each mood moot) :: ++ rung $: rus=(map desk rede) :: neighbor desks == :: -- => @@ -135,7 +137,7 @@ +>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn]) :: ++ bleb :: ship sequence - |= [hen=duct ins=@ud hip=nako] + |= [hen=duct ins=@ud hip=*] ^+ +> (blab hen [%w [%ud ins] ~] hip) :: @@ -147,13 +149,13 @@ =+ xiq=(~(tap by qyx) ~) ^- (unit ,@da) %+ roll xiq - |= [xaq=[p=duct q=rave] nex=(unit ,@da)] + |= [xaq=[p=duct q=rove] nex=(unit ,@da)] %+ hunt nex ?- -.q.xaq & ?.(?=(%da -.q.p.q.xaq) ~ [~ p.q.p.q.xaq]) :: | - =+ mot=`moat`p.q.xaq + =+ mot=`moot`p.q.xaq %+ hunt ?. ?=(%da -.p.mot) ~ ?.((lth now p.p.mot) ~ [~ p.p.mot]) @@ -162,14 +164,15 @@ == :: ++ duce :: produce request - |= [hen=duct rav=rave] + |= [hen=duct rov=rove] ^+ +> - =. qyx (~(put by qyx) hen rav) - ?~ ref +> - |- ^+ +>+.$ + =. qyx (~(put by qyx) hen rov) + ?~ ref +>.$ + |- ^+ +>+.$ :: XX why? + =+ rav=(reve rov) =+ ^= vaw ^- rave ?. ?=([%& %v *] rav) rav - [%| [%ud let.dom] `case`q.p.rav] + [%| [%ud let.dom] `case`q.p.rav r.p.rav] =+ inx=nix.u.ref %= +>+.$ say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say] @@ -211,18 +214,22 @@ =+ nab=(~(aeon ze lim dom ran) p.p.rav) ?~ nab ?> =(~ (~(aeon ze lim dom ran) q.p.rav)) - (duce hen rav) + ~! [%um rav] + (duce hen (rive rav)) =+ huy=(~(aeon ze lim dom ran) q.p.rav) ?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab)))) (blub hen) =+ top=?~(huy let.dom u.huy) - =+ fud=(~(gack ze lim dom ran) u.nab let.dom) - =. +>.$ (bleb hen u.nab fud) + =+ sar=(~(apax ze lim dom ran) u.nab r.p.rav) + =+ ear=(~(apax ze lim dom ran) top r.p.rav) + =. +>.$ ?: =(sar ear) +>.$ + =+ fud=(~(gack ze lim dom ran) u.nab top) + (bleb hen u.nab fud) ?^ huy (blub hen) =+ ^= ptr ^- case [%ud +(let.dom)] - (duce hen `rave`[%| ptr q.p.rav]) + (duce hen `rove`[%| ptr q.p.rav r.p.rav ear]) == :: ++ echa :: announce raw @@ -336,10 +343,21 @@ haw.u.ref (~(del by haw.u.ref) nez) == :: + ++ reve + |= rov=rove + ^- rave + ?: ?=(%& -.rov) rov + [%| p.p.rov q.p.rov r.p.rov] + :: + ++ rive + |= rav=[%| p=moat] + ^- rove + [%| p.p.rav q.p.rav r.p.rav ~] + :: ++ wake :: update subscribers ^+ . =+ xiq=(~(tap by qyx) ~) - =| xaq=(list ,[p=duct q=rave]) + =| xaq=(list ,[p=duct q=rove]) |- ^+ ..wake ?~ xiq ..wake(qyx (~(gas by *cult) xaq)) @@ -357,23 +375,28 @@ $(xiq t.xiq, ..wake (balk p.i.xiq u.nao p.q.i.xiq)) :: | - =+ mot=`moat`p.q.i.xiq + =+ mot=`moot`p.q.i.xiq =+ nab=(~(aeon ze lim dom ran) p.mot) ?~ nab $(xiq t.xiq, xaq [i.xiq xaq]) =+ huy=(~(aeon ze lim dom ran) q.mot) ?~ huy =+ ptr=[%ud +(let.dom)] - =+ fud=`nako`(~(gack ze lim dom ran) u.nab let.dom) %= $ xiq t.xiq - xaq [[p.i.xiq [%| ptr q.mot]] xaq] - ..wake (bleb p.i.xiq let.dom fud) + xaq [[p.i.xiq [%| ptr q.mot r.mot s.mot]] xaq] + ..wake =+ ear=(~(apax ze lim dom ran) let.dom r.p.q.i.xiq) + ?: =(s.p.q.i.xiq ear) ..wake + =+ fud=(~(gack ze lim dom ran) u.nab let.dom) + (bleb p.i.xiq let.dom ear) == - =+ fud=(~(gack ze lim dom ran) u.nab u.huy) %= $ xiq t.xiq - ..wake (blub:(bleb p.i.xiq +(u.nab) fud) p.i.xiq) + ..wake =- (blub:- p.i.xiq) + =+ ear=(~(apax ze lim dom ran) u.huy r.p.q.i.xiq) + ?: =(s.p.q.i.xiq ear) ..wake + =+ fud=(~(gack ze lim dom ran) u.nab u.huy) + (bleb p.i.xiq +(u.nab) ear) == == -- diff --git a/arvo/eyre.hoon b/arvo/eyre.hoon index 178fa0ccd..5437ed8a1 100644 --- a/arvo/eyre.hoon +++ b/arvo/eyre.hoon @@ -139,8 +139,7 @@ hen=duct :: event trace som=seam :: logical request pez=pest :: request state - vaz=(list ,[p=cord q=tape]) :: variables - sip=(list manx) :: scripts in result + sip=marl :: injected scripts == :: ++ rote :: remote server $: cnt=@ud :: number served @@ -152,6 +151,7 @@ [%aph p=ship q=@ud r=@ud s=json] :: app heartbeat [%apg p=term q=ship r=mark s=path] :: app get/start [%apm p=ship q=@ud r=@ud s=hasp t=json] :: message send + [%app p=ship q=(unit ,@ud)] :: script by port [%aps p=ship q=@ud s=hasp t=path] :: subscribe [%apu p=ship q=@ud s=hasp t=path] :: unsubscribe [%cog p=@ud q=@ud] :: console get @@ -226,7 +226,8 @@ =+ ten=(~(get by q.moh) 'content-type') ?~ ten ~ ?~ u.ten ~ - ?. =('text/json' (end 3 9 i.u.ten)) ~ + ?. =('text/json' (end 3 9 i.u.ten)) + ~| %ecce-content-type ~ ?~ r.moh ~ `(unit json)`(rush q.u.r.moh apex:poja) :: @@ -314,28 +315,6 @@ =+ rep=:(welp p.hop scr q.q.hop) [%mid p.luv (tact rep)] == -++ lofe :: variables in head - |= [vaz=(list ,[p=cord q=tape]) luv=love] - %- lofa - :_ luv - :_ ~ - ^- manx - :- [%script ~] - :- :/ "window.urb = \{};\0a" - (turn vaz |=([a=cord b=tape] :/("window.urb.{(trip a)}={b};\0a"))) -:: -++ lofi :: insert in body - |= [mog=(list manx) luv=love] - ^- love - ?: =(~ mog) luv - ?+ -.luv luv - %mid - ?. =(/text/html p.luv) luv - =+ str=(trip q.q.luv) - =+ scr=|-(^-(tape ?~(mog "" (xmlt & i.mog $(mog t.mog))))) - =+ rep=(need (repg "" str scr)) - [%mid p.luv (tact rep)] - == :: ++ loft :: love to response |= luv=love @@ -390,9 +369,8 @@ (slav %ud i.t.t.t.tea) ?~ ouy +>.$ - :: ?: (lth ~m2 (sub now tim.bet.siq:beat:u.ouy)) - :: ~& %axon-heartbeat - :: abet:work:amok:u.ouy + ?: (lth ~m2 (sub now tim.bet.siq:beat:u.ouy)) + abet:work:amok:u.ouy =* mab t.t.t.t.tea =+ woy=(yule:u.ouy ?+(i.mab !! %mess %meg, %show %sub)) =< abet =< work =< abet @@ -608,7 +586,7 @@ =+ cyz=(need (~(get by wup.sef) ses)) ~(. ya [our ses] sef cyz) :: - ++ galt + ++ galt :: |= [our=ship ses=hole num=@ud mez=(each bead (list tank))] ^+ +> =+ suf=(~(get by own) our) @@ -918,116 +896,115 @@ |= [our=ship whu=(unit ship) rul=tape ruf=tape] ^- manx =+ ^= sic ^- manx - ;script - ; - ; var seal = { - ; who: goal, - ; url: burl, - ; pas: null - ; } - ; var hist = [] - ; var hind = 0 - ; $( - ; function() { - ; $input = $('#input .line') - ; $prompt = $('#input .prompt') - ; $prompt.addClass('prefix') - ; $output = $('#output') - ; $input.focus() - ; $('body').click(function() { $input.focus() }) - ; ctrl = false; - ; - ; start = function(ship) { - ; $prompt.text('vessel: ~') - ; $input.attr('placeholder', 'ship-name') - ; if(ship) { - ; $input.val(ship) - ; } - ; } - ; - ; ident = function() { - ; seal.who = $input.val() - ; - ; if( (seal.who.length != 13) && - ; (seal.who.length != 6) && - ; (seal.who.length != 3) ) - ; { - ; $output.text('not a ship name - try again.'); - ; return false; - ; } - ; - ; if(seal.who !== host) { - ; var foreign = {oth: host, ses: session}; - ; var all = $.extend({}, seal, foreign); - ; - ; console.log('redirect') - ; window.location="http://"+seal.who+".urbit.org/gul" - ; + $.params(all); - ; return false; - ; } - ; - ; $output.text($prompt.text() + " " + seal.who) - ; $input.val('') - ; $input.attr('placeholder', 'ronber-bacnub-hanmev-labnyd') - ; $prompt.text('secret: ~') - ; - ; return true; - ; } - ; - ; login = function() { - ; seal.pas = $input.val() - ; - ; output = $output.html() - ; console.log($output.html()) - ; $output.html(output.replace('sorry. please try again.
','')) - ; - ; $.post(form, seal, function(data,xhr,status) { - ; console.log(data); - ; if(data.ok == true) { - ; document.location = data.next; - ; } else { - ; $output.prepend('sorry. please try again.
') - ; } - ; }) - ; } - ; - ; steps = [ident,login] - ; step = 0 - ; start(seal.who) - ; if(seal.who) { - ; ident() - ; step++ - ; } - ; - ; $input.on('keydown', function(e) { - ; if(e.keyCode == 17) { - ; ctrl = true - ; return; - ; } - ; - ; if(e.keyCode == 68 && - ; ctrl == true && - ; step == 1) { - ; $output.text('') - ; step = 0 - ; start(null) - ; return; - ; } - ; - ; if(e.keyCode == 13) { - ; if(steps[step]() && step < steps.length-1) - ; step++ - ; return; - ; } - ; }); - ; - ; $input.on('keyup', function(e) { - ; if(e.keyCode == 17) { - ; ctrl = false - ; } - ; }); - ; }) - == + ;script:''' + var seal = { + who: goal, + url: burl, + pas: null + } + var hist = [] + var hind = 0 + $( + function() { + $input = $('#input .line') + $prompt = $('#input .prompt') + $prompt.addClass('prefix') + $output = $('#output') + $input.focus() + $('body').click(function() { $input.focus() }) + ctrl = false; + + start = function(ship) { + $prompt.text('vessel: ~') + $input.attr('placeholder', 'ship-name') + if(ship) { + $input.val(ship) + } + } + + ident = function() { + seal.who = $input.val() + + if( (seal.who.length != 13) && + (seal.who.length != 6) && + (seal.who.length != 3) ) + { + $output.text('not a ship name - try again.'); + return false; + } + + if(seal.who !== host) { + var foreign = {oth: host, ses: session}; + var all = $.extend({}, seal, foreign); + + console.log('redirect') + window.location="http://"+seal.who+".urbit.org/gul" + + $.params(all); + return false; + } + + $output.text($prompt.text() + " " + seal.who) + $input.val('') + $input.attr('placeholder', 'ronber-bacnub-hanmev-labnyd') + $prompt.text('secret: ~') + + return true; + } + + login = function() { + seal.pas = $input.val() + + output = $output.html() + console.log($output.html()) + $output.html(output.replace('sorry. please try again.
','')) + + $.post(form, seal, function(data,xhr,status) { + console.log(data); + if(data.ok == true) { + document.location = data.next; + } else { + $output.prepend('sorry. please try again.
') + } + }) + } + + steps = [ident,login] + step = 0 + start(seal.who) + if(seal.who) { + ident() + step++ + } + + $input.on('keydown', function(e) { + if(e.keyCode == 17) { + ctrl = true + return; + } + + if(e.keyCode == 68 && + ctrl == true && + step == 1) { + $output.text('') + step = 0 + start(null) + return; + } + + if(e.keyCode == 13) { + if(steps[step]() && step < steps.length-1) + step++ + return; + } + }); + + $input.on('keyup', function(e) { + if(e.keyCode == 17) { + ctrl = false + } + }); + }) + ''' =+ ^= cof ;= ; var host = '{(trip (rsh 3 1 (scot %p our)))}'; @@ -1041,32 +1018,32 @@ ;head ;title: urbit login ;script(type "text/javascript", src jqu); - ;style - ; body { - ; margin: 60px 120px; - ; font: normal 12px "Menlo" monospace; - ; background-color: #000; - ; color: #fff; - ; } - ; - ; #output { - ; - ; } - ; - ; #input .prompt { - ; display: inline-block; - ; margin-right: 12px; - ; } - ; - ; #input .line { - ; outline: none; - ; width: 80%; - ; border: 0; - ; background-color: transparent; - ; color: #fff; - ; font: normal 12px "Menlo" monospace; - ; } - == + ;style:''' + body { + margin: 60px 120px; + font: normal 12px "Menlo" monospace; + background-color: #000; + color: #fff; + } + + #output { + + } + + #input .prompt { + display: inline-block; + margin-right: 12px; + } + + #input .line { + outline: none; + width: 80%; + border: 0; + background-color: transparent; + color: #fff; + font: normal 12px "Menlo" monospace; + } + ''' == =+ ^= bod ^- manx ;body @@ -1148,30 +1125,24 @@ ?> ?=(%way pez.u.pup) $(yov t.yov, q.rey (~(put by q.rey) i.yov u.pup(pez noz))) :: - ++ duti :: heartbeat script - ;script:''' - window.urb.seqn_h = 0 - window.urb.heartbeat = function() { - this.poll({ - type:"heb", - ship:this.ship, - dely:30000, - incs:function() { - window.urb.seqn_h++ - } - },function() { - console.log('heartbeat.') - }) - } - // XX 404 bug - // window.urb.heartbeat() + ++ duty |= [our=ship nap=@ud you=ship orx=oryx] :: interface script + ^- cord + %^ cat 3 + %- crip + =- "window.urb = {(pojo (jobe -))}\0a" + :~ + [%ship (jape |1:)] + [%port (jone nap)] + [%auto %b %&] + [%user (jape |1:)] + [%oryx %s orx] + == ''' - :: - ++ duty - ;script:''' window.urb.seqn_u = 0 + window.urb.seqn_h = 0 window.urb.dely = 0 window.urb.puls = 0 + window.urb.cabs = {} window.urb.perms = { pol:"gie", sub:"tis", @@ -1241,8 +1212,11 @@ } window.urb.gsig = function(params) { + path = params.path + if(!path) + path = "" return params.appl+","+ - params.path.replace(/[^\x00-\x7F]/g, "")+","+ + path.replace(/[^\x00-\x7F]/g, "")+","+ params.ship } @@ -1251,16 +1225,23 @@ throw new Error("You must supply params to urb.poll.") var method, perm, url, $this - method = "get" perm = params.type ? this.perms[params.type] : "gie" - url = [perm,this.user,this.port,this.seqn_u] + json = false + if(perm[0] == "t") { + method = "put" + json = true + } + seqn = this.seqn_u + if(params.seqn) + seqn = params.seqn() + url = [perm,this.user,this.port,seqn] url = "/"+url.join("/") this.puls = 1 $this = this - this.req(method,url,params,false,function(err,data) { + this.req(method,url,params,json,function(err,data) { if (data.data.reload) { return document.location.reload() } else { @@ -1297,6 +1278,23 @@ } window.urb.poll(param) } + + window.urb.heartbeat = function() { + this.poll({ + type:"heb", + ship:this.ship, + dely:30000, + seqn:function() { + return window.urb.seqn_h + }, + incs:function() { + window.urb.seqn_h = window.urb.seqn_h+1 + } + },function() { + console.log('heartbeat.') + }) + } + window.urb.heartbeat() ''' :: ++ fape :: dispatch %ape @@ -1350,6 +1348,18 @@ (need (eccu orx.ced moh)) == :: + ++ fapp + |= [fur=(unit term) you=@p paw=path] + ?> ?=([~ %js] fur) + ?> ?=(?([%hart ~] [@ %hart ~]) paw) + :- ~ + :* %app + you + ?~ t.paw + ~ + (some (slav %ui (cat 3 '0i' i.paw))) + == + :: ++ faps :: dispatch %aps |= [fur=(unit term) you=@p paw=path moh=moth] ^- (unit seam) @@ -1455,8 +1465,9 @@ == :: ++ foin :: version request - |= [fur=(unit term) paw=(list ,@t) quy=quay] + |= [fur=(unit term) you=@p paw=(list ,@t) quy=quay] ^- (unit seam) + =. aut.ced (~(put ju aut.ced) %$ (scot %p you)) :: XX backwards ?. ?& ?=(~ fur) ?=(~ quy) ?=([@ @ ~] paw) @@ -1470,17 +1481,18 @@ ~ :: [%$ ?(%da %ud %tas) @] - [~ (case p.u.soy) (case p.u.soy)] + [~ (case p.u.soy) (case p.u.soy) /] :: [%many [%$ ?(%da %ud %tas) @] [%$ ?(%da %ud %tas) @] ~] - [~ (case i.p.u.soy) (case i.t.p.u.soy)] + [~ (case i.p.u.soy) (case i.t.p.u.soy) /] == |= mot=moat `seam`[%det i.t.paw mot] :: ++ funk :: functional request - |= [nep=@tas fur=(unit term) paw=(list ,@t) quy=quay] + |= [nep=@tas fur=(unit term) you=@p paw=(list ,@t) quy=quay] ^- (unit seam) + =. aut.ced (~(put ju aut.ced) %$ (scot %p you)) :: XX backwards =+ won==(%n (rsh 3 2 nep)) %+ bind ^- (unit ,[mark tube]) @@ -1508,11 +1520,15 @@ toe(s (weld s.toe `path`[~(rent co (flux [nep ~] quy)) %web ~])) ?. won ~ :_ ~ - =- =+ pey=(cat 3 (end 3 2 nep) %v) + =- =+ pey="{(scag 2 (trip nep))}v" + =. pey %+ weld pey + ?. =(%i (snag 1 pey)) + "" + "/{(slag 1 (scow %p you))}" =+ ven=+((,@ (need (sky %cw p.toe q.toe r.toe ~)))) =+ ^= cal :/ "path='". - "/{(trip pey)}". + "/{pey}". "/{(scow %ud ven)}". "/{(trip q.toe)}';" [-.sac [cal +.sac]] @@ -1591,6 +1607,7 @@ %r :: app response %s :: app subscribe %h :: app heartbeat + %p :: app script by port %n :: now %u :: app unsubscribe %z :: app version @@ -1615,12 +1632,13 @@ ?+ one ~ %g ?+ tri ~ - ?(%f %n) (funk nep p.q.pul paw r.pul) - %v (foin p.q.pul paw r.pul) + ?(%f %n) (funk nep p.q.pul yun paw r.pul) + %v (foin p.q.pul yun paw r.pul) %c (flub paw ~) %l (fool r.pul) %g (fapg p.q.pul yun paw) %e (fape p.q.pul yun paw) + %p (fapp p.q.pul yun paw) == :: %p @@ -1706,7 +1724,6 @@ *seam `pest`[%raw pul moh] ~ - ~ == == :: @@ -1777,6 +1794,10 @@ :: ~& [%wink-apm +.som.pip] :- [~ pip(pez %way)] (yokm num +.som.pip) + :: + %app :: script by port + :: ~& [%wink-app +.som.pip] + (yokp num +.som.pip) :: %aps :: subscribe :: ~& [%wink-aps +.som.pip] @@ -1892,7 +1913,7 @@ :+ 500 ~[content-type/'text/html'] [~ (tact (xmlt | mad ~))] - & [%fin (lofe vaz.pip (lofi mog (lopo q.p.p.pez.pip)))] + & [%fin (lofa mog (lopo q.p.p.pez.pip))] == == :: @@ -1948,6 +1969,17 @@ ?~ yon (bust 204 num) abet:(post:u.yon cnt num hap jon) :: + ++ yokp :: script by port + |= [num=@ud you=ship nup=(unit ,@ud)] + ^- [(unit pimp) _+>] + ?~ nup + $(nup [~ num], +> ~(harp yo num you *sink)) + =+ yon=(yolk u.nup) + ?~ yon + =+ err=(bust 204 num) + [`(need (~(get by q.rey.err) num)) err] + [- abet:+]:(hark:u.yon num) + :: ++ yoks :: subscribe |= [num=@ud you=ship nap=@ud hap=hasp pax=path] =+ yon=(yolk nap) @@ -1991,7 +2023,7 @@ (pass(hen hen.q.i.wuh) `p.i.wuh `note`[%g %nuke hap.q.i.wuh you]) == :: - ++ beat + ++ beat |= [cnt=@ud num=@ud jon=json] ^- [(unit pimp) _+>] ?. =(cnt num.bet.siq) @@ -2001,6 +2033,18 @@ =. +>.$ (hear:(yule %bet) ~ %& %json !>((joba %a-ok %b %&))) [`(need (~(get by q.rey) num)) +>.$] :: + ++ hark + |= num=@ud + ^- [(unit pimp) _+>] + =. +>.$ abet:(busk:(yule %nil) num _@ ~ %& %js !>((duty our nap you orx.ced))) + [`(need (~(get by q.rey) num)) +>.$] + :: + ++ harp + %_ abet + tim.bet.siq now + num.sub.siq 1 + == + :: ++ hoop :: request path |= can=(unit ,@ud) ^- path @@ -2096,22 +2140,17 @@ == =+ pip=u.pup =+ ^= sip - ?. =(%apg -.som.pip) sip.pip - [duti duty sip.pip] + ?. ?=(%apg -.som.pip) sip.pip + =* his q.som.pip + =+ mef=?:(=(our his) "gop" "gip/{|1:}") + [;script(src "/{mef}/{(pojo (jone nap))}/hart.js"); sip.pip] ?~ huq +>.$(..yo (bust 404 num)) %= +>.$ q.rey %+ ~(put by q.rey) num ^- pimp - =+ quo=|=(a=cord :(weld "\"" (trip a) "\"")) %= pip pez %new - vaz :~ [%ship (quo (rsh 3 1 (scot %p our)))] - [%port (trip (rsh 3 2 (scot %ui nap)))] - [%auto "true"] - [%oryx (quo orx.ced)] - [%user (quo (rsh 3 1 (scot %p you)))] - == sip sip som ^- seam :+ %sil diff --git a/arvo/ford.hoon b/arvo/ford.hoon index cf10ee508..98fe28311 100644 --- a/arvo/ford.hoon +++ b/arvo/ford.hoon @@ -503,7 +503,7 @@ (stag %hub ;~(pfix pat day:read)) (stag %man ;~(pfix tar man:read)) (stag %nap ;~(pfix cen day:read)) - (stag %now ;~(pfix fas day:read)) + (stag %now ;~(pfix pam day:read)) (stag %saw ;~(pfix sem saw:read)) (stag %see ;~(pfix col see:read)) (stag %sic ;~(pfix ket sic:read)) diff --git a/arvo/gall.hoon b/arvo/gall.hoon index eabf9b590..847dfea2d 100644 --- a/arvo/gall.hoon +++ b/arvo/gall.hoon @@ -332,22 +332,28 @@ ++ gasp :: %x take |= [hen=duct pax=path sih=sign] ^- [(list move) _..^$] - ?: ?=(%a -.sih) [~ ..^$] - ?> ?=(%f -.sih) - :_ ..^$ - :_ ~ - :- hen - ?- -.p.+.sih - %| - [%give %crud %gasp-crud p.p.+.sih] - :: - %& - =+ cay=`cage`q.p.p.+.sih - ?+ -.pax !! - %d [%give (best %rush cay)] - %f [%give (best %rust cay)] + ?+ -.sih !! + %a + ?> ?=(%woot +<.sih) + :_ ..^$ :_ ~ + ?~ q.sih + [hen %give %nice ~] + [hen %give %mean u.q.sih] + %f + :_ ..^$ + :_ ~ + :- hen + ?- -.p.+.sih + %| + [%give %crud %gasp-crud p.p.+.sih] + :: + %& + =+ cay=`cage`q.p.p.+.sih + ?+ -.pax !! + %d [%give (best %rush cay)] + %f [%give (best %rust cay)] + == == == - == :: ++ gave :: %r take |= [hen=duct pax=path sih=sign] @@ -630,7 +636,7 @@ :- hun.mat :^ %pass (away %w %drug (scot %p p.a) q.a ~) %c ~& [%sync-subscribe our p.a q.a] - [%warp [our p.a] q.a ~ %| [%da +(now)] [%da (add now ~d1000)]] + [%warp [our p.a] q.a ~ %| [%da +(now)] [%da (add now ~d1000)] /] =+ ^= old ^- (list move) %+ turn %+ skip (~(tap in ped.sat) ~) @@ -990,7 +996,7 @@ ?. (warm %pour) +>.$(qic.sat ~) ?> ?=(^ huv.sat) - =+ sam=(slop !>(p.kon) q.kon) + =+ sam=:(slop [[%atom %ud] ost] !>(p.kon) q.kon) %+ ford /s/pour [%call (harm %pour (conf (core u.huv.sat))) (cove %$ sam)] == diff --git a/arvo/hoon.hoon b/arvo/hoon.hoon index 838bd5c85..0cedcb0dd 100644 --- a/arvo/hoon.hoon +++ b/arvo/hoon.hoon @@ -50,14 +50,8 @@ [ven=term pro=term kel=@] :: vendor and product [ven=term pro=term ver=@ kel=@] :: all of the above == :: -++ claw $% [%ash p=twig] :: XX not used - [%elm p=twig] :: - [%oak ~] :: - [%yew p=(map term claw)] :: - == :: ++ clue ,[p=axis q=chum r=tyre] :: battery definition -++ coat ,[p=path q=vase] :: -++ coil $: p=?(%gold %iron %lead %zinc) :: +++ coil $: p=?(%gold %iron %lead %zinc) :: core type q=type :: r=[p=?(~ ^) q=(map term foot)] :: == :: @@ -71,7 +65,7 @@ ++ dram $% [| p=(map ,@tas dram)] :: simple unix dir [& p=@ud q=@] :: == :: -++ each |*([a=$+(* *) b=$+(* *)] $%([& p=a] [| p=b])) :: +++ each |*([a=$+(* *) b=$+(* *)] $%([& p=a] [| p=b])) :: either a or b ++ edge ,[p=hair q=(unit ,[p=* q=nail])] :: parsing output ++ foot $% [%ash p=twig] :: dry arm, geometric [%elm p=twig] :: wet arm, generic @@ -79,13 +73,6 @@ [%yew p=(map term foot)] :: XX not used == :: ++ gate $+(* *) :: general gate -++ gear |* a=_,* :: XX list generator - $_ :: - =| b=* :: - |? :: - ?@ b :: - ~ :: - [i=(a -.b) t=^?(..$(b +.b))] :: ++ hair ,[p=@ud q=@ud] :: parsing trace ++ hapt (list ,@ta) :: XX not used ++ like |* a=_,* :: generic edge @@ -141,7 +128,7 @@ == :: ++ qual |* [a=$+(* *) b=$+(* *) c=$+(* *) d=$+(* *)] :: just a quadruple ,[p=a q=b r=c s=d] :: -:: + :: XX move to zuse ++ rege $| ?(%dote %ende %sart %empt %boun %bout) :: parsed regex $% [%lite p=char] :: literal [%pair p=rege q=rege] :: ordering @@ -164,9 +151,15 @@ ++ spot ,[p=path q=pint] :: range in file ++ tang (list tank) :: general error ++ tank $% [%leaf p=tape] :: printing formats - [%palm p=[p=tape q=tape r=tape s=tape] q=(list tank)] - [%rose p=[p=tape q=tape r=tape] q=(list tank)] - == :: + $: %palm :: + p=[p=tape q=tape r=tape s=tape] :: + q=(list tank) :: + == :: + $: %rose :: + p=[p=tape q=tape r=tape] :: + q=(list tank) :: + == :: + == ++ tape (list char) :: like a string ++ term ,@tas :: Hoon ASCII subset ++ tiki :: test case @@ -204,13 +197,13 @@ ++ twig $& [p=twig q=twig] :: $% :: [%$ p=axis] :: simple leg - :: :: + :: :::::: tiling [%bccb p=tile] :: bunt a tile [%bccm p=tile] :: clam a tile [%bcpt p=wing q=tile] :: whip p into q [%bctr p=tile] :: static bunt w/ ^~ [%bczp p=base] :: bunt an axil - :: :: + :: :::::: cores [%brcb p=tile q=(map term foot)] :: %gold tray, sample p [%brcn p=(map term foot)] :: %gold core, natural [%brdt p=twig] :: dry %gold trap @@ -222,7 +215,7 @@ [%brtr p=tile q=twig] :: vulcan. wet gate [%brts p=tile q=twig] :: dry %gold gate [%brwt p=twig] :: dry %lead trap - :: :: + :: :::::: tuples [%clcb p=twig q=twig] :: [q p] [%clcn p=tusk] :: [[p ~] ~] [%clfs p=twig] :: [%$ [%$ p ~] ~] @@ -232,19 +225,19 @@ [%clsg p=tusk] :: [p ~] [%cltr p=tusk] :: p as a tuple [%clzz p=tusk] :: macro - :: :: + :: :::::: invocations [%cncb p=wing q=tram] :: %=, then cast to p [%cncl p=twig q=twig] :: pull $.p w/ sample q [%cndt p=twig q=twig] :: %-(q p) [%cnhp p=twig q=tusk] :: slam p w/ sample q - [%cntr p=wing q=twig r=tram] :: + [%cntr p=wing q=twig r=tram] :: pull p.q w/ changes [%cnkt p=twig q=twig r=twig s=twig] :: slam p w/ %*(q r s) [%cnls p=twig q=twig r=twig] :: slam p w/ %*(q r) [%cnsg p=wing q=twig r=twig] :: pull p from q with r [%cnts p=wing q=tram] :: eval. p w/ q changes [%cnzy p=term] :: pulls limb p [%cnzz p=wing] :: pulls p - :: :: + :: :::::: nock [%dtkt p=twig] :: nock 11 data skyhook [%dtls p=twig] :: nock 4 increment [%dtzy p=term q=@] :: atom constant @@ -252,9 +245,9 @@ [%dttr p=twig q=twig] :: nock p w/ formula q [%dtts p=twig q=twig] :: nock 5 equality test [%dtwt p=twig] :: nock 3 cell test - :: :: - [%hxgl p=tusk] :: slam noah w/ !>:*(p) - [%hxgr p=tusk] :: slam cain w/ !>:*(p) + :: :::::: prettyprinting + [%hxgl p=tusk] :: prettyprint tape + [%hxgr p=tusk] :: prettyprint tank :: :::::: type conversion [%ktbr p=twig] :: %gold core to %iron [%ktdt p=twig q=twig] :: cast q to type (p q) @@ -278,13 +271,13 @@ [%sgts p=twig q=twig] :: avoid duplication [%sgwt p=@ud q=twig r=twig s=twig] :: hint iff q is yes [%sgzp p=twig q=twig] :: type in stacktrace - :: :: miscellaneous + :: :::::: miscellaneous [%smcl p=twig q=tusk] :: binary to n-ary [%smdt p=twig q=tusk] :: [%smdq p=(list beer)] :: assemble string [%smsg p=twig q=tusk] :: gonads [%smsm p=twig q=twig] :: make sure q is a p - :: :: compositions + :: :::::: compositions [%tsbr p=tile q=twig] :: push bunt: =+(_p q) [%tscl p=tram q=twig] :: p changes, then q [%tscn p=twig q=twig] :: XX not used @@ -305,7 +298,7 @@ [%wthz p=tiki q=tine] :: tiki %wthp [%wtcl p=twig q=twig r=twig] :: if p, then q, else r [%wtdt p=twig q=twig r=twig] :: unless, ?:(p r q) - [%wtkt p=wing q=twig r=twig] :: if p is not its bunt + [%wtkt p=wing q=twig r=twig] :: if p is a cell [%wtkz p=tiki q=twig r=twig] :: tiki %wtkt [%wtgl p=twig q=twig] :: assert |, ?:(p !! q) [%wtgr p=twig q=twig] :: assert &, ?:(p q !!) @@ -456,8 +449,7 @@ ~/ %add |= [a=@ b=@] ^- @ - ?: =(0 a) - b + ?: =(0 a) b $(a (dec a), b +(b)) :: ++ cap :: tree head @@ -478,8 +470,7 @@ ?< =(0 a) =+ b=0 |- ^- @ - ?: =(a +(b)) - b + ?: =(a +(b)) b $(b +(b)) :: ++ div :: divide @@ -490,16 +481,14 @@ ?< =(0 b) =+ c=0 |- - ?: (lth a b) - c + ?: (lth a b) c $(a (sub a b), c +(c)) :: ++ fac :: factorial ~/ %fac |= a=@ ^- @ - ?: =(0 a) - 1 + ?: =(0 a) 1 (mul a $(a (dec a))) :: ++ gte :: greater-equal @@ -523,7 +512,12 @@ ~/ %lth |= [a=@ b=@] ^- ? - &(!=(a b) |-(|(=(0 a) &(!=(0 b) $(a (dec a), b (dec b)))))) + ?& !=(a b) + |- + ?| =(0 a) + ?& !=(0 b) + $(a (dec a), b (dec b)) + == == == :: ++ mas :: tree body ~/ %mas @@ -540,16 +534,14 @@ ~/ %max |= [a=@ b=@] ^- @ - ?: (gth a b) - a + ?: (gth a b) a b :: ++ min :: minimum ~/ %min |= [a=@ b=@] ^- @ - ?: (lth a b) - a + ?: (lth a b) a b :: ++ mod :: remainder @@ -565,8 +557,7 @@ ^- @ =+ c=0 |- - ?: =(0 a) - c + ?: =(0 a) c $(a (dec a), c (add b c)) :: ++ peg :: tree connect @@ -585,8 +576,7 @@ |= [a=@ b=@] ~| %subtract-underflow ^- @ - ?: =(0 b) - a + ?: =(0 b) a $(a (dec a), b (dec b)) :::::::::::::::::::::::::::::::::::::::::::::::::::::: :: :::: chapter 2b, basic containers :::: @@ -595,14 +585,12 @@ :: ++ biff :: apply |* [a=(unit) b=$+(* (unit))] - ?~ a - ~ + ?~ a ~ (b u.a) :: ++ bind :: argue |* [a=(unit) b=gate] - ?~ a - ~ + ?~ a ~ [~ u=(b u.a)] :: ++ bond :: replace @@ -619,16 +607,13 @@ :: ++ clap :: combine |* [a=(unit) b=(unit) c=_|=(^ +<-)] - ?~ a - b - ?~ b - a + ?~ a b + ?~ b a [~ u=(c u.a u.b)] :: ++ drop :: enlist |* a=(unit) - ?~ a - ~ + ?~ a ~ [i=u.a t=~] :: ++ fall :: default @@ -642,16 +627,13 @@ :: ++ mate :: choose |* [a=(unit) b=(unit)] - ?~ b - a - ?~ a - b + ?~ b a + ?~ a b ?.(=(u.a u.b) ~|('mate' !!) a) :: ++ need :: demand |* a=(unit) - ?~ a - !! + ?~ a !! u.a :: ++ some :: lift (pure) @@ -667,8 +649,7 @@ ^+ a =+ b=`_a`~ |- - ?~ a - b + ?~ a b $(a t.a, b [i.a b]) :: ++ homo :: homogenize @@ -691,17 +672,16 @@ ^- @ =+ b=0 |- - ?~(a b $(a t.a, b +(b))) + ?~ a b + $(a t.a, b +(b)) :: ++ levy ~/ %levy :: all of |* [a=(list) b=_|=(p=* .?(p))] |- ^- ? - ?~ a - & - ?: (b i.a) - $(a t.a) - | + ?~ a & + ?. (b i.a) | + $(a t.a) :: ++ lien :: some of ~/ %lien @@ -714,8 +694,7 @@ ++ murn :: maybe transform |* [a=(list) b=$+(* (unit))] |- - ?~ a - ~ + ?~ a ~ =+ c=(b i.a) ?~ c $(a t.a) @@ -725,8 +704,7 @@ |* [a=@ b=*] =| c=(list) |- ^- (list) - ?: =(a 0) - c + ?: =(a 0) c $(c [b c], a (dec a)) :: ++ reel :: right fold @@ -757,8 +735,7 @@ |* [a=(list) b=_|=(p=* .?(p))] |- ^+ a - ?~ a - ~ + ?~ a ~ ?:((b i.a) [i.a $(a t.a)] $(a t.a)) :: ++ skip :: except @@ -766,26 +743,22 @@ |* [a=(list) b=_|=(p=* .?(p))] |- ^+ a - ?~ a - ~ + ?~ a ~ ?:((b i.a) $(a t.a) [i.a $(a t.a)]) :: ++ scag :: prefix ~/ %scag |* [a=@ b=(list)] |- ^+ b - ?: |(?=(~ b) =(0 a)) - ~ + ?: |(?=(~ b) =(0 a)) ~ [i.b $(b t.b, a (dec a))] :: ++ slag :: suffix ~/ %slag |* [a=@ b=(list)] |- ^+ b - ?: =(0 a) - b - ?~ b - ~ + ?: =(0 a) b + ?~ b ~ $(b t.b, a (dec a)) :: ++ snag :: index @@ -794,8 +767,7 @@ |- ?~ b ~|('snag-fail' !!) - ?: =(0 a) - i.b + ?: =(0 a) i.b $(b t.b, a (dec a)) :: ++ sort :: quicksort @@ -817,8 +789,7 @@ ~/ %turn |* [a=(list) b=_,*] |- - ?~ a - ~ + ?~ a ~ [i=(b i.a) t=$(a t.a)] :: ++ weld :: concatenate @@ -862,8 +833,7 @@ ~/ %bex |= a=@ ^- @ - ?: =(0 a) - 1 + ?: =(0 a) 1 (mul 2 $(a (dec a))) :: ++ xeb :: binary logarithm @@ -876,8 +846,7 @@ ~/ %can |= [a=bloq b=(list ,[p=@ q=@])] ^- @ - ?~ b - 0 + ?~ b 0 (mix (end a p.i.b q.i.b) (lsh a p.i.b $(b t.b))) :: ++ cat :: concatenate @@ -915,16 +884,14 @@ ^- @ =+ c=0 |- - ?: =(0 b) - c + ?: =(0 b) c $(b (rsh a 1 b), c +(c)) :: ++ rap :: assemble nonzero ~/ %rap |= [a=bloq b=(list ,@)] ^- @ - ?~ b - 0 + ?~ b 0 (cat a i.b $(b t.b)) :: ++ rep :: assemble single @@ -933,16 +900,14 @@ ^- @ =+ c=0 |- - ?~ b - 0 + ?~ b 0 (con (lsh a c (end a 1 i.b)) $(c +(c), b t.b)) :: ++ rip :: disassemble ~/ %rip |= [a=bloq b=@] ^- (list ,@) - ?: =(0 b) - ~ + ?: =(0 b) ~ [(end a 1 b) $(b (rsh a 1 b))] :: ++ rsh :: right-shift @@ -960,13 +925,16 @@ |= [a=@ b=@] =+ [c=0 d=0] |- ^- @ - ?: ?&(=(0 a) =(0 b)) - d + ?: ?&(=(0 a) =(0 b)) d %= $ a (rsh 0 1 a) b (rsh 0 1 b) c +(c) - d (add d (lsh 0 c ?&(=(0 (end 0 1 a)) =(0 (end 0 1 b))))) + d %+ add d + %^ lsh 0 c + ?& =(0 (end 0 1 a)) + =(0 (end 0 1 b)) + == == :: ++ dis :: binary and @@ -974,13 +942,16 @@ |= [a=@ b=@] =| [c=@ d=@] |- ^- @ - ?: ?|(=(0 a) =(0 b)) - d + ?: ?|(=(0 a) =(0 b)) d %= $ a (rsh 0 1 a) b (rsh 0 1 b) c +(c) - d (add d (lsh 0 c ?|(=(0 (end 0 1 a)) =(0 (end 0 1 b))))) + d %+ add d + %^ lsh 0 c + ?| =(0 (end 0 1 a)) + =(0 (end 0 1 b)) + == == :: ++ mix :: binary xor @@ -989,8 +960,7 @@ ^- @ =+ [c=0 d=0] |- - ?: ?&(=(0 a) =(0 b)) - d + ?: ?&(=(0 a) =(0 b)) d %= $ a (rsh 0 1 a) b (rsh 0 1 b) @@ -1008,16 +978,13 @@ ~/ %aor |= [a=* b=*] ^- ? - ?: =(a b) - & + ?: =(a b) & ?. ?=(@ a) - ?. ?=(@ b) - ?: =(-.a -.b) - $(a +.a, b +.b) - $(a -.a, b -.b) - | - ?. ?=(@ b) - & + ?: ?=(@ b) | + ?: =(-.a -.b) + $(a +.a, b +.b) + $(a -.a, b -.b) + ?. ?=(@ b) & |- =+ [c=(end 3 1 a) d=(end 3 1 b)] ?: =(c d) @@ -1028,16 +995,13 @@ ~/ %dor |= [a=* b=*] ^- ? - ?: =(a b) - & + ?: =(a b) & ?. ?=(@ a) - ?. ?=(@ b) - ?: =(-.a -.b) - $(a +.a, b +.b) - $(a -.a, b -.b) - | - ?. ?=(@ b) - & + ?: ?=(@ b) | + ?: =(-.a -.b) + $(a +.a, b +.b) + $(a -.a, b -.b) + ?. ?=(@ b) & (lth a b) :: ++ gor :: g-order @@ -1054,11 +1018,9 @@ |= [a=* b=*] ^- ? ?: ?=(@ a) - ?: ?=(@ b) - (gor a b) - & - ?: ?=(@ b) - | + ?. ?=(@ b) & + (gor a b) + ?: ?=(@ b) | ?: =(-.a -.b) (gor +.a +.b) (gor -.a -.b) @@ -1114,6 +1076,47 @@ ?.(=(0 ham) ham $(syd +(syd))) -- ++ fnv |=(a=@ (end 5 1 (mul 16.777.619 a))) :: FNV scrambler +:: +++ mum :: mug with murmur3 + ~/ %mum + |= a=* + |^ (trim ?@(a a (mix $(a -.a) (mix 0x7fff.ffff $(a +.a))))) + ++ spec :: standard murmur3 + |= [syd=@ key=@] + ?> (lte (met 5 syd) 1) + =+ ^= row + |= [a=@ b=@] + (con (end 5 1 (lsh 0 a b)) (rsh 0 (sub 32 a) b)) + =+ mow=|=([a=@ b=@] (end 5 1 (mul a b))) + =+ len=(met 5 key) + =- =. goc (mix goc len) + =. goc (mix goc (rsh 4 1 goc)) + =. goc (mow goc 0x85eb.ca6b) + =. goc (mix goc (rsh 0 13 goc)) + =. goc (mow goc 0xc2b2.ae35) + (mix goc (rsh 4 1 goc)) + ^= goc + =+ [inx=0 goc=syd] + |- ^- @ + ?: =(inx len) goc + =+ kop=(cut 5 [inx 1] key) + =. kop (mow kop 0xcc9e.2d51) + =. kop (row 15 kop) + =. kop (mow kop 0x1b87.3593) + =. goc (mix kop goc) + =. goc (row 13 goc) + =. goc (end 5 1 (add 0xe654.6b64 (mul 5 goc))) + $(inx +(inx)) + :: + ++ trim :: 31-bit nonzero + |= key=@ + =+ syd=0xcafe.babe + |- ^- @ + =+ haz=(spec syd key) + =+ ham=(mix (rsh 0 31 haz) (end 0 31 haz)) + ?.(=(0 ham) ham $(syd +(syd))) + -- +:: ++ mug :: 31bit nonzero FNV1a ~/ %mug |= a=* @@ -1139,24 +1142,24 @@ :: ++ po ~/ %po - =+ :- ^= sis - 'dozmarbinwansamlitsighidfidlissogdirwacsabwissib\ - /rigsoldopmodfoglidhopdardorlorhodfolrintogsilmir\ - /holpaslacrovlivdalsatlibtabhanticpidtorbolfosdot\ - /losdilforpilramtirwintadbicdifrocwidbisdasmidlop\ - /rilnardapmolsanlocnovsitnidtipsicropwitnatpanmin\ - /ritpodmottamtolsavposnapnopsomfinfonbanporworsip\ - /ronnorbotwicsocwatdolmagpicdavbidbaltimtasmallig\ - /sivtagpadsaldivdactansidfabtarmonranniswolmispal\ - /lasdismaprabtobrollatlonnodnavfignomnibpagsopral\ - /bilhaddocridmocpacravripfaltodtiltinhapmicfanpat\ - /taclabmogsimsonpinlomrictapfirhasbosbatpochactid\ - /havsaplindibhosdabbitbarracparloddosbortochilmac\ - /tomdigfilfasmithobharmighinradmashalraglagfadtop\ - /mophabnilnosmilfopfamdatnoldinhatnacrisfotribhoc\ - /nimlarfitwalrapsarnalmoslandondanladdovrivbacpol\ - /laptalpitnambonrostonfodponsovnocsorlavmatmipfap' - ^= dex + =+ :- ^= sis :: prefix syllables + 'dozmarbinwansamlitsighidfidlissogdirwacsabwissib\ + /rigsoldopmodfoglidhopdardorlorhodfolrintogsilmir\ + /holpaslacrovlivdalsatlibtabhanticpidtorbolfosdot\ + /losdilforpilramtirwintadbicdifrocwidbisdasmidlop\ + /rilnardapmolsanlocnovsitnidtipsicropwitnatpanmin\ + /ritpodmottamtolsavposnapnopsomfinfonbanporworsip\ + /ronnorbotwicsocwatdolmagpicdavbidbaltimtasmallig\ + /sivtagpadsaldivdactansidfabtarmonranniswolmispal\ + /lasdismaprabtobrollatlonnodnavfignomnibpagsopral\ + /bilhaddocridmocpacravripfaltodtiltinhapmicfanpat\ + /taclabmogsimsonpinlomrictapfirhasbosbatpochactid\ + /havsaplindibhosdabbitbarracparloddosbortochilmac\ + /tomdigfilfasmithobharmighinradmashalraglagfadtop\ + /mophabnilnosmilfopfamdatnoldinhatnacrisfotribhoc\ + /nimlarfitwalrapsarnalmoslandondanladdovrivbacpol\ + /laptalpitnambonrostonfodponsovnocsorlavmatmipfap' + ^= dex :: suffix syllables 'zodnecbudwessevpersutletfulpensytdurwepserwylsun\ /rypsyxdyrnuphebpeglupdepdysputlughecryttyvsydnex\ /lunmeplutseppesdelsulpedtemledtulmetwenbynhexfeb\ @@ -1813,6 +1816,13 @@ |* b=_+<+.a (a b c) :: +++ cork |*([a=_,* b=gate] (corl b a)) +:: +++ corl + |* [a=gate b=_,*] + |= c=_+<.b + (a (b c)) +:: ++ hard |* han=$+(* *) |= fud=* ^- han @@ -2572,15 +2582,15 @@ ~ [i=[p=-.i.leh q=+.i.leh] t=$(leh t.leh)] :: -++ stew +++ stew :: switch by first char ~/ %stew - |* leh=(list ,[p=?(@ [@ @]) q=_rule]) - =+ ^= wor + |* leh=(list ,[p=?(@ [@ @]) q=_rule]) :: char/range keys + =+ ^= wor :: range complete lth |= [ort=?(@ [@ @]) wan=?(@ [@ @])] ?@ ort ?@(wan (lth ort wan) (lth ort -.wan)) ?@(wan (lth +.ort wan) (lth +.ort -.wan)) - =+ ^= hel + =+ ^= hel :: build parser map =+ hel=`(tree $_(?>(?=(^ leh) i.leh)))`~ |- ^+ hel ?~ leh @@ -5849,25 +5859,25 @@ :: :::::::::::::::::::::::::::::::::::::::::::::::::::::: :: section 2fA, miscellaneous funs :: :: :: -++ bull +++ bull :: make %bull type |= [bid=twin der=type] ^- type ?:(|(=(%void der) =(%void s.bid)) %void [%bull bid der]) :: -++ cain |=(vax=vase (sell vax)) -++ cell +++ cain |=(vax=vase (sell vax)) :: $+(vase tank) for #> +++ cell :: make %cell type ~/ %cell |= [hed=type tal=type] ^- type ?:(=(%void hed) %void ?:(=(%void tal) %void [%cell hed tal])) :: -++ core +++ core :: make %core type ~/ %core |= [pac=type con=coil] ^- type ?:(=(%void pac) %void [%core pac con]) :: -++ cube +++ cube :: make %cube type ~/ %cube |= [dil=* goq=type] ^- type @@ -5875,7 +5885,7 @@ %void [%cube dil goq] :: -++ face +++ face :: make %face type ~/ %face |= [cog=term der=type] ^- type @@ -5883,8 +5893,8 @@ %void [%face cog der] :: -++ bool ^-(type [%fork [%cube 0 %atom %f] [%cube 1 %atom %f]]) -++ flay +++ bool ^-(type [%fork [%cube 0 %atom %f] [%cube 1 %atom %f]]) :: -:!>(*?) +++ flay ~/ %flay |= pok=port ^- [p=axis q=type] @@ -5912,7 +5922,7 @@ | [p.pok [p.q.pok q.q.pok]] == :: -++ fork +++ fork :: make %fork type ~/ %fork |= [hoz=type bur=type] ^- type @@ -5924,14 +5934,14 @@ hoz [%fork hoz bur] :: -++ cove +++ cove :: extract [0 *] axis |= nug=nock ?- nug [0 *] p.nug [10 *] $(nug q.nug) * ~|([%cove nug] !!) == -++ comb +++ comb :: combine two formulas ~/ %comb |= [mal=nock buz=nock] ^- nock @@ -5945,9 +5955,9 @@ [%8 p.mal buz] ?: =([0 1] buz) mal - [%7 mal buz] + [%7 mal buz] :: informative default :: -++ cond +++ cond :: ?: compile ~/ %cond |= [pex=nock yom=nock woq=nock] ^- nock @@ -5957,7 +5967,7 @@ * [%6 pex yom woq] == :: -++ cons +++ cons :: make formula cell ~/ %cons |= [vur=nock sed=nock] ^- nock @@ -5969,7 +5979,7 @@ [%1 p.vur p.sed] [vur sed] :: -++ fitz +++ fitz :: odor compatibility ~/ %fitz |= [yaz=term wix=term] =+ ^= fiz @@ -5994,7 +6004,7 @@ == == :: -++ flan +++ flan :: loobean & ~/ %flan |= [bos=nock nif=nock] ^- nock @@ -6009,12 +6019,12 @@ == == :: -++ flip +++ flip :: loobean negation ~/ %flip |= [dyr=nock] [%6 dyr [%1 1] [%1 0]] :: -++ flor +++ flor :: loobean | ~/ %flor |= [bos=nock nif=nock] ^- nock @@ -6050,7 +6060,7 @@ == ?>(?=([* ~] zet) q.i.zet) :: -++ hoax +++ hoax :: invert ++hoof |= a=@ta ?> =(%ho (end 3 2 a)) %+ add @@ -6059,7 +6069,7 @@ =+ b=(cut 3 [2 1] a) ?+(b !! %o 0, %i 1, %u 2, %e 3, %a 4, %y 5, %w 6, %l 7) :: -++ hoof +++ hoof :: hash of some kind? |= a=@ ^- @ta (rap 3 'h' 'o' (snag (div a 26) "oiueaywl") (add 'a' (mod (add a 13) 26)) ~) :: @@ -6111,49 +6121,49 @@ $(axe (peg axe 7), dab r.dab) == :: -++ make +++ make :: compile cord to nock |= txt=@ q:(~(mint ut %noun) %noun (ream txt)) :: -++ noah |=(vax=vase (pave vax)) -++ onan |=(vix=vise (seer vix)) -++ rain +++ noah |=(vax=vase (pave vax)) :: $+(vase tape) for #< +++ onan |=(vix=vise (seer vix)) :: $+(vise vase) for !> +++ rain :: parse with % path |= [bon=path txt=@] ^- twig =+ vaz=vast ~| bon (scan (trip txt) (full (ifix [gay gay] tall:vaz(wer bon)))) :: -++ ream +++ ream :: parse cord to twig |= txt=@ ^- twig (rash txt vest) :: -++ reck +++ reck :: parse hoon file |= bon=path (rain bon ((hard ,@t) .^(%cx (weld bon `path`[%hoon ~])))) :: -++ seed +++ seed :: hoon/hoon core vase ^- vase ~+ !;(*type ..seed) :: -++ seem |=(toy=typo `type`toy) -++ seer |=(vix=vise `vase`vix) -++ sell +++ seem |=(toy=typo `type`toy) :: promote typo +++ seer |=(vix=vise `vase`vix) :: promote vise +++ sell :: tank pretty-print |= vax=vase ^- tank ~| %sell (dish:ut ~(dole ut p.vax) q.vax) :: -++ pave +++ pave :: tape pretty-print |= vax=vase ^- tape ~(ram re (sell vax)) :: -++ loot +++ loot :: cord pretty-print |= vax=vase ^- @ta (rap 3 (pave vax)) :: -++ slam +++ slam :: slam a gate |= [gat=vase sam=vase] ^- vase =+ :- ^= typ ^- type [%cell p.gat p.sam] @@ -6162,34 +6172,34 @@ =+ gun=(~(mint ut typ) %noun gen) [p.gun .*([q.gat q.sam] q.gun)] :: -++ slim +++ slim :: identical to seer? |= old=vise ^- vase old :: -++ slit +++ slit :: type of slam |= [gat=type sam=type] ?> (~(nest ut (~(peek ut gat) %free 6)) & sam) (~(play ut [%cell gat sam]) [%cncl [~ 2] [~ 3]]) :: -++ slym +++ slym :: slam w/o sample-type |= [gat=vase sam=*] ^- vase (slap gat(+<.q sam) [%cnzy %$]) :: ++ slap - |= [vax=vase gen=twig] ^- vase + |= [vax=vase gen=twig] ^- vase :: untyped vase .* =+ gun=(~(mint ut p.vax) %noun gen) [p.gun .*(q.vax q.gun)] :: -++ slop +++ slop :: cons two vases |= [hed=vase tal=vase] ^- vase [[%cell p.hed p.tal] [q.hed q.tal]] :: -++ skol +++ skol :: $+(type tank) for ~! |= typ=type ^- tank ~(duck ut typ) :: -++ spat |=(pax=path (rap 3 (spud pax))) +++ spat |=(pax=path (rap 3 (spud pax))) :: path to cord ++ spec :: reconstruct type |= vax=vase ^- vase @@ -6201,8 +6211,8 @@ [%wtgr [%wtts [%leaf %tas -.q.vax] [%$ 2]~] [%$ 1]] (~(fuse ut p.vax) [%cell %noun %noun]) :: -++ spud |=(pax=path ~(ram re (dish:ut [~ %path] pax))) -++ slew +++ spud |=(pax=path ~(ram re (dish:ut [~ %path] pax))) :: path to tape +++ slew :: get axis in vase |= [axe=@ vax=vase] ^- (unit vase) ?. |- ^- ? ?: =(1 axe) & @@ -6211,11 +6221,11 @@ ~ `[(~(peek ut p.vax) %free axe) .*(q.vax [0 axe])] :: -++ slab +++ slab |= [cog=@tas typ=type] !=(~ q:(~(fino ut typ) 0 %free cog)) :: -++ sloe +++ sloe :: get arms in core |= typ=type ^- (list term) ?+ typ ~ @@ -6223,7 +6233,7 @@ [%core *] (turn (~(tap by q.r.q.typ) ~) |=([a=term *] a)) == -++ slot +++ slot :: got axis in vase |= [axe=@ vax=vase] ^- vase [(~(peek ut p.vax) %free axe) .*(q.vax [0 axe])] :: @@ -6237,11 +6247,11 @@ [* * *] $(wad [n.wad ~ r.wad], vax $(wad l.wad)) == :: -++ stab +++ stab :: parse cord to path |= zep=@ta ^- path (need (rush zep ;~(pfix fas ;~(sfix (more fas urs:ab) fas)))) :: -++ wash +++ wash :: render tank at width |= [[tab=@ edg=@] tac=tank] ^- wall (~(win re tac) tab edg) :::::::::::::::::::::::::::::::::::::::::::::::::::::::::: @@ -8065,7 +8075,10 @@ ~/ %nest |= [tel=? ref=type] ^- ? - =+ gil=*(set ,[p=type q=type]) + =| $: gem=(set ,[p=type q=type]) :: prune ref + gul=(set ,[p=type q=type]) :: assume match + meg=(set ,[p=type q=type]) :: prune sut + == =< dext |% ++ cong @@ -8081,9 +8094,9 @@ ?& ?|(=(p.q.sut p.q.ref) =(%gold p.q.ref)) :: - ?| (~(has in gil) [sut ref]) + ?| (~(has in gul) [sut ref]) %+ %= cram - gil (~(put in gil) [sut ref]) + gul (~(put in gul) [sut ref]) sut sut(p q.q.sut) ref ref(p q.q.ref) == @@ -8134,18 +8147,13 @@ == == :: - ++ dext + ++ dare + ?& !(~(has in meg) [sut ref]) + dext(tel |, meg (~(put in meg) [sut ref])) + == + :: + ++ dear ^- ? - =- ?: tyn - & - ?: tel - :: ~_ (dunk %need) - :: ~_ (dunk(sut ref) %have) - ~|(%type-fail !!) - | - ^= tyn - ?: =(sut ref) - & ?- sut %void sint %noun & @@ -8181,13 +8189,27 @@ [%fork *] ?. ?=(?([%atom *] %noun [%cell *] [%cube *] [%core *]) ref) sint - ?|(dext(tel |, sut p.sut) dext(tel |, sut q.sut)) + |(dare(sut p.sut) dare(sut q.sut)) :: - [%hold *] - ?| - (~(has in gil) [sut ref]) - dext(gil (~(put in gil) [sut ref]), sut repo) - == + [%hold *] dext(sut repo) + == + :: + ++ dext + ^- ? + =- ?: tyn + & + ?: tel + :: ~_ (dunk %need) + :: ~_ (dunk(sut ref) %have) + ~|(%type-fail !!) + | + ^= tyn + ?: =(sut ref) & + dear + :: + ++ sext + ?| (~(has in gem) [sut ref]) + dext(gem (~(put in gem) [sut ref])) == :: ++ sint @@ -8195,13 +8217,8 @@ ?- ref [%atom *] | [%cell *] | - [%fork *] ?&(dext(ref p.ref) dext(ref q.ref)) - [%hold *] - ?| - (~(has in gil) [sut ref]) - dext(gil (~(put in gil) [sut ref]), ref repo(sut ref)) - == - :: + [%fork *] &(sext(ref p.ref) sext(ref q.ref)) + [%hold *] dext(ref repo(sut ref)) %noun | %void & * dext(ref repo(sut ref)) @@ -9067,7 +9084,7 @@ ++ exqd |.(lobe) ++ exqe |.(;~(gunk sym loaf)) -- - ++ norm + ++ norm :: rune regular form |= tol=? =< %- stew ^. stet ^. limo @@ -9226,7 +9243,7 @@ == == |% - ++ boog + ++ boog :: core arms %+ knee [p=*term q=*foot] |. ~+ ;~ pfix lus ;~ pose @@ -9255,31 +9272,33 @@ == == :: - ++ wisp + ++ wisp :: core tail %- ulva %+ cook |=(a=(list ,[p=term q=foot]) (~(gas by *(map term foot)) a)) (most muck boog) :: - ++ toad + ++ toad :: untrap parser exp |* har=_expa =+ dur=(ifix [pel per] $:har(tol |)) ?:(tol ;~(pose ;~(pfix gap $:har(tol &)) dur) dur) :: - ++ rune + ++ rune :: build rune |* [dif=_rule tuq=* har=_expa] ;~(pfix dif (stag tuq (toad har))) :: - ++ glop ~+((glue mash)) - ++ gunk ~+((glue muck)) - ++ butt |*(zor=_rule ?:(tol ;~(sfix zor ;~(plug gap duz)) zor)) - ++ ulva |*(zor=_rule ?.(tol fail ;~(sfix zor ;~(plug gap dun)))) - ++ hank (most muck loaf) - ++ loaf ?:(tol tall wide) - ++ lobe ?:(tol howl toil) - ++ mash ?:(tol gap ;~(plug com ace)) - ++ muck ?:(tol gap ace) - ++ teak %+ knee *tiki |. ~+ + ++ glop ~+((glue mash)) :: separated by space + ++ gunk ~+((glue muck)) :: separated list + ++ butt |* zor=_rule :: closing == if tall + ?:(tol ;~(sfix zor ;~(plug gap duz)) zor) + ++ ulva |* zor=_rule :: closing -- and tall + ?.(tol fail ;~(sfix zor ;~(plug gap dun))) + ++ hank (most muck loaf) :: gapped twigs + ++ loaf ?:(tol tall wide) :: hoon, current width + ++ lobe ?:(tol howl toil) :: tile form + ++ mash ?:(tol gap ;~(plug com ace)) :: list separator + ++ muck ?:(tol gap ace) :: general separator + ++ teak %+ knee *tiki |. ~+ :: wing or twig =+ ^= gub |= [a=term b=$%([& p=wing] [| p=twig])] ^- tiki @@ -9310,50 +9329,54 @@ :: (stag %| (stag ~ tall)) == - ++ race (most mash ;~(gunk lobe loaf)) - ++ rack (most mash ;~(gunk loaf loaf)) - ++ rick (most mash ;~(gunk rope loaf)) - ++ expa |.(loaf) - ++ expb |.(;~(gunk loaf loaf)) - ++ expc |.(;~(gunk loaf loaf loaf)) - ++ expd |.(;~(gunk loaf loaf loaf loaf)) - ++ expe |.(wisp) - ++ expf |.(;~(gunk teak loaf loaf)) - ++ expg |.(;~(gunk sym loaf)) - ++ exph |.((butt ;~(gunk rope rick))) - ++ expi |.((butt ;~(gunk loaf hank))) - ++ expj |.(;~(gunk sym rope loaf)) - ++ expk |.(;~(gunk loaf ;~(plug loaf (easy ~)))) - ++ expm |.((butt ;~(gunk rope loaf rick))) - ++ expn |.((stag %cltr (butt hank))) - ++ expo |.(;~(gunk lobe loaf)) - ++ expp |.(;~(gunk (butt rick) loaf)) - ++ expq |.(;~(gunk rope loaf loaf)) - ++ expr |.(;~(gunk loaf wisp)) - ++ exps |.((butt hank)) - ++ expt |.((butt ;~(gunk loaf race))) - ++ expu |.(;~(gunk lobe wisp)) - ++ expv |.(lobe) - ++ expw |.(;~(gunk lobe rope)) - ++ expx |.((butt ;~(gunk teak race))) - ++ expy |.((butt ;~(gunk teak loaf race))) - ++ expz |.(loaf(bug &)) - ++ hina |.(;~(gunk (ifix [sel ser] ;~(gunk dem dem)) loaf)) - ++ hinb |.(;~(gunk bont loaf)) - ++ hinc |.(;~(pose ;~(gunk bony loaf) ;~(plug (easy ~) loaf))) - ++ hind |.(;~(gunk bonk loaf bonz loaf)) - ++ hine |.(;~(gunk bonk loaf)) - ++ hinf |. + ++ race (most mash ;~(gunk lobe loaf)) :: list [tile twig] + ++ rack (most mash ;~(gunk loaf loaf)) :: list [twig twig] + ++ rick (most mash ;~(gunk rope loaf)) :: list [wing twig] + :: Rune contents + ++ expa |.(loaf) :: one twig + ++ expb |.(;~(gunk loaf loaf)) :: two twigs + ++ expc |.(;~(gunk loaf loaf loaf)) :: three twigs + ++ expd |.(;~(gunk loaf loaf loaf loaf)) :: four twigs + ++ expe |.(wisp) :: core tail + ++ expf |.(;~(gunk teak loaf loaf)) :: tiki and two twigs + ++ expg |.(;~(gunk sym loaf)) :: term and twig + ++ exph |.((butt ;~(gunk rope rick))) :: wing, [tile twig]s + ++ expi |.((butt ;~(gunk loaf hank))) :: one or more twigs + ++ expj |.(;~(gunk sym rope loaf)) :: term, wing, and twig + ++ expk |.(;~(gunk loaf ;~(plug loaf (easy ~)))) :: list of two twigs + ++ expm |.((butt ;~(gunk rope loaf rick))) :: several [tile twig]s + ++ expn |.((stag %cltr (butt hank))) :: autoconsed twigs + ++ expo |.(;~(gunk lobe loaf)) :: tile and twig + ++ expp |.(;~(gunk (butt rick) loaf)) :: [wing twig]s, twig + ++ expq |.(;~(gunk rope loaf loaf)) :: wing and two twigs + ++ expr |.(;~(gunk loaf wisp)) :: twig and core tail + ++ exps |.((butt hank)) :: closed gapped twigs + ++ expt |.((butt ;~(gunk loaf race))) :: twig, [tile twig]s + ++ expu |.(;~(gunk lobe wisp)) :: tile, core tail + ++ expv |.(lobe) :: tile + ++ expw |.(;~(gunk lobe rope)) :: tile and wing + ++ expx |.((butt ;~(gunk teak race))) :: tiki, [tile twig]s + ++ expy |.((butt ;~(gunk teak loaf race))) :: tiki twig [tile twig]s + ++ expz |.(loaf(bug &)) :: twig with tracing + :: Hint syntaces (nock 10) + ++ hina |. :: unused + ;~(gunk (ifix [sel ser] ;~(gunk dem dem)) loaf) + ++ hinb |.(;~(gunk bont loaf)) :: hint and twig + ++ hinc |. :: optional =en, twig + ;~(pose ;~(gunk bony loaf) ;~(plug (easy ~) loaf)) + ++ hind |.(;~(gunk bonk loaf bonz loaf)) :: jet twig "bon"s twig + ++ hine |.(;~(gunk bonk loaf)) :: jet-hint and twig + ++ hinf |. :: 0-3 >s, two twigs ;~ pose ;~(gunk (cook lent (stun [1 3] gar)) loaf loaf) (stag 0 ;~(gunk loaf loaf)) == - ++ hing |. + ++ hing |. :: 0-3 >s, three twigs ;~ pose ;~(gunk (cook lent (stun [1 3] gar)) loaf loaf loaf) (stag 0 ;~(gunk loaf loaf loaf)) == - ++ bonk + ++ bonk :: jet signature ;~ pfix cen ;~ pose ;~(plug sym ;~(pfix col ;~(plug sym ;~(pfix dot ;~(pfix dot dem))))) @@ -9362,7 +9385,7 @@ sym == == - ++ hinh |. + ++ hinh |. :: 1/2 numbers, twig ;~ gunk ;~ pose dem @@ -9370,12 +9393,12 @@ == loaf == - ++ bont ;~ (bend) + ++ bont ;~ (bend) :: term, optional twig ;~(pfix cen sym) ;~(pfix dot ;~(pose wide ;~(pfix muck loaf))) == - ++ bony (cook |=(a=(list) (lent a)) (plus tis)) - ++ bonz + ++ bony (cook |=(a=(list) (lent a)) (plus tis)) :: base 1 =en count + ++ bonz :: term-labelled twigs ;~ pose (cold ~ sig) %+ ifix @@ -9423,14 +9446,14 @@ :: ++ lobo (most ;~(plug com ace) ;~(glam rope wide)) ++ loon (most ;~(plug com ace) ;~(glam wide wide)) - ++ lute + ++ lute :: tall [] noun ~+ %+ stag %cltr %+ ifix [;~(plug sel gap) ;~(plug gap ser)] (most gap tall) :: - ++ rope + ++ rope :: wing form %+ knee *wing |. ~+ %+ (slug `wing`~ |=([a=wing b=wing] (weld a b))) @@ -9453,9 +9476,10 @@ == == :: - ++ tall %+ knee *twig + ++ tall %+ knee *twig :: full tall form |.(~+((wart ;~(pose (norm &) long lute ape:(sail &))))) - ++ wide (knee *twig |.(~+((wart ;~(pose (norm |) long ape:(sail |)))))) + ++ wide %+ knee *twig :: full wide form + |.(~+((wart ;~(pose (norm |) long ape:(sail |))))) ++ hill (knee *tile |.(~+(;~(pose (noil |) toil)))) ++ howl (knee *tile |.(~+(;~(pose (noil &) toil)))) ++ toil diff --git a/arvo/test.hoon b/arvo/test.hoon index b81e36679..a632f70f6 100644 --- a/arvo/test.hoon +++ b/arvo/test.hoon @@ -1,165 +1,24 @@ -!::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::: -:::::: :::::: Preface :::::: -:::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::: -?> ?=(@ .) :: atom subject -%. . :: fun with subject -|= cud=@ :: call it cud -=- (mul:all 2 cud) :: multiply by 2 -^= all :: assemble engine - =~ :: volume stack -%164 :: version constant -:::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::: -:::::: :::::: volume 0, version stub :::::: -:::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::: -~% %k.164 ~ ~ :: -|% :: -++ stub 164 :: version stub --- :: -:::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::: -:::::: :::::: volume 1, Hoon models :::::: -:::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::: -~% %mood - + - ~ -|% :: -++ axis ,@ :: tree address --- :: -:::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::: -:::::: :::::: volume 2, Hoon libraries and compiler :::::: -:::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::: -~% %hoon - + - == - %dec dec - == +?> ?=([@ @] .) +%. . +|= [x=@ y=@] +=- (add:all x y) +^= all +=> %164 +~% %k.164 ~ ~ |% - ::::::::::::::::::::::::::::::::::::::::::::::::::::: :: -:::: chapter 2a, basic unsigned math :::: -:: :::::::::::::::::::::::::::::::::::::::::::::::::::::: -++ add :: add +++ add ~/ %add |= [a=@ b=@] ^- @ - ?: =(0 a) - b + ?: =(0 a) b $(a (dec a), b +(b)) :: -++ cap :: tree head - ~/ %cap - |= a=@ - ^- ?(%2 %3) - ?- a - %2 %2 - %3 %3 - ?(%0 %1) !! - * $(a (div a 2)) - == -:: -++ dec :: decrement +++ dec ~/ %dec |= a=@ ?< =(0 a) =+ b=0 |- ^- @ - ?: =(a +(b)) - b + ?: =(a +(b)) b $(b +(b)) -:: -++ div :: divide - ~/ %div - |= [a=@ b=@] - ^- @ - ?< =(0 b) - =+ c=0 - |- - ?: (lth a b) - c - $(a (sub a b), c +(c)) -:: -++ gte :: greater-equal - ~/ %gte - |= [a=@ b=@] - ^- ? - !(lth a b) -:: -++ gth :: greater-than - ~/ %gth - |= [a=@ b=@] - ^- ? - !(lte a b) -:: -++ lte :: less-equal - ~/ %lte - |= [a=@ b=@] - |(=(a b) (lth a b)) -:: -++ lth :: less-than - ~/ %lth - |= [a=@ b=@] - ^- ? - &(!=(a b) |-(|(=(0 a) &(!=(0 b) $(a (dec a), b (dec b)))))) -:: -++ mas :: tree body - ~/ %mas - |= a=@ - ^- @ - ?- a - 1 !! - 2 1 - 3 1 - * (add (mod a 2) (mul $(a (div a 2)) 2)) - == -:: -++ max :: maximum - ~/ %max - |= [a=@ b=@] - ^- @ - ?: (gth a b) - a - b -:: -++ min :: minimum - ~/ %min - |= [a=@ b=@] - ^- @ - ?: (lth a b) - a - b -:: -++ mod :: remainder - ~/ %mod - |= [a=@ b=@] - ^- @ - ?< =(0 b) - (sub a (mul b (div a b))) -:: -++ mul :: multiply - ~/ %mul - |= [a=@ b=@] - ^- @ - =+ c=0 - |- - ?: =(0 a) - c - $(a (dec a), c (add b c)) -:: -++ peg :: tree connect - ~/ %peg - |= [a=@ b=@] - ^- @ - ?- b - 1 a - 2 (mul a 2) - 3 +((mul a 2)) - * (add (mod b 2) (mul $(b (div b 2)) 2)) - == -:: -++ sub :: subtract - ~/ %sub - |= [a=@ b=@] - ^- @ - ?: =(0 b) - a - $(a (dec a), b (dec b)) -- -. == diff --git a/arvo/zuse.hoon b/arvo/zuse.hoon index 6b820328a..ef6151ec5 100644 --- a/arvo/zuse.hoon +++ b/arvo/zuse.hoon @@ -828,13 +828,13 @@ => .(+< [a b]=+<) (scan a (parsf b)) ++ parsf :: make parser from: - |^ |* (pole ,_:/(*$&(_rule tape))) :: ;"chars{rule}chars" - => .(+< a=+<) + |^ |* a=(pole ,_:/(*$&(_rule tape))) :: ;"chars{rule}chars" %- cook :_ (bill (norm a)) |* (list) ?~ +< ~ ?~ t i [i $(+< t)] + :: :: .= (norm [;"{n}, {n}"]:n=dim:ag) ~[[& dim] [| ", "] [& dim]]:ag ++ norm |* (pole ,_:/(*$&(_rule tape))) @@ -847,6 +847,7 @@ ?~ +.rul [%| p=rul] ?@ &2.rul [%| p=;;(tape rul)] [%& p=rul] + :: :: .= (bill ~[[& dim] [| ", "] [& dim]]:ag) :: ;~(plug dim ;~(pfix com ace ;~(plug dim (easy)))):ag ++ bill @@ -1045,7 +1046,7 @@ ^- ankz ^$(p ank) :: -++ ze !: +++ ze |_ [lim=@da dome rang] ++ zoal :: make yaki |= [p=(list tako) q=(map path lobe) t=@da] @@ -1125,6 +1126,24 @@ =+ zoq=(zaru voq) ((diff (zump (zaal u.leb))) zeq zoq) :: + ++ apax :: apax:ze + |= [oan=@ud pax=path] :: data at path + ^- (map path lobe) + ?: =(0 oan) ~ + %- mo + %+ skim + %. ~ + %~ tap by + =< q + %- ~(got by hut) + %- ~(got by hit) + oan + |= [p=path q=lobe] + ?| ?=(~ pax) + ?& !?=(~ p) + =(-.pax -.p) + $(p +.p, pax +.pax) + == == :: ++ aeon :: aeon:ze |= lok=case :: act count through @@ -1220,7 +1239,7 @@ |= lob=lobe (need (~(get by lat) lob)) :: - ++ gack !: :: gack a through b + ++ gack :: gack a through b |= [a=@ud b=@ud] ^- [(map ,@ud tako) @ud (set yaki) (set blob)] :_ :- b @@ -1250,7 +1269,7 @@ ^+ +> ?: =(let oan) +> ?: (gth oan let) !! :: don't have this version - +>(ank (azel q:(need (~(get by hut) (need (~(get by hit) oan))))), let oan) + +>(ank (azel q:(~(got by hut) (~(got by hit) oan))), let oan) :: :::: ++ aqel :: aqel:ze @@ -1309,8 +1328,9 @@ |= [[pat=path bar=lobe] ank=ankh] ^- ankh %- cosh - =+ zar=(zaul bar) - ?~ pat [_cash [~ [(sham zar) zar]] `(map ,@ta ankh)`~] + ?~ pat + =+ zar=(zaul bar) + ank(q [~ (sham zar) zar]) =+ nak=(~(get by r.ank) i.pat) %= ank r %+ ~(put by r.ank) i.pat @@ -1355,7 +1375,7 @@ $(gud (~(put in gud) tek), unk bun) $(unk bun) :: - ++ zeas !: :: merge points fast + ++ zeas :: merge points fast |= [p=yaki q=yaki] :: (future zeal) ^- (set yaki) :: zear still uses zule %- zear :: this is test-only @@ -1373,13 +1393,13 @@ (~(uni in u) (zeaz v)) $(u (~(uni in u) (zeaz v)), s (zeat s.qez), t (zeat t.qez)) :: - ++ zeaz !: + ++ zeaz |= qez=(set tako) ^- (set yaki) %- sa %+ turn (~(tap in qez) ~) |= tak=tako (~(got by hut) tak) - ++ zeat !: :: expand set + ++ zeat :: expand set |= qez=(set tako) ^- (set tako) %+ roll (~(tap in qez) ~) @@ -1839,7 +1859,7 @@ +>(ank ank:(durn:(zu ank) nyp)) -- :: -++ zu !: :: filesystem +++ zu :: filesystem |= ank=ankh :: filesystem state =| myz=(list ,[p=path q=miso]) :: changes in reverse =| ram=path :: reverse path into @@ -3047,7 +3067,7 @@ == :: ++ mizu ,[p=@u q=(map ,@ud tako) r=rang] :: new state ++ moar ,[p=@ud q=@ud] :: normal change range -++ moat ,[p=case q=case] :: change range +++ moat ,[p=case q=case r=path] :: change range ++ mood ,[p=care q=case r=path] :: request in desk ++ moth ,[p=meth q=math r=(unit octs)] :: http operation ++ name ,[p=@t q=(unit ,@t) r=(unit ,@t) s=@t] :: first mid/nick last diff --git a/main/app/a-twit/core.hook b/main/app/a-twit/core.hook index 895ad13f0..a15086322 100644 --- a/main/app/a-twit/core.hook +++ b/main/app/a-twit/core.hook @@ -87,7 +87,7 @@ == == ++ pour - |= [way=path sih=sign] + |= [ost=bone way=path sih=sign] ^- [(list move) _+>] :_ +>.$ %+ turn (~(tap in (~(get ju pus.hid) ~))) diff --git a/main/app/chat/core.hook b/main/app/chat/core.hook index 203510b2b..7ad80c241 100644 --- a/main/app/chat/core.hook +++ b/main/app/chat/core.hook @@ -130,7 +130,7 @@ == :: ++ pour - |= [pax=path sih=*] + |= [ost=bone pax=path sih=*] ^- [(list move) _+>] =+ sih=((hard sign) sih) :: ~& [%chat-pour sih] diff --git a/main/app/test/app.js b/main/app/test/app.js new file mode 100644 index 000000000..5053f04e4 --- /dev/null +++ b/main/app/test/app.js @@ -0,0 +1,73 @@ +$(function() { + $tests = $("#tests") + + runtest = function(name) { + test = $(name) + test.attr('disabled', true) + test.addClass('disabled') + + window.urb.send({ + appl:"test", + data:{test:name} + }, function(err,res) { + test.attr('disabled', false) + test.removeClass('disabled') + + _test = { + name: name, + result: res.data + } + + console.log('set it') + console.log(_test) + + $tests.prepend(renderTest(_test)) + }) + } + + renderTest = function(test) { + css = "test" + if(test.pending == true) + css += " pending" + $_test = $("
") + $_test.append("
"+test.name+"
") + $_test.append("
"+JSON.stringify(test.result)+"
") + return $_test + } + + renderTests = function(testlist) { + console.log("renderTests: "+testlist) + $tests.html("") + for(i in testlist) { + $tests.append(renderTest(testlist[i])) + } + } + + renderError = function(error) { + $tests.html("
Sorry! There was an error fetching from Test: "+error+"
") + } + + window.urb.subscribe({ + appl:"test", + path:"/tests" + }, function(err,res) { + console.log('subscr') + console.log(arguments) + if (res.data.ok) + return + if(err) + renderTests(err) + else + { + if(res.data) { + if(res.data) { + renderTests(res.data) + } + else + { + renderTests("unknown error") + } + } + } + }) +}) diff --git a/main/app/test/core.hook b/main/app/test/core.hook new file mode 100644 index 000000000..eaf7c9f21 --- /dev/null +++ b/main/app/test/core.hook @@ -0,0 +1,237 @@ +:: Test suite +:: +:: runnable from unix with command: +:: curl http://localhost:8080/gog/test/all-tests +:: +:::: /hook/core/test/app + :: +/? 314 :: need urbit 314 +/= front /:/%%/front:/hymn/ :: load front page +:: +:::: structures + :: +|% :: structures + ++ axle ,[%0 tests=(map term test)] :: application state + ++ gilt :: subscription frame + $% [%json p=json] :: json data + [%html p=@t] :: html text + [%hymn p=manx] :: html tree + [%mime p=mite q=octs] :: mime data + == :: + ++ gift :: output action + $% [%rust gilt] :: total update + [%mean p=ares] :: message failure + [%nice ~] :: succeed + == :: + ++ hasp ,[p=ship q=term] :: see %gall + ++ move ,[p=bone q=(mold note gift)] :: output operation + ++ result :: test result + $% [%mean p=ares] :: failure + [%nice ~] :: success + == :: + ++ note :: system request + $% $: %g :: to %ames + $% [%mess p=hasp q=ship r=cage] :: + == == == :: + ++ test :: test template + $_ ^? |% :: + ++ poke |+([bone ship] [_(list move) +>]) :: start test + ++ pour |+([bone path *] [_(list move) +>]) :: system response + -- :: +-- :: +!: +:::: program + :: +|_ $: hid=hide :: system state + axle :: custom state + == +++ et :: tests + |% + ++ tests-json + %- jobe + %+ turn (~(tap by tests)) + |= [nam=@t tes=test] + :- nam + %- jobe + ^- (list ,[@t json]) + ~[[%name %s nam] [%result %s %untested]] + ++ succeed + ^- test + |% + ++ poke + |+ [ost=bone you=ship] + ^- [(list move) _+>] + [[ost %give %nice ~]~ +>.$] + ++ pour + |+ [ost=bone pax=path sih=*] + ^- [(list move) _+>] + !! + -- + ++ poke-local + ^- test + => |% + ++ sign ,[%g result] + -- + |% + ++ poke + |+ [ost=bone you=ship] + ^- [(list move) _+>] + :_ +>.$ :_ ~ + :* ost %pass /poke-local %g + %mess [our.hid %test] you %json + !> (joba %test %s %bad-test-name) + == + ++ pour + |+ [ost=bone pax=path sih=*] + ^- [(list move) _+>] + :_ +>.$ + =+ sih=((soft sign) sih) + :_ ~ :+ ost %give + ?~ sih [%mean ~ %poke-local-pour-bad-sign ~] + ?- +<.u.sih + %nice [%mean ~ %poke-local-pour-unexpected-nice ~] + %mean + ?: ?=([~ %bad-test ~] p.u.sih) + [%nice ~] + [%mean ~ %poke-local-pour-unexpected-mean ~] + == + -- + ++ ze + ^- test + |% + ++ poke + |+ [ost=bone you=ship] + ^- [(list move) _+>] + :_ +>.$ :_ ~ + =+ ^= zez + %+ ~(axel ^ze lat.hid *dome *rang) + lat.hid + [%& [0v0 0v0] [/hello %ins 'hello, world']~] + =+ `[l=@da d=dome r=rang]`+<.zez + ?: .= lat.r + :_ [~ ~] + [p=1.292.805.149 q=[%direct p=1.292.805.149 q='hello, world' r=%c]] + [ost %give %nice ~] + [ost %give %mean ~ %bad-rang ~[leaf/ leaf/]] + ++ pour + |+ [ost=bone pax=path sih=*] + ^- [(list move) _+>] + !! + -- + ++ all-tests + ^- test + => |% + ++ sign ,[%g result] + ++ sult + $? result + [%pending ~] + == + -- + =| results=(map ,@t sult) + |% + ++ poke + |+ [ost=bone you=ship] + ^- [(list move) _+>] + =. results + %- mo + %+ turn (~(tap by tests)) + |= [nam=@t tes=test] + [nam %pending ~] + :_ +>.$ + %+ turn (~(tap by tests)) + |= [nam=@t tes=test] + :* ost %pass /all-tests/[nam] %g + %mess [our.hid %test] you %json + !> (joba %test %s nam) + == + ++ pour + |+ [ost=bone pax=path sih=*] + ^- [(list move) _+>] + =+ sih=((hard sign) sih) + ?. ?=([@ ~] pax) ~& [%all-tests-strange-path pax] [~ +>.$] + =. results (~(put by results) -.pax +.sih) + :_ +>.$ + ?: (~(any by results) |=([res=sult] ?=(%pending -.res))) + ~ + :_ ~ + ?: (~(all by results) |=([res=sult] ?=(%nice -.res))) + [ost %give %nice ~] + :^ ost %give %mean + :+ ~ %failed-tests + %- zing + %+ turn + (skim (~(tap by results)) |=([nam=@t res=sult] ?=(%mean -.res))) + |= [nam=@t res=sult] + ?> ?=(%mean -.res) + ^- (list tank) + :_ ?~ p.res ~ q.u.p.res + :- %leaf + %+ weld "test %{(trip nam)} failed with " + ?~ p.res "no error message" + %+ weld "error code %{(trip p.u.p.res)} and " + ?~ q.u.p.res "no error info" + "the following error info:" + -- + -- +++ spec-pour + |= [ost=bone pax=path sih=*] + ^- [(list move) _+>] + =+ sih=((hard ,[%g result]) sih) + :_ +>.$ :_ ~ + [ost %give %rust %mime /text/plain (taco (cat 3 (crip ) 10))] +++ prep + |= old=(unit (unit axle)) + ^- [(list move) _+>] + :- ~ + %= +>.$ + tests + ?~ old + ~& %prep-sig tests + ?^ u.old + ~& %prep-no-sig tests.u.u.old + =. tests + %- mo + ^- (list ,[@t test]) + => et + :~ [%succeed succeed] + [%ze ze] + [%poke-local poke-local] + == + (~(put by tests) %all-tests all-tests:et) + == +++ peer :: accept subscriber + |= [ost=bone you=ship pax=path] + ^- [(list move) _+>] + ?~ pax [[ost %give %rust %hymn front]~ +>.$] + ?: ?=(%tests -.pax) + [[ost %give %rust %json tests-json:et]~ +>.$] + :_ +>.$ :_ ~ + :* ost %pass /automagic %g + %mess [our.hid %test] you %json + !> (joba %test %s -.pax) + == +++ poke-json :: browser message + |= [ost=bone you=ship jon=json] + ^- [(list move) _+>] + =+ tes=((of [%test so] ~):jo jon) + ?~ tes [[ost %give %mean ~ %strange-json ~]~ +>.$] + =+ tst=(~(get by tests) +.u.tes) + ?~ tst + [[ost %give %mean ~ %bad-test ~]~ +>.$] + ~& [%running-test +.u.tes] + =+ res=(poke:u.tst ost you) + :- -.res + +>.$(tests (~(put by tests) +.u.tes +.res)) +++ pour :: response + |= [ost=bone pax=path sih=*] + ^- [(list move) _+>] + ?~ pax ~& %test-strange-path [~ +>.$] + =+ tst=(~(get by tests) -.pax) + ?: ?=(%automagic -.pax) + (spec-pour ost pax sih) + ?~ tst + ~& %test-bad-path [~ +>.$] + =+ res=(pour:u.tst ost +.pax sih) + :- -.res + +>.$(tests (~(put by tests) -.pax +.res)) +-- diff --git a/main/app/test/front/hymn.hook b/main/app/test/front/hymn.hook new file mode 100644 index 000000000..8a20718f0 --- /dev/null +++ b/main/app/test/front/hymn.hook @@ -0,0 +1,30 @@ +:: Front page of the twitter app. +:: +:::: /hook/hymn/front/twit/app + :: +/? 314 :: need urbit 314 +/= urbit /:/===/lib/urb:/hymn/ :: urbit library (js) +/= style /:/%%%/style:/hymn/ :: stylesheet (css) +/= application /:/%%%/app:/hymn/ :: application (js) +!: +:::: content + :: +^- manx +;html + ;head + ;title: Tests + ;+ style + ;script + =type "text/javascript" + =src "//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js" + ; + == + == + ;body + ;div#tests + ;p: Fetching tests... + == + ;+ urbit + ;+ application + == +== diff --git a/main/app/test/style.css b/main/app/test/style.css new file mode 100644 index 000000000..224edf8fc --- /dev/null +++ b/main/app/test/style.css @@ -0,0 +1,82 @@ +body, +textarea, +input { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 400; +} + +body { + margin-top: 4rem; + font-size: 18px; +} + +.test, +.name, +.result { + width: 32rem; +} + +textarea { + border: 0; + height: 8rem; + line-height: 1.5rem; + margin-bottom: .3rem; + resize: none; + padding: 1rem 1px; + background-color: #f7f7f7; +} + +.name { + border: 0; + color: #333; + letter-spacing: 0.01rem; +} + +.name { + background-color: transparent; + border: 2px solid #5DE668; + color: #5DE668; + padding: .3rem 1rem; + font-weight: 500; + cursor: pointer; +} + +.name { + background-color: #5DE668; + color: #fff; +} + +.disabled { + opacity: .6; +} + +.text { + word-wrap:break-word; + margin-bottom: .3rem; + line-height: 1.6rem; +} + +#twet { + margin-bottom: 3rem; + border-bottom: 2px solid #464646; + padding-bottom: 2rem; +} + +#twet, +.tweet { + border-bottom: 1px solid #eee; +} + +.tweet { + margin-bottom: 2rem; + padding-bottom: 1rem; +} + +.pending { + opacity: .3; +} + +.error { + color: #FF5F5F; + letter-spacing: .06rem; +} diff --git a/main/app/twit/core.hook b/main/app/twit/core.hook index 1aec19a89..05bcae557 100644 --- a/main/app/twit/core.hook +++ b/main/app/twit/core.hook @@ -100,7 +100,7 @@ == :: ++ pour :: HTTP response - |= [pax=path sih=sign] + |= [ost=bone pax=path sih=sign] ^- [(list move) _+>] :_ +>.$ ?+ -.pax !! diff --git a/main/bin/cat.hoon b/main/bin/cat.hoon index 3ff2f5afb..4ccef2f8d 100644 --- a/main/bin/cat.hoon +++ b/main/bin/cat.hoon @@ -12,11 +12,14 @@ ?~ q.ark ?- r.ark ~ - ~[(crip "No file {(spud pax)}")] + ~[(crip "~ {(spud pax)}")] [[@t ~] ~ ~] $(pax (welp pax /[p.n.r.ark])) * - ~[(crip "Multiple in {(spud pax)}")] + :- (crip "* {(spud pax)}") + %- sort :_ aor + %- turn :_ |=([a=@t ~] a) + (~(tap by `(map ,@t ,~)`r.ark)) == :- (crip (spud pax)) (lore ;;(,@t .^(%cx pax))) diff --git a/main/bin/chat.hoon b/main/bin/chat.hoon index f76d5c4a9..d36286efc 100644 --- a/main/bin/chat.hoon +++ b/main/bin/chat.hoon @@ -15,7 +15,7 @@ [%tower p=@p] [%s p=path] == - =+ flags=*(list flag) + =+ [flags=*(list flag) lat=&3:%] => |% ++ chat :: user action $% [%all p=mess] :: say @@ -63,22 +63,19 @@ == :: ++ dat - %+ cook + %+ sear |= p=coin - ?. ?=(~ -.p) [%ud 5] - ?+ p.p.p [%ud 5] - %da [%da q.p.p] - %dr [%dr q.p.p] - %ud [%ud q.p.p] - == - ;~(pfix (jest '\\\\ ') nuck:so) + ?. ?=([%$ ?(%da %dr %ud) @] p) ~ + (some +.p) + ;~(pfix bas bas (star ace) nuck:so) :: ++ expn %- sear :_ text |= a=@t ^- (unit ,[p=@t q=tank]) - =+ hun=(rush a wide:vast) + ~! % + =+ hun=(rush a wide:(vang | &1:% &2:% lat |3:%)) ?~ hun ~ ?~(a ~ [~ a (sell (slap !>(sed) u.hun))]) :: @@ -273,7 +270,7 @@ |= [now=@da txt=@t] ^+ +> ?: =(0 txt) +> - =+ rey=(rush txt chat) + =+ rey=(rush txt chat(lat (scot da/est))) ?~ rey (show %leaf "invalid input") |- diff --git a/main/bin/tree.hoon b/main/bin/tree.hoon index 6aa5ec791..e8b90aa24 100644 --- a/main/bin/tree.hoon +++ b/main/bin/tree.hoon @@ -10,5 +10,7 @@ =- ?~ q.ark - [(crip (rend pax)) -] %- zing -%+ turn (~(tap by r.ark)) -|=([a=@t ~] ^$(pax (weld pax `path`/[a]))) +%- turn :_ |=(a=@t ^$(pax (weld pax `path`/[a]))) +%- sort :_ aor +%- turn :_ |=([a=@t ~] a) +(~(tap by r.ark)) diff --git a/main/lib/urb.js b/main/lib/urb.js index 6c74b3dcd..3f3679ea5 100644 --- a/main/lib/urb.js +++ b/main/lib/urb.js @@ -1,13 +1,13 @@ window.urb.seqn_s = 0 -window.urb.cabs = {} window.urb.send = function(params,cb) { if(!params) throw new Error("You must supply params to urb.send.") - if(!params.appl) + if(!params.appl) { if(!urb.appl) throw new Error("You must specify an appl for urb.send.") params.appl = urb.appl + } if(!params.data) { params.data = {}; } var method, perm, url, $this @@ -35,10 +35,11 @@ window.urb.subscribe = function(params,cb) { throw new Error("You must supply a callback to urb.subscribe.") if(!params) throw new Error("You must supply params to urb.subscribe.") - if(!params.appl) + if(!params.appl) { if(!urb.appl) throw new Error("You must specify an appl for urb.subscribe.") params.appl = urb.appl + } if(!params.path) throw new Error("You must specify a path for urb.subscribe.") params.ship = params.ship ? params.ship : this.ship @@ -66,10 +67,11 @@ window.urb.subscribe = function(params,cb) { window.urb.unsubscribe = function(params,cb) { if(!params) throw new Error("You must supply params to urb.unsubscribe.") - if(!params.appl) - if(!urb.appl ) + if(!params.appl) { + if(!urb.appl) throw new Error("You must specify an appl for urb.unsubscribe.") params.appl = urb.appl + } if(!params.path) throw new Error("You must specify a path for urb.unsubscribe.") params.ship = params.ship ? params.ship : this.ship diff --git a/main/mar/down/door.hook b/main/mar/down/door.hook index a8dee1da0..e13824fcb 100644 --- a/main/mar/down/door.hook +++ b/main/mar/down/door.hook @@ -10,8 +10,7 @@ ++ grab :: convert from |% ++ md :: convert from %md - |= src=@t - =< (mark (trip src)) + =< |=(src=@t (mark (trip src))) |% ++ mark |= p=tape @@ -23,7 +22,7 @@ =+ sep=(sepa tub) ?~ q.sep [p.sep ~] :- p.sep - %- some :_ [p.sep ~] + %- some :_ [p.sep ~] (turn p.u.q.sep |=(a=tape (scan a blos))) :: ++ base %+ stag %par @@ -39,7 +38,7 @@ code codf html para base == :: - ++ brek (stag %cut (cold ~ ;~(plug fas fas))) :: line break + ++ brek (stag %cut (cold ~ ;~(plug fas fas))) :: line break ++ chrd ;~(pose escp prn (cold ' ' eol)) :: shin character data ++ code :: code block %+ stag %pre @@ -61,7 +60,7 @@ %- plus ;~ pose %+ cook welp - ;~(plug (plus prn) (cold "\0a" eol)) + ;~(plug (star prn) (cold "\0a" eol)) (full (plus ;~(less ;~(plug tec tec tec) prn))) == :: @@ -83,7 +82,7 @@ == ++ spas :: all shin elements |* res=_rule - %- plus + %- plus ;~ pose emph stri link brek cods (text res) == @@ -106,19 +105,7 @@ (ifix [cab cab] (stag %bent inn)) == :: - ++ escp :: escapable chars - ;~ pose - (cold '`' (jest '\\`')) - (cold '*' (jest '\\*')) - (cold '#' (jest '\\#')) - (cold '-' (jest '\\-')) - (cold '.' (jest '\\.')) - (cold '{' (jest '\\{')) - (cold '}' (jest '\\}')) - (cold '[' (jest '\\[')) - (cold ']' (jest '\\]')) - (cold '\\' (jest '\\\\')) - == + ++ escp ;~(pfix bas (mask (trip '`*#-.{}[]\\'))) :: escapable chars :: ++ head :: header %+ stag %had @@ -160,7 +147,7 @@ ;~(plug (stun [0 3] ace) cab wits cab wits cab (star ;~(pose cab ace))) == :: - ++ html (stag %hem apex:xmlp) :: html barb + ++ html (stag %hem apex:xmlp) :: html barb ++ lasd :: top level list %+ stag %lit %- full @@ -212,7 +199,7 @@ == == :: - ++ para (stag %par (full (spas fail))) :: paragraph + ++ para (stag %par (full (spas fail))) :: paragraph ++ quot :: blockquotes %+ stag %quo %- full @@ -234,16 +221,28 @@ ++ sepa :: separate barbs %+ knee *wall |. ~+ =+ lin=;~(plug eol wits eol) + %- full %+ ifix [(star whit) (star whit)] %+ more ;~(plug eol wits (more wits eol)) ;~ pose + sepc (sepl (cold "-" hep)) (sepl (cold "*" tar)) (sepl (cold "+" lus)) (sepl (cook welp ;~(plug (star nud) (cold "." dot)))) - (plus ;~(less lin ;~(pose prn ;~(simu ;~(plug eol prn) eol)))) + (plus ;~(pose prn ;~(less lin eol))) == :: + ++ sepc :: separate code block + =+ tecs=(cold "```" (jest '```')) + %+ cook |=(wall `tape`(zing +<)) + ;~ plug + tecs + (cook zing (star ;~(plug eol ;~(less tecs (star prn))))) + (cold "\0a" eol) + tecs + (easy ~) + == ++ sepl :: separate list |* bus=_rule %+ cook zing @@ -285,14 +284,14 @@ :: ++ grow :: convert into =< |% - ++ hymn :: convert to %hymn + ++ hymn :: convert to %hymn ;html ;head:title:"Untitled" ;body ;* (apex don) == == - ++ psal :: convert to %psal + ++ psal :: convert to %psal ;div ;* (apex don) == diff --git a/main/mar/psal/door.hook b/main/mar/psal/door.hook index f3c9ee033..b5db936a2 100644 --- a/main/mar/psal/door.hook +++ b/main/mar/psal/door.hook @@ -6,7 +6,8 @@ :: ++ grow :: convert to |% - ++ html (crip (xmlt | own ~)) :: convert to %html + ++ hymn ;html(head:title:"Untitled" body:"+{own}") :: convert to %hymn + ++ html (crip (xmlt | hymn ~)) :: convert to %html ++ mime [/text/html (taco html)] :: convert to %mime -- -- diff --git a/main/pub/fab/dirs/hymn.hook b/main/pub/fab/dirs/hymn.hook new file mode 100644 index 000000000..574d50c50 --- /dev/null +++ b/main/pub/fab/dirs/hymn.hook @@ -0,0 +1,41 @@ +:: %clay browser +:: +:::: /hook/hymn/dirs/fab/pub + :: +/= gas /$ fuel +/= rut /$ |= [a=beam path] ^- [p=path q=path] + [(tope a(s ~)) (flop (slag 1 s.a))] +!: +:::: ~pittyp-pittyp + :: +=+ pax=`path`(flop but.gas) +=+ cot=(trip ;;(,@ (fall (file (welp p.rut pax)) ''))) +=+ js=""" + window.location = "/gen/main{}/" + pax.value + """ +;html + ;head:title:"{}" + ;body + ;input#pax(onchange js, value (slag 1 )); + ;+ =+ ups="%" + |- + ?: =(~ pax) ;div:a/"/gen/main{}":"/===" + =: ups "%{ups}" + pax (scag (dec (lent pax)) pax) + == + =+ sul=;;(arch .^(%cy (welp p.rut pax))) + ?: (gte 2 ~(wyt by r.sul)) $ + ;div:a/"/gen/main{}{}":"{ups}" + :: + ;* =+ sub=;;(arch .^(%cy (welp p.rut pax))) + =| don=tape + %+ turn (~(tap by r.sub)) |= [a=span ~] + =: don "{don}/{(trip a)}" + pax (welp pax /[a]) + == + =+ sus=;;(arch .^(%cy (welp p.rut pax))) + ?: =(2 ~(wyt by r.sus)) $(a p.n.-.r.sus) + ;div:a/"/gen/main{}{}":"{(slag 1 don)}" + ;pre:"{cot}" + == +== diff --git a/main/pub/fab/next-site/hymn.hook b/main/pub/fab/next-site/hymn.hook new file mode 100644 index 000000000..ed43cb65b --- /dev/null +++ b/main/pub/fab/next-site/hymn.hook @@ -0,0 +1,114 @@ +:: Documentation website generator. +:: +:::: /hook/hymn/next-site/fab/fub + :: +/= bod /^ manx /: /===/pub/src/doc/say/intro /psal/ +/= sty /^ @t /: /===/pub/fab/site/styles /css/ +/= say /^ (map ,@ (list ,[@u manx])) + /: /===/pub/src/doc/say + /% /@ /hymn/ +/= ref /: /===/pub/src/doc/ref + /. /= vol /; |= vol=(map ,@ manx) + %+ sort (~(tap by vol)) |= [[a=term *] [b=term *]] + =+ [pax=(trip a) paf=(trip b)] + |- + ?~ pax & ?~ paf | + ?: =(i.pax i.paf) $(pax t.pax, paf t.paf) + (lth i.pax i.paf) + /, vol /% /psal/ + :: /= hon /, hoon /% /psal/ + == +/= gas /$ fuel +:: +:::: ~tomsyt-balsen, ~pittyp-pittyp + :: +|% +++ tuts + |= tut=(list ,[term tape]) ^- manx + :- /ol + %+ turn tut |= [a=term b=tape] + ;li:p:a/"/gen/main/pub/fab/next-site/tut/{(trip a)}":"{b}" +++ refs + |= ref=(list ,[term tape tape]) ^- marl + %+ turn ref |= [a=term b=tape c=tape] + ;p:a/"/gen/main/pub/fab/next-site/ref/{(trip a)}":";{strong "{b}"}: {c}" +-- +!: +:::: + :: +;html + ;head + ;title: Urbit: Personal Cloud Computing + ;link/"/gen/main/pub/fab/site/styles.css"(rel "stylesheet"); + == + ;body + ;div(class "content container") + ;+ + =. but.gas (flop but.gas) + =+ ^= pag ^- marl + ?. ?=([@ @ *] but.gas) ~ + =+ ^- paf=(unit ,[nom=@t num=@u]) + %+ rush i.t.but.gas :: XX numbers in path + ;~(plug (cook crip (star alf)) dem) + ?~ paf ~ + ?+ i.but.gas ~ + %tut + =+ dir=(fall (~(get by say) nom.u.paf) ~) + =+ mir=(~(get by (mo dir)) num.u.paf) + ?^ mir [u.mir]~ + (turn dir |=([@ a=manx] a)) + %ref + ?+ nom.u.paf ~ :: XX foreword, preface + %vol + %+ murn vol.ref |= [a=term b=manx] + ?. =((end 3 1 a) (scot ud/num.u.paf)) ~ + (some b) + == + == + ?^ pag + ;div.subpage + ;* pag + == + ;div(class "page documentation") + ;+ bod + ;h1(class "page-title"): Documentation + ;p ; This documentation is a work in progress. Feedback and corrections + ; are welcome. Pull requests are encouraged. The repo for this site + ; lives ;{a(href "https://github.com/urbit/urbit.github.io") "here"}. + == + ;ul + ;li + ;p:(h2:"Tutorial") + ;p:(a/"/gen/main/pub/fab/site/tut/setup":"Setup") + ;strong: Nock + ;+ %- tuts :~ + nock1/"Intro to Nock" nock2/"Nock is Easy" nock3/"Using Nock" + == + ;strong: Hoon + ;+ %- tuts :~ + hoon1/"Intro to Hoon" hoon2/"Types" hoon3/"Hoon Computes" + hoon4/"Gates" hoon5/"Tiles" hoon6/"Type Inference" + hoon7/"Odds, Ends, Quirks" + == + ;strong: Arvo + ;+ %- tuts :~ + arvo1/"Basic Arvo" arvo2/"More Basic Arvo" arvo3/"Apps" + arvo4/"Functional Publishing I" arvo5/"Functional Publishing II" + == + == + ;li + ;p:(h2:"Reference") + ;* %- refs :~ + foreword/["Foreword" "Nock"] preface/["Preface" "Hoon Abstract"] + vol0/["Volume 0" "Version Stub"] + vol1/["Volume 1" "Hoon Structures"] + vol2/["Volume 2" "Hoon Compiler"] + vol3/["Volume 3" "Arvo Core"] + vol4/["Volume 4" "Arvo Vanes"] + == + == + == + == + == + == +== diff --git a/main/pub/fab/site/styles.css b/main/pub/fab/site/styles.css index dedf19c5e..c02e5f460 100644 --- a/main/pub/fab/site/styles.css +++ b/main/pub/fab/site/styles.css @@ -139,7 +139,7 @@ pre, .codeblock { margin-top: 0; margin-bottom: 1rem; padding: 1rem; - font-size: .9rem; + font-size: .8rem; line-height: 1.4; white-space: pre; white-space: pre-wrap; diff --git a/main/pub/src/doc/chat/help.txt b/main/pub/src/doc/chat/help.txt index 0f445c25e..594e51d62 100644 --- a/main/pub/src/doc/chat/help.txt +++ b/main/pub/src/doc/chat/help.txt @@ -13,7 +13,7 @@ other: = show ships in current station \\ 5 show recent backlog (last n messages) \\ ~m5 show recent backlog (using @dr syntax) -\\ ~2014.07.04 show recent backlog (using @da syntax) +\\ ~2014.7.4 show recent backlog (using @da syntax) command-line parameters: [%tower ~hoclur-bicrel] select haus server (default: ticketing ship) diff --git a/main/pub/src/doc/ref/hoon/LexiconToDo.txt b/main/pub/src/doc/ref/hoon/LexiconToDo.txt new file mode 100644 index 000000000..487062371 --- /dev/null +++ b/main/pub/src/doc/ref/hoon/LexiconToDo.txt @@ -0,0 +1,3 @@ +Lexicon: + +Links between common runes and their inverts. diff --git a/main/pub/src/doc/ref/hoon/lex-noun.md b/main/pub/src/doc/ref/hoon/lex-noun.md new file mode 100644 index 000000000..25ee5c14c --- /dev/null +++ b/main/pub/src/doc/ref/hoon/lex-noun.md @@ -0,0 +1,553 @@ +Lexicon: Nouns +======= + +Atom Syntax +---------- + + +###Canonical Atom Odors + +An odor is an atom format that specifies an atomic subtype. + +``` +@c UTF-32 codepoint +@d date + @da absolute date + @dr relative date (ie, timespan) +@f yes or no (inverse boolean) +@n nil +@p phonemic base +@r IEEE floating-point + @rd double precision (64 bits) + @rh half precision (16 bits) + @rq quad precision (128 bits) + @rs single precision (32 bits) +@s signed integer, sign bit low + @sb signed binary + @sd signed decimal + @sv signed base32 + @sw signed base64 + @sx signed hexadecimal +@t UTF-8 text (cord) + @ta ASCII text (span) + @tas ASCII symbol (term) +@u unsigned integer + @ub unsigned binary + @ud unsigned decimal + @uv unsigned base32 + @uw unsigned base64 + @ux unsigned hexadecimal +``` + +###Unsigned decimal, @ud + +Hoon's unsigned decimal format is the normal Continental syntax. It differs +from the Anglo-American only in the use of periods, rather than commas, between +groups of 3: + + ~zod/try=> 19 + 19 + ~zod/try=> 1.024 + 1.024 + +An unsigned decimal not broken into groups is a syntax error. Also, whitespace +or even linebreaks can appear between the dot and the next group. + + ~zod/try=> 65. 536 + 65.536 + +###Unsigned hexadecimal, @ux + +@ux has the same syntax as @ud, except that it's prefixed by 0x and uses groups +of four. Hex digits are lowercase only. + + ~zod/try=> 0x0 + 0x0 + ~zod/try=> `@ud`0x17 + 23 + +###Unsigned base64 and base32, @uv, @uw + +The prefix is 0w for base64 and 0v for base32. The digits for @uw are, in +order: 0-9, a-z, A-Z, -, ~: + + ~zod/try=> `@ud`0w- + 62 + +For @uv, the digits are 0-9, a-v. + +Signed integers, @sd, @sx, @sw, @sv, @sb + +Obviously, without finite-sized integers, the sign extension trick does not +work. A signed integer in Hoon is a different way to use atoms than an unsigned +integer; even for positive numbers, the signed integer cannot equal the +unsigned. + +The prefix for a negative signed integer is a single - before the unsigned +syntax. The prefix for a positive signed integer is --. The sign bit is the low +bit: + + ~zod/try=> -1 + -1 + ~zod/try=> --1 + --1 + ~zod/try=> `@ud`-1 + 1 + ~zod/try=> `@ud`--1 + 2 + ~zod/try=> `@ud`-2 + 3 + ~zod/try=> `@ud`--2 + 4 + ~zod/try=> `@ux`-0x10 + 0x1f + ~zod/try=> `@ux`--0x10 + 0x20 + ~zod/try=> `@ud`--0w- + 124 + ~zod/try=> `@sw`124 + --0w- + +###Absolute date, @da + +Urbit dates represent 128-bit chronological time, with 2^64 seconds from the +start of the universe to the end. 2^127 is 3:30:08 PM on December 5, AD 226, +for reasons not clear or relevant: + + ~zod/try=> `@da`(bex 127) + ~226.12.5..15.30.08 + + ~zod/try=> `@da`(dec (bex 127)) + ~226.12.5..15.30.07..ffff.ffff.ffff.ffff + +The time of day and/or second fragment is optional: + + ~zod/try=> `@ux`~2013.12.7 + 0x8000.000d.2140.7280.0000.0000.0000.0000 + + ~zod/try=> `@ux`~2013.12.7..15.30.07 + 0x8000.000d.2141.4c7f.0000.0000.0000.0000 + + ~zod/try=> `@ux`~2013.12.7..15.30.07..1234 + 0x8000.000d.2141.4c7f.1234.0000.0000.0000 + +We also do BC: + + ~zod/try=> `@ux`~226-.12.5 + 0x7fff.fffc.afb1.b800.0000.0000.0000.0000 + +The semantics of the time system are that UGT (Urbit Galactic Time) is GMT/UTC +as of leap second 25. UGT is chronological and will never add leap seconds, +even if UTC continues this mistake. If a gap appears, it must be resolved in +the presentation layer, with timezones and other human curiosities. + +See section 2cH of the source for more details. + +###Relative date, @dr + +It's also nice to have a syntax for basic time intervals: + + ~zod/try=> `@ux`~s1 + 0x1.0000.0000.0000.0000 + + ~zod/try=> `@ux`~m1 + 0x3c.0000.0000.0000.0000 + + ~zod/try=> (div ~m1 ~s1) + 60 + + ~zod/try=> (div ~h1 ~m1) + 60 + + ~zod/try=> (div ~h1 ~s1) + 3.600 + + ~zod/try=> (div ~d1 ~h1) + 24 + + ~zod/try=> `@da`(add ~2013.11.30 ~d1) + ~2013.12.1 + +There are no @dr intervals under a second or over a day. Since the resolution +is so high, though, (div ~s1 1.000.000) produces a pretty accurate microsecond. + +###Loobean, @f + +A loobean, or just bean, is 0 or 1. 0 is yes, 1 is no: + + ~zod/try=> `@ud`.y + 0 + ~zod/try=> `@ud`.n + 1 + +###Nil, @n + +Nil indicates an absence of information, as in a list terminator. The only +value is ~, 0. + + ~zod/try=> `@ud`~ + 0 + +###Unicode text, @t + +@t is a sequence of UTF-8 bytes, LSB first - sometimes called a cord. For +lowercase numbers and letters, the canonical syntax is ~~text: + + ~zod/try=> ~~foo + 'foo' + +Note that the prettyprinter makes an unprincipled exception and prints the text +in a noncanonical format: + + ~zod/try=> `@ux`~~foo + 0x6f.6f66 + +We want to be able to encode an arbitrary Unicode string as a single URL-safe +token, using no punctuation but .~-, in @t. Space is ., . is ~., ~ is ~~, - is +-: + + ~zod/try=> ~~foo.bar + 'foo bar' + ~zod/try=> ~~foo.bar~.baz~~moo-hoo + 'foo bar.baz~moo-hoo' + +For all other ASCII/Unicode characters, insert the Unicode codepoint in +lower-case hexadecimal, followed by .. For example, for U+2605 "BLACK STAR", +write: + + ~zod/try=> ~~foo~2605.bar + 'foo★bar' + +This UTF-32 codepoint is of course converted to UTF-8: + + ~zod/try=> `@ux`~~foo~2605.bar + 0x72.6162.8598.e26f.6f66 + +###URL-safe ASCII text, @ta + +@ta encodes the ASCII subset that all canonical atom syntaxes restrict +themselves to. The prefix is ~.. There are no escape sequences except ~~, which +means ~, and ~-, which means \_. - and . encode themselves. No other characters +besides numbers and lowercase letters need apply. + + ~zod/try=> `@t`~.foo + 'foo' + ~zod/try=> `@t`~.foo.bar + 'foo.bar' + ~zod/try=> `@t`~.foo~~bar + 'foo~bar' + ~zod/try=> `@t`~.foo~-bar + 'foo_bar' + ~zod/try=> `@t`~.foo-bar + 'foo-bar' + +A @ta atom is called a span. + +###Codepoint, @c + +Normally when we build atoms of Unicode text, we use a UTF-8 bytestream, LSB +first. But sometimes it's useful to build atoms of one or more UTF-32 words. + +The codepoint syntax is the same as @t, except with a ~- prefix. Let's repeat +our examples, with hex display: + + ~zod/try=> `@ux`~-foo + 0x6f.0000.006f.0000.0066 + + ~zod/try=> `@ux`~-foo.bar + 0x72.0000.0061.0000.0062.0000.0020.0000.006f.0000.006f.0000.0066 + +###Phonemic, @p + +We've seen @p used for ships, of course. But it's not just for ships - it's for +any short number optimized for memorability, not for arithmetic. @p is great +for checksums, for instance. + +That said, @p is subtly customized for the sociopolitical design of Urbit as a +digital republic. For example, one feature we don't want is the ability to see +at a glance which carrier and cruiser issued a destroyer. Consider the carrier +0x21: + + ~zod/try=> `@p`0x21 + ~mep + +It issues 255 cruisers, including 0x4321: + + ~zod/try=> `@p`0x4321 + ~pasnut + +Which issues 65.535 destroyers, including 0x8765.4321 and several successors: + + ~zod/try=> `@p`0x8765.4321 + ~famsyr-dirwes + ~zod/try=> `@p`0x8766.4321 + ~lidlug-maprec + ~zod/try=> `@p`0x8767.4321 + ~tidlus-roplen + ~zod/try=> `@p`0x8768.4321 + ~lisnel-lonbet + +Of course, anyone who can juggle bits can see that ~famsyr-dirwes is a close +cousin of ~lidlug-maprec. But she actually has to juggle bits to do it. +Obfuscation does not prevent calculated associations, just automatic ones. + +But at the yacht level, we actually want to see a uniform 32-bit space of +yachts directly associated with the destroyer: + + ~zod/try=> `@p`0x9.8765.4321 + ~talfes-sibzod-famsyr-dirwes + ~zod/try=> `@p`0xba9.8765.4321 + ~tacbep-ronreg-famsyr-dirwes + ~zod/try=> `@p`0xd.cba9.8765.4321 + ~bicsub-ritbyt-famsyr-dirwes + ~zod/try=> `@p`0xfed.cba9.8765.4321 + ~sivrep-hadfeb-famsyr-dirwes + +###IPv4 and IPv6 addresses, @if, @is + +Urbit lives atop IP and would be very foolish to not support a syntax for the +large atoms that are IPv4 and IPv6 addresses. + +@if is the standard IPv4 syntax, prefixed with .: + + ~zod/try=> `@ux`.127.0.0.1 + 0x7f00.0001 + +@is is the same as @if, but with 8 groups of 4 hex digits: + + ~zod/try=> `@ux`.dead.beef.0.cafe.42.babe.dead.beef + 0xdead.beef.0000.cafe.0042.babe.dead.beef + + +###Floating Point, @rs, @rd, @rq, @rh + +The syntax for a single-precision float is the normal English syntax, with a . prefix: + + .6.2832 :: τ as @rs + .-6.2832 :: -τ as @rs + .~6.2832 :: τ as @rd + .~-6.2832 :: -τ as @rd + .~~6.2832 :: τ as @rh + .~~~6.2832 :: τ as @rq + +(Hoon is a Tauist language and promotes International Tau Day.) + +###Transparent cell syntax + +By adding _, we can encode arbitrary nouns in our safe subset. The prefix to a +canonical cell is ._; the separator is _; the terminator is __. Thus: + + ~zod/try=> ._3_4__ + [3 4] + + ~zod/try=> :type; ._.127.0.0.1_._0x12_19___~tasfyn-partyv__ + [.127.0.0.1 [0x12 19] ~tasfyn-partyv] + [@if [@ux @ud] @p] + +Those who don't see utility in this strange feature have perhaps never needed +to jam a data structure into a URL. + +###Opaque noun syntax + +Speaking of jam, sometimes we really don't care what's inside our noun. Then, +the syntax to use is a variant of @uw prefixed by ~, which incorporates the +built-in jam and cue marshallers: + + ~zod/try=> (jam [3 4]) + 78.241 + ~zod/try=> `@uw`(jam [3 4]) + 0wj6x + ~zod/try=> (cue 0wj6x) + [3 4] + ~zod/try=> ~0wj6x + [3 4] + +Noncanonical Syntax +-------------------- + +These are syntaxes for constants which don't fit the canonical character-set +constraints. + +###Cubes, @tas + +@tas, a term, is our most exclusive odor. The only characters permitted are +lowercase ASCII, - except as the first or last character, and 0-9 except as the +first character. + +The syntax for @tas is the text itself, always preceded by %. This means a term +is always cubical. You can cast it to @tas if you like, but we just about +always want the cube: + + ~zod/try=> %dead-fish9 + %dead-fish9 + + ~zod/try=> -:!>(%dead-fish9) + [%cube p=271.101.667.197.767.630.546.276 q=[%atom p=%tas]] + +The empty @tas has a special syntax, $: + + ~zod/try=> %$ + %$ + +A term without % is not a constant, but a name: + + ~zod/try=> dead-fish9 + ! -find-limb.dead-fish9 + ! find-none + ! exit + +A common structure in Hoon is a noun with a cubical head and an arbitrary tail: + + ~zod/try=> [%foo 'bar'] + [%foo 'bar'] + +This structure may be generated with the following irregular syntax: + + ~zod/try=> a/'bar' + [%a 'bar'] + +###Loobeans, @f + + .y is a little cumbersome, so we can say & and |. The % prefix cubes as usual. + + ~zod/try=> `@ud`& + 0 + ~zod/try=> `@ud`| + 1 + +###Cords, @t + +The canonical ~~ syntax for @t, while it has its place, is intolerable in a +number of ways - especially when it comes to escaping capitals. So @t is both +printed and parsed in a conventional-looking single-quote syntax: + + ~zod/try=> 'foo bar' + 'foo bar' + ~zod/try=> `@ux`'foo bar' + 0x72.6162.206f.6f66 + Escape ' with \: + + ~zod/try=> 'Foo \'bar' + 'Foo \'bar' + ~zod/try=> `@ux`'\'' + 0x27 + +###Strings + +Text in Hoon is generally manipulated in two ways, depending on what you're +doing: as an atomic cord/span/term, or as a tape which is a list of bytes (not +codepoints). + +To generate a tape, use double quotes: + + ~zod/try=> "foo" + "foo" + ~zod/try=> `*`"foo" + [102 111 111 0] + +We're getting off the constant reservation, but strings also interpolate with curly-braces: + + ~zod/try=> "hello {(weld "wor" "ld")} is a fun thing to say" + "hello world is a fun thing to say" + +And they can be joined across space or lines with a .: + + ~zod/try=> "hello"."world" + "helloworld" + ~zod/try=> "hello". "world" + "helloworld" + +Lists +----- + +A list in Hoon is a null-terminated tuple. See section 2bB for Hoon's List library. + + ~zod/try=> :type; `(list)`[3 4 ~] + ~[3 4] + it(*) + +The list type can be further specified by a subtype: + + ~zod/try=> :type; `(list ,@ud)`[3 4 ~] + ~[3 4] + it(@ud) + +The above example is a list of @ud, meaning the all values in the list must be of type @ud. + +Polymorphic lists can be specified by constructing a more complex type: + + ~zod/try=> :type; `(list ?(@ud @ux))`[3 0xf ~] + ~[3 15] + it({@ud @ux}) + +Not specifing a more complex type defaults to a list of raw nouns: + + ~zod/try=> :type; `(list)`[3 0xf ~] + ~[3 15] + it(*) + +Null-terminated tuples may be generated with the following syntax: + + ~zod/try=> ~[3 0xf] + [3 0xf ~] + + ~zod/try=> :type; ~[3 0xf] + [3 0xf ~] + [@ud @ux %~] + +Note that this syntax is not automatically typed as a list, but may be cast as such: + + ~zod/try=> :type; `(list ?(@ux @ud))`~[3 0xf] + ~[0x3 0xf] + it({@ux @ud}) + +Furthermore, a different syntax may be used to group the entire noun in the +head of a null terminated tuple: + + + ~zod/try=> [3 0xf]~ + [[3 0xf] ~] + +This is often used to easily generate a list from a single noun. + +~zod/try=> :type; `(list ,[@ud @ux])`[3 0xf]~ +~[[3 0xf]] +it([@ud @ux]) + +The above is typed as a list of decimal hexadecimal pairs. + +Units +----- + +A Unit is Hoon's "maybe" type. As in, either some value or null. See section 2bA for Hoon's Unit library. Units are represented by a cell whose head is null and whose tail is some noun: + + ~zod/try=> `(unit ,@ud)`[~ 3] + [~ 3] + +The unit type can be further specified by a subtype. The above example is a unit of @ud, meaning the optional value must be of type @ud. + + ~zod/try=> `(unit ,@ud)`[~ [3 3]] + ! type-fail + ! exit + + ~zod/try=> `(unit ,^)`[~ [3 3]] + [~ [3 3]] + +For convenience, a null-headed noun may be specified with the following irregular syntax: + + ~zod/try=> `3 + [~ 3] + + ~zod/try=> :type; `3 + [~ 3] + [%~ @ud] + +Note that this syntax is not automatically typed as a Unit, but may be cast as such: + + ~zod/try=> :type; `(unit)``3 + [~ 3] + u(*) + + + + diff --git a/main/pub/src/doc/ref/hoon/lex-rune.md b/main/pub/src/doc/ref/hoon/lex-rune.md new file mode 100644 index 000000000..a55a10f8c --- /dev/null +++ b/main/pub/src/doc/ref/hoon/lex-rune.md @@ -0,0 +1,2521 @@ +Lexicon: Runes +======= + +Irregular +-------- + + ,p $,(p) + *p $*(p) + _p $_(p) + p@q $@(p q) + !p ?!(p) + &(p q) ?&(p q) + |(p q) ?|(p q) + `p`q ^-(p q) + p=q ^=(p q) + ~[p q] :~(a b) + [p q]~ :~(a) + `[p] [~ p] + p^q [p q] + [p q] :*(p) + +(p) .+(p) + =(p q) .=(p) + p:q =<(p q) + p(q r) %=(p q r) + (p list) %-(p) + ~(p q r) %~(p q r) + >p< #<(p) +

#>(p) + :(p q) ;:(p q) + +Regular Runes +============ + +Core construction: `|` +--------------------- + + |_ dry %gold door + + Twig: [%brcb p=tile q=(map term foot)] + + Tall: |_ p + ++ p.n.q + q.n.q + -- + +--- + + |% generic %gold core + + Twig: [%brcn p=(map term foot)] + + Tall: |% + ++ p.n.p + q.n.p + +- p.n.l.p + q.n.l.p + -- + + [Note: dry arms are specified with ++, wet arms with +-] + +--- + + + |. dry %gold trap + + Twig: [%brdt p=twig] + + Tall: |. p + + Wide: |.(p) + +--- + + |/ vulcanized gold door + + Twig: [%brfs p=tile q=(map term foot)] + + Tall: |/ p + +- p.n.q + q.n.q + -- + + [Note: |/ only accepts wet arms with +-] + +--- + + |^ kick a %gold book + + Twig: [%brkt p=twig q=(map term foot)] + + Tall: |^ p + ++ p.n.q + q.n.q + -- +--- + + + |- kick a %gold trap + + Twig: [%brhp p=twig] + + Tall: |- p + + Wide: |-(p) + +---- + + |+ dry %iron gate + + Twig: [%brls p=tile q=twig] + + Tall: |+ p q + + Wide: |+(p q) + +--- + + |* vulcanized wet gate + + Twig: [%brtr p=tile q=twig] + + Tall: |* p q + + Wide: |*(p q) + +--- + + |= dry %gold gate + + Twig: [%brts p=tile q=twig] + + Tall: |= p q + + Wide: |=(p q) + +--- + + |? dry %lead trap + + Twig: [%brwt p=twig] + + Tall: |? p + + Wide: |?(p) + +--- + +Tiles and tiling: `$` +--------------------- + + $_ bunt a tile + + Twig: [%bccb p=tile] + + Tall: $_ p + + Wide: $_(p) + + Irrg: _p + +--- + + $, clam a tile + + Twig: [%bccm p=tile] + + Tall: $, p + + Wide: none + + Irrg: ,p + +--- + + $@ whip a wing into a tile + + Twig: [%bcpt p=wing q=tile] + + Tall: $@ p q + + Wide: $@(p q) + + Irrg: p@q + +--- + + $* bunt a tile statically + + Twig: [%bctr p=tile] + + Tall: $* p + + Wide: $*(p) + + Irrg: *p + +--- + +###Tile runes + + $^ plant a %herb + + Tile: [%herb p=twig] + + Tall: $^ p + + Wide: $^(p) + +--- + + $: build a tile + + Tile: [p=tile q=tile] + + Tall: $: p + q + == + + Wide: [p q] + +--- + + $= plant a %bark + + Tile: [%bark p=term q=tile] + + Tall: $= p q + + Wide: none + + Irrg: p=q + +--- + + $& plant a %bush + + Tile: [%bush p=tile q=tile] + + Tall: $& p q + + Wide: $&(p q) + + Irrg: none + +--- + + $? plant a %fern + + Tile: [%fern p=[i=tile t=(list tile)]] + + Tall: $? i.p + i.t.p + == + + Wide: none + + Irrg: ?(i.p i.t.p) + +--- + + $% plant a %kelp + + Tile: [%kelp p=[i=line t=(list line)]] + + Tall: $% p + q + == + + Wide: none + + Irrg: none + +--- + + $| plant a %reed + + Tile: [%reed p=tile q=tile] + + Tall: $| p + q + == + + Wide: $|(p q) + + Irrg: none + +--- + +###Axils glyphs + + @ atom axil + ^ cell axil + * noun axil + ? bean axil + ~ null axil + +--- + +Invocations: `%` +--------------- + + %_ invoke with changes and cast + + Twig: [%cncb p=wing q=tram] + + Tall: %_ p + p.i.q q.i.q + p.i.t.q q.i.t.q + == + + Wide: %_(p p.i.q q.i.q, p.i.t.q q.i.t.q) + +--- + + %: pull %$ of a door with a sample + + Twig: [%cncl p=twig q=twig] + + Tall: %: p q + + Wide: %:(p q) + +--- + + %. inverse order %- + + Twig: [%cndt p=twig q=twig] + + Tall: %. p q + + Wide: %.(p q) + +--- + + %- slam a core with a sample + + Twig: [%cnhp p=twig q=tusk] + + Tall: %- p q + + Wide: %-(p q) + + Irrg: (p q) + +--- + + %* pull wing from tray with changes + + Twig: [%cntr p=wing q=twig r=tram] + + Tall: %* p q + p.i.r q.i.r + p.i.t.r q.i.t.r + == + + Wide: %*(p q p.i.r q.i.r, p.i.t.r q.i.t.r) + +--- + + %^ slam gate with triple + + Twig: [%cnkt p=twig q=twig r=twig s=twig] + + Tall: %^ p + q + r + s + + Wide: %^(p q r s) + +--- + + %+ slam gate with pair + + Twig: [%cnls p=twig q=twig r=twig] + + Tall: %+ p + r + s + + Wide: %+(p q r) + +--- + + %~ pull from tray with sample + + Twig: [%cnsg p=wing q=twig r=twig] + + Tall: %~ p + q + r + + Wide: %~(p q r) + +--- + + %= evaluate with changes + + Twig: [%cnts p=wing q=tram] + + Tall: %= p + p.i.q q.i.q + p.i.t.q q.i.t.q + == + + Wide: %=(p p.i.q q.i.q, p.i.t.q q.i.t.q) + + Irrg: p(p.i.q q.i.q, p.i.t.q q.i.t.q) + +--- + +Tuples: `:` +--------- + + :_ reverse pair [q p] + + Twig: [%clcb p=twig q=twig] + + Tall: :_ p q + + Wide: :_(p q) + +--- + + :% produce [[p ~] ~] + + Twig: [%clcn p=tusk] + + Tall: :% i.p + i.t.p + i.t.t.p + == + + Wide: :%(i.p i.t.p i.t.t.p) + +--- + + :/ produce [%$ [%$ p ~] ~] + + Twig: [%clfs p=twig] + + Tall: :/ p + + Wide: :/(p) + +--- + + :^ produce [p q r s] + + Twig: [%clkt p=twig q=twig r=twig s=twig] + + Tall: :^ p + q + r + s + + Wide: :^(p q r s) + +--- + + :- produce [p q] + + Twig: [%clhp p=twig q=twig] + + Tall: :- p q + + Wide: :-(p q) + + Irrg: [p q] + +--- + + :+ produce [p q r] + + Twig: [%clls p=twig q=twig r=twig] + + Tall: :+ p + q + r + + Wide: :+(p q r) + +--- + + :~ produce null-terminated tuple + + Twig: [%clsg p=tusk] + + Tall: :~ i.p + i.t.p + i.t.t.p + == + + Wide: :~(i.p i.t.p i.t.t.p) + + Irrg: ~[i.p i.t.p i.t.t.p] + +--- + + :* produce n-ary tuple + + Twig: [%cltr p=tusk] + + Tall: :* i.p + i.t.p + i.t.t.p + == + + Wide: :*(i.p i.t.p i.t.t.p) + + Irrg: [i.p i.t.p i.t.t.p] + +--- + +Nock operators: `.` +-------------- + + .^ + .+ + .* + .= + .? + +Type conversions: `^` +-------------------- + + ^| + ^. + ^+ + ^- + ^& + ^~ + ^= + ^? + +Miscellaneous macros: `;` +------------------------ + + ;: + ;. + ;" + ;~ + ;; + +Hints: `~` +---------- + + ~| + ~_ + ~% + ~/ + ~< + ~> + ~$ + ~+ + ~& + ~= + ~? + ~! + +Compositions: `=` +---------------- + + =| + =: + =% + =. + =/ + => + =< + =- + =^ + =+ + =& + =@ + =* + =~ + +Conditionals, booleans, tests: `?` +--------------------------------- + + ?| + ?- + ?: + ?. + ?^ + ?> + ?< + ?+ + ?& + ?~ + ?= + ?! + +Special operations: `!` +----------------------- + + !: + !_ + !, + !% + !/ + !; + !? + !! + +Wing Runes +--------- + +Limbs + Names + a + ^a + + Axes + . + +3 + &3 + ->- + +Wings: concatenate limbs separated by . + +Punctuation runes + +++ dry arm ++- wet arm + +== terminate list +-- terminate map or set + + + + [%brcb p=tile q=(map term foot)] + +|_ ("barcab") is a synthetic rune that produces a %gold tray with +sample p, arms q. q is an associative array of names and +expressions, each pair of which is called an arm. After any number +of dry (%ash, ++) and/or wet (%elm, +-) arms, the array is +terminated with -- + + Tall + |_ p + ++ p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brcn p=(map term foot)] + +|% ("barcen") is a natural rune that produces a %gold core from an +associative array of names and expressions, each pair of which is +called an arm. After any number of dry (%ash, ++) and/or wet (%elm, ++-) arms, the array is terminated with -- + + Tall + |% + ++ p.n.q + q.n.q + +- p.n.l.q + q.n.l.q + -- + + Wide + none + + Irregular + none + + Reduction + none, natural + + [%brdt p=twig] + +|. ("bardot") is a synthetic rune that produces a dry %gold trap +from twig p. + + Tall + |. p + + Wide + |.(p) + + Irregular + none + + Reduction + See ++open + + [%brfs p=tile q=(map term foot)] + +|/ ("barfas") is a synthetic rune that produces a vulcanized %gold +tray with arms q, sample p. + + Tall + |/ p + +- p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brkt p=twig q=(map term foot)] + +|^ ("barket") is a synthetic rune that produces a %gold book with +arms q, with p as %$, and kicks it. + + Tall + |^ p + ++ p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brhp p=twig] + +|- ("barhep") is a synthetic rune that produces a dry %gold trap +from twig p, and kicks it. + + Tall + |- + p + + Wide + |-(p) + + Irregular + none + + Reduction + See ++open + + [%brls p=tile q=twig] + +|+ ("barlus") is a synthetic rune that produces a dry %iron gate +with arm q, sample p. + + Tall + |+ p + q + + Wide + |+(p q) + + Irregular + none + + Reduction + See ++open + + [%brpt p=tile q=tile r=twig] + + XX not used + + [%brtr p=tile q=twig] + +|* ("bartar") is a synthetic rune that produces a vulcanized wet +gate with arm q, sample p. + + Tall + |* p + q + + Wide + |*(p q) + + Irregular + none + + Reduction + See ++open + + [%brts p=tile q=twig] + +|= ("bartis") is a synthetic hoon that produces a dry %gold gate +with arm q, sample p. + + Tall + |= p + q + + Wide + |=(p q) + + Irregular + none + + Reduction + See ++open + + [%brwt p=twig] + +|? ("barwut") is a synthetic rune that produces a dry %lead trap. + + Tall + |? p + + Wide + |?(p) + + Irregular + none + + Reduction + See ++open + + [%clcb p=twig q=twig] + +:_ ("colcab") is a synthetic rune that produces the cell [q p]. + + Tall + :_ p + q + + Wide + :_(p q) + + Irregular + none + + Reduction + See ++open + + [%clcn p=tusk] + +:% ("colcen") is a synthetic rune that produces a cell [[p ~] ~] +from a list of twigs p, terminated by a == + + Tall + :% i.p + i.t.p + i.t.t.p + == + + Wide + :%(i.p i.t.p i.t.t.p) + + Irregular + %[i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%clfs p=twig] + +:/ ("colfas") is a synthetic rune that, given a twig p, produces +[%$ [%$ p ~] ~], i.e., [0 [0 p 0] 0]. Used in practice only in +string interpolation. + + Tall + :/ p + + Wide + :/(p) + + Irregular + none + + Reduction + See ++open + + [%clkt p=twig q=twig r=twig s=twig] + +:^ ("colket") is a synthetic rune that produces a cell [p q r s] +from twigs p, q, r, and s. + + Tall + :^ p + q + r + s + + Wide + :^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%clhp p=twig q=twig] + +:- ("colhep") is a synthetic rune that produces the cell [p q] from +twigs p and q. + + Tall + :- p + q + + Wide + :-(p q) + + Irregular + [p q] + + Reduction + See ++open + + [%clls p=twig q=twig r=twig] + +:+ ("collus") is a synthetic rune that produces a cell [p q r] from +twigs p, q, and r. + + Tall + :+ p + q + r + + Wide + :+(p q r) + + Irregular + none + + Reduction + See ++open + + [%clsg p=tusk] + +:~ ("colsig") is a synthetic rune that produces a null-terminated +tuple of a list of twigs p. + + Tall + :~ i.p + i.t.p + i.t.t.p + == + + Wide + :~(i.p i.t.p i.t.t.p) + + Irregular + ~[i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%cltr p=tusk] + +:* ("coltar") is a synthetic hoon that produces a tuple from p, a +list of twigs. + + Tall + :* i.p + i.t.p + i.t.t.p + == + + Wide + :*(i.p i.t.p i.t.t.p) + + Irregular + [i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%clzz p=tusk] + +"colzaz" is a synthetic internal rune that promotes its tusk p +within a %clsg or %cltr tusk. + + Not used at present. + + [%cncb p=wing q=tram] + +%_ ("cencab") is a synthetic rune that evaluates the wing p with +the changes specified in tram q, then casts the product back to p. + + Tall + %_ p + p.i.q q.i.q + p.i.t.q q.i.t.q + == + + Wide + %_(p p.i.q q.i.q, p.i.t.q q.i.t.q) + + Irregular + none + + Reduction + See ++open + + [%cncl p=twig q=twig] + +%: ("cencol") is a synthetic rune that pulls %$ from the twig p +with the with its sample set to q. + + Tall + %: p + q + + Wide + %:(p q) + + Irregular + none + + Reduction + See ++open + + [%cndt p=twig q=twig] + +%. ("cendot") is a synthetic rune that slams the gate q with +[%cltr p]. The dual of %cnhp. + + Tall + %. p + q + + Wide + %.(p q) + + Irregular + none + + Reduction + %- q + p + + See ++open + + [%cnhp p=twig q=tusk] + +%- ("cenhep") is a synthetic rune that slams the gate p with +[%cltr q]. + + Tall + %- p + q + + Wide + %-(p q) + + Irregular + (p q) + + Reduction + See ++open + + [%cntr p=wing q=twig r=tram] + +%* is a synthetic rune that pulls the wing p from tray q with changes r. + + Tall + %* p q + p.i.r q.i.r + p.i.t.r q.i.t.r + == + + Wide + %*(p q p.i.r q.i.r, p.i.t.r q.i.t.r) + + Irregular + none + + Reduction + See ++open + + [%cnkt p=twig q=twig r=twig s=twig] + +%^ ("cenket") is a synthetic rune that slams gate p with [%cntr q r s]. + + Tall + %^ p + q + r + s + + Wide + %^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%cnls p=twig q=twig r=twig] + +%+ ("cenlus") is a synthetic rune that slams gate p with [%cntr q r]. + + Tall + %+ p + r + s + + Wide + %+(p q r) + + Irregular + none + + Reduction + See ++open + + [%cnsg p=wing q=twig r=twig] + +%~ ("censig") is a synthetic rune that pulls p from the tray q with its +sample set to r. + + Tall + %~ p + q + r + + Wide + %~(p q r) + + Irregular + ~(p q r) + + Reduction + See ++open + + [%cnts p=wing q=tram] + +%= ("centis") is a natural rune that evaluates p with the changes +specified in q. + + Tall + %= p + p.i.q q.i.q + p.i.t.q q.i.t.q + == + + Wide + %=(p p.i.q q.i.q, p.i.t.q q.i.t.q) + + Irregular + p(p.i.q q.i.q, p.i.t.q q.i.t.q) + + Reduction + See ++open + + [%cnzy p=term] + +"cenzey" is a synthetic internal rune that pulls limb p from the subject. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%cnzz p=wing] + +"cenzaz" is a synthetic internal rune that pulls wing p from the subject. + + Form + none, internal + + Reduction + See ++open + + [%dtkt p=twig] + +.^ ("dotket") is a natural rune that generates Nock operator 11, which in +virtual userspace Nock (++mock) loads a file from the global namespace. + + Tall + .^ p + + Wide + .^(p) + + Irregular + ^:type/path + + ^/path + + Reduction + none, natural + + [%dtls p=twig] + +.+ ("dotlus") is a natural rune that generates Nock operator 4, which +increments an atomic operand. + + Tall + .+ p + + Wide + .+(p) + + Irregular + +(p) + + Reduction + none, natural + + [%dtzy p=term q=@] + +"dotzey" is a natural internal rune that produces a non-cubed atomic +constant of odor p and value q. + + Tall/Wide/Irregular + none, internal + + Reduction + none, natural + + [%dtzz p=term q=*] + +"dotzaz" is a natural internal rune that produces a cubed noun constant of +value q and odor p, if q is an atom. + + Tall/Wide/Irregular + none, internal + + Reduction + none, natural + + [%dttr p=twig q=twig] + +.* ("dottar") is a natural rune that calculates the Nock of subject p, +formula q. + + Tall + .* p + q + + Wide + .*(p q) + + Irregular + none + + Reduction + none, natural + + [%dtts p=twig q=twig] + +.= ("dottis") is a natural rune that applies Nock 5 (equals) to determine +if the products of p and q are equivalent. + + Tall + .= p + q + + Wide + .=(p q) + + Irregular + =(p q) + + Reduction + none, natural + + [%dtwt p=twig] + +.? ("dotwut") is a natural hoon that applies Nock 3 to a noun: if the +noun is a cell, it returns the loobean & (true); if the noun is an atom, +it returns the loobean | (false). + + Tall + .? p + + Wide + .?(p) + + Irregular + none + + Reduction + none, natural + + [%hxgl p=tusk] + +#< ("haxgal") is a synthetic rune that slams the assumed gate noah on +[%zpgr %cntr p]. See the Biblical names. + + Tall/Wide + none + + Irregular + >i.p i.t.p i.t.t.p< + + Reduction + See ++open + + [%hxgr p=tusk] + +#> ("haxgar") is a synthetic rune that slams the assumed gate cain on +[%zpgr %cntr p]. See the Biblical names. + + Tall/Wide + none + + Irregular + + + Reduction + See ++open + + [%ktbr p=twig] + +^| ("ketbar") is a natural rune that converts a %gold core into an %iron +core. See geometric polymorphism. + + Tall + ^| p + + Wide + ^|(p) + + Irregular + none + + Reduction + none, natural + + [%ktdt p=twig q=twig] + +^. ("ketdot") is a synthetic rune that casts q to the type of (p q). + + Tall + ^. p + q + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%ktls p=twig q=twig] + +^+ ("ketlus") is a natural rune that casts the product of q to the +type of p, verifying that it contains the type of q. + + Tall + +^ p + q + + Wide + ^+(p q) + + Irregular + none + + Reduction + none, natural + + [%kthp p=tile q=twig] + +^- ("kethep") is a synthetic rune that casts q to ~(bunt al p), +i.e., the icon of p. + + Tall + ^- p + q + + Wide + ^-(p q) + + Irregular + `p`q + + Reduction + See ++open + + [%ktpm p=twig] + +^& ("ketpam") is a natural rune that converts a %gold core to %zinc core. +See geometric polymorphism. + + Tall + ^& p + + Wide + ^&(p) + + Irregular + none + + Reduction + none, natural + + [%ktsg p=twig] + +^~ ("ketsig") is a natural rune that tries to execute p statically at +compile time; if this fails, p remains dynamic. + + Tall + ^~ p + + Wide + ^~(a) + + Irregular + none + + Reduction + none, natural + + [%ktts p=toga q=twig] + +^= ("kettis") is a natural rune that wraps q in the toga p. The +toga is a powerful naming device that can assign an entire name +tree to a properly typed result. For instance, if foo produces +an unlabeled tuple [x y z], [a b=[c d]]=foo produces +[a=x b=[c=y d=z]]. + + Tall + ^= p + q + + Wide + ^=(p q) + + Irregular + none + + Reduction + none, natural + + [%ktwt p=twig] + +^? ("ketwut") is a natural hoon that converts a %gold core into a +%lead core. See geometric polymorphism. + + Tall + ^? p + + Wide + ^?(p) + + Irregular + none + + Reduction + none, natural + + [%sgbr p=twig q=twig] + +~| ("sigbar") is a synthetic rune that presents the product of p +in the stack trace if q crashes. Only performed as needed. +Generates %cain - see the Biblical names. + + Tall + ~| p + q + + Wide + ~|(p q) + + Irregular + none + + Reduction + See ++open, ++feck + + [%sgcb p=twig q=twig] + +~_ ("sigcab") is a synthetic rune that inserts p, a trap producing a tank, +into the trace of q. + + Tall + ~_ p + q + + Wide + ~_(p q) + + Irregular + none + + Reduction + See ++open + + [%sgcn p=chum q=twig r=tyre s=twig] + +~% ("sigcen") is a synthetic rune that identifies a core for specific +optimization. See jet propulsion. + + Tall + ~% p + q + == + p.i.r q.i.r + p.i.t.r q.i.t.r + == + s + + ~% p + q + ~ + s + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%sgfs p=chum q=twig] + +~/ ("sigfas") is a synthetic rune that identifies an arm for specific +optimization. See jet propulsion. + + Tall + ~/ p + q + + Wide + ~/(p q) + + Irregular + none + + Reduction + See ++open + + [%sggl p=$|(term [p=term q=twig]) q=twig] + +~< ("siggal") is a synthetic rune that applies arbitrary hint p to +the product of q. Does not wake the hint engine until the +computation is finished. + + Tall + ~< p + q + + Wide + ~<(p q) + + Irregular + none + + Reduction + See ++open + + [%sggr p=$|(term [p=term q=twig]) q=twig] + +~> ("siggar") is a natural rune that applies arbitrary hint p to q. + + Tall + ~> p + q + + Wide + ~>(p q) + + Irregular + none + + Reduction + See ++open + + [%sgbc p=term q=twig] + +~$ ("sigbuc") is a synthetic rune that labels computation q as p +for profiling (not currently enabled). + + Tall + ~$ p + q + + Wide + ~$(p q) + + Irregular + none + + Reduction + See ++open + + [%sgls p=@ q=twig] + +XX Solve ~+ ("siglus") is a synthetic rune that memoizes computation q + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%sgpm p=@ud q=twig r=twig] + +~& ("sigpam") is a synthetic rune that prints q on the console +before computing r. p is the log priority 0-3, defaulting to 0. + + Tall + 0, debug + ~& q + r + + 1, notice + ~& > q + r + + 2, warning + ~& >> q + r + + 3, alarm + ~& >>> q + r + + Wide + ~&(>>> q r) + + Irregular + none + + Reduction + See ++open + + [%sgts p=twig q=twig] + +~= ("sigtis") is a synthetic rune that hints to the interpreter +that q may produce a noun equal to the already existing p, +avoiding duplication. + + Tall + ~= p + q + + Wide + ~=(p q) + + Irregular + none + + Reduction + See ++open + + [%sgwt p=@ud q=twig r=twig s=twig] + +~? ("sigwut") is a synthetic rune that prints r to the console +before computing s, iff q produces yes. p is the log priority, +0-3, 0 by default + + Tall + 0, debug + ~? q + r + s + + 1, notice + ~? > q + r + s + + 2, warning + ~? >> q + r + s + + 3, alarm + ~? >>> q + r + s + + Wide + ~?(>>> q r s) + + Irregular + none + + Reduction + See ++open + + [%sgzp p=twig q=twig] + +~! ("sigzap") is a natural rune for debugging uses only, +semantically equivalent to its own twig q. Should compilation +fail within q, ~! will show the type of p on the stacktrace. + + Tall + ~! p + q + + Wide + ~!(p q) + + Irregular + none + + Reduction + none, natural + + [%smcl p=twig q=tusk] + +;: ("semcol") is a synthetic gate that applies p, a binary gate, +to the n-ary tuple q. + + Tall + ;: p + i.q + i.t.q + i.t.t.q + == + + Wide + ;:(p i.q i.t.q i.t.t.q) + + Irregular + :(p i.q i.t.q i.t.t.q) + + Reduction + See ++open + + [%smdt p=twig q=tusk] +XX determine function + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smdq p=(list beer)] +XX determine if internal/external + +;" ("semdoq") is a synthetic rune used to make strings, +interpolated or not. + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smsg p=twig q=tusk] + +XX to do + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smsm p=twig q=twig] + +;; ("semsem") is a synthetic rune that types q as a fixpoint of p. +Semantically identical to ((hard p) q). + + Tall + ;; p + q + + Wide + ;;(p q) + + Irregular + none + + Reduction + See ++open + + [%tsbr p=tile q=twig] + +=| ("tisbar") is a synthetic rune that pushes ~(bunt al p) on the +subject and sends it to q. + + Tall + =| p + q + + Wide + =|(p q) + + Irregular + none + + Reduction + =+(_p q) + See ++open, ++bunt in ++al + + [%tscl p=tram q=twig] + +=: ("tiscol") is a synthetic rune that produces q with the subject +by p. Uses %cncb, and so cannot change the subject type. + + Tall + =: p.i.p q.i.p + p.i.t.p q.i.t.p + p.i.t.t.p q.i.t.t.p + == + q + + Wide + none + + Irregular + noen + + Reduction + See ++open + + [%tscn p=twig q=twig] +XX to do + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%tsdt p=wing q=twig r=twig] + +=. ("tisdot") is a synthetic rune that produces r with p in the +subject set to q. Uses %cncb, and so cannot change the subject + p. + + Tall + =. p + q + r + + =. p q + r + + Wide + =.(p q r) + + Irregular + none + + Reduction + See ++open + + [%tsfs p=twig q=twig] + XX not used + + [%tsgl p=twig q=twig] + +=< ("tisgal") is a synthetic rune that uses the product of q as +the subject of p. + + Tall + =< p + q + + Wide + =<(p q) + + Irregular + + Reduction + See ++open + + [%tshp p=twig q=twig] + +=- ("tishep") is a synthetic rune that pushes q on the subject +and sends it to p. Dual of =+ ("tislup") + + + Tall + =- p + q + + Wide + =- + + Irregular + none + + Reduction + See ++open + + [%tsgr p=twig q=twig] + +=> ("tisgar") is a natural rune that uses the product of p as the +subject of q. + + Tall + => p + q + + Wide + =>(p q) + + Irregular + none + + Reduction + none, natural + + [%tskt p=twig q=twig r=twig s=twig] + +=^ ("tisket") is a synthetic rune that handles a product which is +a cell of the new result, and a mutation to the subject. + + Tall + Kingside + =^ p + q + r + s + + Queenside + =^ p q + r + s + + Wide + =^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%tsls p=twig q=twig] + +=+ ("tislus") is a synthetic rune that pushes p on the subject +and sends it to q. Semantically equavlent to Nock 8.Dual of =- ("tishep") + + Tall + =+ p + q + + Wide + =+(p q) + + Irregular + none + + Reduction + See ++open + + [%tspm p=tile q=twig] + + XX not used + + [%tspt p=tile q=twig] + + XX not used + + [%tstr p=term q=wing r=twig] + +=* ("tistar") is a natural rune that creates a %bull, or alias, +type. + + Tall + =* p q + r + + Wide + =*(p q r) + + Irregular + none + + Reduction + none, natural + + [%tssg p=tusk] + +=~ ("tissig") is a synthetic rune that composes a list of twigs. + + Tall + Kingside + =~ i.p + i.t.p + i.t.t.p + == + + Queenside + =~ i.p + i.t.p + i.t.t.p + == + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%wtbr p=tusk] + +?| ("wutbar") is a synthetic rune that computes the "or" of the +loobeans in p. + + Tall + ?| i.p + i.t.p + i.t.t.p + == + + Wide + ?|(i.p i.t.p i.t.t.p) + + Irregular + |(i.p i.t.p i.t.t.p) + + Reduction + See ++open + + [%wthp p=wing q=tine] + +?- ("wuthep") is a synthetic rune that selects a case in q for +the actual type of p. + + Tall + Kingside + ?- p + p.i.q q.i.q + p.i.t.q q.i.t.q + p.i.t.t.q q.i.t.t.q + == + + Queenside + ?- p + p.i.q + q.i.q + p.i.t.q + q.i.t.q + p.i.t.t.q + q.i.t.t.q + == + + Wide + ?-(p p.i.q q.i.q, p.i.t.q q.i.t.q, p.i.t.t.q q.i.t.t.q) + + Irregular + none + + Reduction + See ++open + + [%wthz p=tiki q=tine] + +"wuthaz" is a synthetic internal rune that selects a case in q +for the actual type of p. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtcl p=twig q=twig r=twig] + +?: ("wutcol") is a natural rune that produces q if p is yes (&, 0), +or r if p is no (|, 1). + + Tall + ?: p + q + r + + Wide + ?:(p q r) + + Irregular + none + + Reduction + none, natural + + [%wtdt p=twig q=twig r=twig] + +?. ("wutdot") is a synthetic rune that prduces r if p is yes +(&, 0), of q if p is no (|, 1). + + Tall + ?. p + q + r + + Wide + ?:(p q r) + + Irregular + none + + Reduction + none, natural + + [%wtkt p=wing q=twig r=twig] + +?^ ("wutkey") is a synthetic rune that evaluates r if p is +equivalent to the bunt for its tile, otherwise q is evaluted. + + Tall + ?^ p + q + r + + Wide + ?^(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtkz p=tiki q=twig r=twig] + +"wutkaz" is a synthetic, internal rune that evaluates r if p is +equivalent to the bunt for its tile, otherwise q is evaluated. +See tikis. + + Tall + ?^ p + q + r + + Wide + ?^(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtgl p=twig q=twig] + +?< ("wutgal") is a synthetic hoon that produces q, asserting that +p is no (|, 1). + + Tall + ?< p + q + + Wide + ?<(p q) + + Irregular + none + + Reduction + See ++open + + [%wtgr p=twig q=twig] + +?> ("wutgar") is a synthetic hoon that produces q, asserting that +p is yes (&, 0). + + Tall + ?> p + q + + Wide + ?>(p q) + + Irregular + none + + Reduction + See ++open + + [%wtls p=wing q=twig r=tine] + +?+ ("wutlus") is a synthetic rune that selects a case in q for +the actual type of p. + + Tall + Kingside + ?+ p + q + p.i.r q.i.r + p.i.t.r q.i.t.r + p.i.t.t.r q.i.t.t.r + == + + Queenside + ?+ p + q + p.i.r + q.i.r + p.i.t.r + q.i.t.r + p.i.t.t.r + q.i.t.t.r + == + + Wide + ?+(p p.i.r q.i.r, p.i.t.r q.i.t.r, p.i.t.t.r q.i.t.t.r) + + Irregular + none + + Reduction + See ++open + + [%wtlz p=tiki q=twig r=tine] + +"wutlaz" is a synthetic, internal rune that selects a case in q for +the actual type of p. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtpm p=tusk] + +?& ("wutpam") is a synthetic hoon that computes the "and" of the +loobeans in p. + + Tall + ?& i.p + i.t.p + i.t.t.p + == + + Wide + ?&(i.p i.t.p i.t.t.p) + + Irregular + none + + Reduction + See ++open + + [%wtpt p=wing q=twig r=twig] + +?@ ("wutpat") is a synthetic hoon that produces q if p is an +atom, r otherwise. + + Tall + Kingside + ?@ p + q + r + + Queenside + ?@ p + q + r + + Wide + ?@(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtpz p=tiki q=twig r=twig] + +"wutpaz" is a synthetic hoon that produces q if p is an atom, r +otherwise. + + Tall + ?@ p + q + r + + Wide + ?@(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtsg p=wing q=twig r=twig] + +?~ ("wutsig") is a synthetic rune that produces q if p is ~, r +otherwise. + + Tall + ?~ p + q + r + + Wide + ?~(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtsz p=tiki q=twig r=twig] + +"wutsaz" is a synthetic internal rune that produces q if p is ~, +r otherwise. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtts p=tile q=wing] + +?= ("wuttis") is a natural rune that produces true if the leg at +wing q is in tile p. + + Tall + ?= p + q + + Wide + ?=(p q) + + Irregular + none + + Reduction + none, natural + + [%wtzp p=twig] + +?! ("wutzap") is a synthetic rune that produces the logical "not" +of p. + + Tall + ?! p + + Wide + ?!(p) + + Irregular + !p + + Reduction + See ++open + + [%zpcb p=spot q=twig] +XX tall/wide form +!_ ("zapcab") is a natural rune that puts debugging information +in the stack trace. + + Tall + + Wide + + Irregular + none + + Reduction + none, natural + + [%zpcm p=twig q=twig] + +!, ("zapcom") is a natural rune that inserts twig q as a +constant, typed with the type of twig p. + + Tall + !, p + q + + Wide + !,(p q) + + Irregular + none + + Reduction + none, natural + + [%zpcn ~] +XX determine function +!% ("zapcen") + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%zpfs p=twig] +XX tall/wide +!/ ("zapfas") is a natural rune that should never be compiled. +When compiled with error checking turned on, it reports its +subject as an error. + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%zpgr p=twig] + +!> ("zapgar") is a synthetic rune that produces a vase (a +[type noun] cell) with the value p. + + Tall + !> p + + Wide + !>(p) + + Irregular + none + + Reduction + See ++open + + [%zpsm p=twig q=twig] + +!; ("zapsem") is a natural rune that produces the product of twig +q as a [type noun] pair, with twig p defining the type of the type. + + Tall + !; p + q + + Wide + !;(p q) + + Irregular + none + + Reduction + none, natural + + [%zpts p=twig] + +!= ("zaptis") is a natural rune that produces the formula of twig +p as a noun. + + Tall + != p + + Wide + !=(p) + + Irregular + none + + Reduction + none, natural + + [%zpwt p=$|(p=@ [p=@ q=@]) q=twig] + +!? ("zapwut") is a synthetic rune that enforces a Hoon version +restriction. + + Tall + !? p + q + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%zpzp ~] + +!! ("zapzap") is a natural rune that always causes a crash when +executed. + + Tall + none + + Wide + !! + + Irregular + none + + Reduction + none, natural + +--- + diff --git a/main/pub/src/doc/ref/hoon/lex-tile.md b/main/pub/src/doc/ref/hoon/lex-tile.md new file mode 100644 index 000000000..7080fb0cb --- /dev/null +++ b/main/pub/src/doc/ref/hoon/lex-tile.md @@ -0,0 +1,2612 @@ +Lexicon +======= + +Atom Syntax +---------- + + +###Canonical Atom Odors + +An odor is an atom format that specifies an atomic subtype. + +``` +@c UTF-32 codepoint +@d date + @da absolute date + @dr relative date (ie, timespan) +@f yes or no (inverse boolean) +@n nil +@p phonemic base +@r IEEE floating-point + @rd double precision (64 bits) + @rh half precision (16 bits) + @rq quad precision (128 bits) + @rs single precision (32 bits) +@s signed integer, sign bit low + @sb signed binary + @sd signed decimal + @sv signed base32 + @sw signed base64 + @sx signed hexadecimal +@t UTF-8 text (cord) + @ta ASCII text (span) + @tas ASCII symbol (term) +@u unsigned integer + @ub unsigned binary + @ud unsigned decimal + @uv unsigned base32 + @uw unsigned base64 + @ux unsigned hexadecimal +``` + +###Unsigned decimal, @ud + +Hoon's unsigned decimal format is the normal Continental syntax. It differs +from the Anglo-American only in the use of periods, rather than commas, between +groups of 3: + + ~zod/try=> 19 + 19 + ~zod/try=> 1.024 + 1.024 + +An unsigned decimal not broken into groups is a syntax error. Also, whitespace +or even linebreaks can appear between the dot and the next group. + + ~zod/try=> 65. 536 + 65.536 + +###Unsigned hexadecimal, @ux + +@ux has the same syntax as @ud, except that it's prefixed by 0x and uses groups +of four. Hex digits are lowercase only. + + ~zod/try=> 0x0 + 0x0 + ~zod/try=> `@ud`0x17 + 23 + +###Unsigned base64 and base32, @uv, @uw + +The prefix is 0w for base64 and 0v for base32. The digits for @uw are, in +order: 0-9, a-z, A-Z, -, ~: + + ~zod/try=> `@ud`0w- + 62 + +For @uv, the digits are 0-9, a-v. + +Signed integers, @sd, @sx, @sw, @sv, @sb + +Obviously, without finite-sized integers, the sign extension trick does not +work. A signed integer in Hoon is a different way to use atoms than an unsigned +integer; even for positive numbers, the signed integer cannot equal the +unsigned. + +The prefix for a negative signed integer is a single - before the unsigned +syntax. The prefix for a positive signed integer is --. The sign bit is the low +bit: + + ~zod/try=> -1 + -1 + ~zod/try=> --1 + --1 + ~zod/try=> `@ud`-1 + 1 + ~zod/try=> `@ud`--1 + 2 + ~zod/try=> `@ud`-2 + 3 + ~zod/try=> `@ud`--2 + 4 + ~zod/try=> `@ux`-0x10 + 0x1f + ~zod/try=> `@ux`--0x10 + 0x20 + ~zod/try=> `@ud`--0w- + 124 + ~zod/try=> `@sw`124 + --0w- + +###Absolute date, @da + +Urbit dates represent 128-bit chronological time, with 2^64 seconds from the +start of the universe to the end. 2^127 is 3:30:08 PM on December 5, AD 226, +for reasons not clear or relevant: + + ~zod/try=> `@da`(bex 127) + ~226.12.5..15.30.08 + + ~zod/try=> `@da`(dec (bex 127)) + ~226.12.5..15.30.07..ffff.ffff.ffff.ffff + +The time of day and/or second fragment is optional: + + ~zod/try=> `@ux`~2013.12.7 + 0x8000.000d.2140.7280.0000.0000.0000.0000 + + ~zod/try=> `@ux`~2013.12.7..15.30.07 + 0x8000.000d.2141.4c7f.0000.0000.0000.0000 + + ~zod/try=> `@ux`~2013.12.7..15.30.07..1234 + 0x8000.000d.2141.4c7f.1234.0000.0000.0000 + +We also do BC: + + ~zod/try=> `@ux`~226-.12.5 + 0x7fff.fffc.afb1.b800.0000.0000.0000.0000 + +The semantics of the time system are that UGT (Urbit Galactic Time) is GMT/UTC +as of leap second 25. UGT is chronological and will never add leap seconds, +even if UTC continues this mistake. If a gap appears, it must be resolved in +the presentation layer, with timezones and other human curiosities. + +See section 2cH of the source for more details. + +###Relative date, @dr + +It's also nice to have a syntax for basic time intervals: + + ~zod/try=> `@ux`~s1 + 0x1.0000.0000.0000.0000 + + ~zod/try=> `@ux`~m1 + 0x3c.0000.0000.0000.0000 + + ~zod/try=> (div ~m1 ~s1) + 60 + + ~zod/try=> (div ~h1 ~m1) + 60 + + ~zod/try=> (div ~h1 ~s1) + 3.600 + + ~zod/try=> (div ~d1 ~h1) + 24 + + ~zod/try=> `@da`(add ~2013.11.30 ~d1) + ~2013.12.1 + +There are no @dr intervals under a second or over a day. Since the resolution +is so high, though, (div ~s1 1.000.000) produces a pretty accurate microsecond. + +###Loobean, @f + +A loobean, or just bean, is 0 or 1. 0 is yes, 1 is no: + + ~zod/try=> `@ud`.y + 0 + ~zod/try=> `@ud`.n + 1 + +###Nil, @n + +Nil indicates an absence of information, as in a list terminator. The only +value is ~, 0. + + ~zod/try=> `@ud`~ + 0 + +###Unicode text, @t + +@t is a sequence of UTF-8 bytes, LSB first - sometimes called a cord. For +lowercase numbers and letters, the canonical syntax is ~~text: + + ~zod/try=> ~~foo + 'foo' + +Note that the prettyprinter makes an unprincipled exception and prints the text +in a noncanonical format: + + ~zod/try=> `@ux`~~foo + 0x6f.6f66 + +We want to be able to encode an arbitrary Unicode string as a single URL-safe +token, using no punctuation but .~-, in @t. Space is ., . is ~., ~ is ~~, - is +-: + + ~zod/try=> ~~foo.bar + 'foo bar' + ~zod/try=> ~~foo.bar~.baz~~moo-hoo + 'foo bar.baz~moo-hoo' + +For all other ASCII/Unicode characters, insert the Unicode codepoint in +lower-case hexadecimal, followed by .. For example, for U+2605 "BLACK STAR", +write: + + ~zod/try=> ~~foo~2605.bar + 'foo★bar' + +This UTF-32 codepoint is of course converted to UTF-8: + + ~zod/try=> `@ux`~~foo~2605.bar + 0x72.6162.8598.e26f.6f66 + +###URL-safe ASCII text, @ta + +@ta encodes the ASCII subset that all canonical atom syntaxes restrict +themselves to. The prefix is ~.. There are no escape sequences except ~~, which +means ~, and ~-, which means \_. - and . encode themselves. No other characters +besides numbers and lowercase letters need apply. + + ~zod/try=> `@t`~.foo + 'foo' + ~zod/try=> `@t`~.foo.bar + 'foo.bar' + ~zod/try=> `@t`~.foo~~bar + 'foo~bar' + ~zod/try=> `@t`~.foo~-bar + 'foo_bar' + ~zod/try=> `@t`~.foo-bar + 'foo-bar' + +A @ta atom is called a span. + +###Codepoint, @c + +Normally when we build atoms of Unicode text, we use a UTF-8 bytestream, LSB +first. But sometimes it's useful to build atoms of one or more UTF-32 words. + +The codepoint syntax is the same as @t, except with a ~- prefix. Let's repeat +our examples, with hex display: + + ~zod/try=> `@ux`~-foo + 0x6f.0000.006f.0000.0066 + + ~zod/try=> `@ux`~-foo.bar + 0x72.0000.0061.0000.0062.0000.0020.0000.006f.0000.006f.0000.0066 + +###Phonemic, @p + +We've seen @p used for ships, of course. But it's not just for ships - it's for +any short number optimized for memorability, not for arithmetic. @p is great +for checksums, for instance. + +That said, @p is subtly customized for the sociopolitical design of Urbit as a +digital republic. For example, one feature we don't want is the ability to see +at a glance which carrier and cruiser issued a destroyer. Consider the carrier +0x21: + + ~zod/try=> `@p`0x21 + ~mep + +It issues 255 cruisers, including 0x4321: + + ~zod/try=> `@p`0x4321 + ~pasnut + +Which issues 65.535 destroyers, including 0x8765.4321 and several successors: + + ~zod/try=> `@p`0x8765.4321 + ~famsyr-dirwes + ~zod/try=> `@p`0x8766.4321 + ~lidlug-maprec + ~zod/try=> `@p`0x8767.4321 + ~tidlus-roplen + ~zod/try=> `@p`0x8768.4321 + ~lisnel-lonbet + +Of course, anyone who can juggle bits can see that ~famsyr-dirwes is a close +cousin of ~lidlug-maprec. But she actually has to juggle bits to do it. +Obfuscation does not prevent calculated associations, just automatic ones. + +But at the yacht level, we actually want to see a uniform 32-bit space of +yachts directly associated with the destroyer: + + ~zod/try=> `@p`0x9.8765.4321 + ~talfes-sibzod-famsyr-dirwes + ~zod/try=> `@p`0xba9.8765.4321 + ~tacbep-ronreg-famsyr-dirwes + ~zod/try=> `@p`0xd.cba9.8765.4321 + ~bicsub-ritbyt-famsyr-dirwes + ~zod/try=> `@p`0xfed.cba9.8765.4321 + ~sivrep-hadfeb-famsyr-dirwes + +###IPv4 and IPv6 addresses, @if, @is + +Urbit lives atop IP and would be very foolish to not support a syntax for the +large atoms that are IPv4 and IPv6 addresses. + +@if is the standard IPv4 syntax, prefixed with .: + + ~zod/try=> `@ux`.127.0.0.1 + 0x7f00.0001 + +@is is the same as @if, but with 8 groups of 4 hex digits: + + ~zod/try=> `@ux`.dead.beef.0.cafe.42.babe.dead.beef + 0xdead.beef.0000.cafe.0042.babe.dead.beef + + +###Floating Point, @rs, @rd, @rq, @rh + +The syntax for a single-precision float is the normal English syntax, with a . prefix: + + .6.2832 :: τ as @rs + .-6.2832 :: -τ as @rs + .~6.2832 :: τ as @rd + .~-6.2832 :: -τ as @rd + .~~6.2832 :: τ as @rh + .~~~6.2832 :: τ as @rq + +(Hoon is a Tauist language and promotes International Tau Day.) + +###Transparent cell syntax + +By adding _, we can encode arbitrary nouns in our safe subset. The prefix to a +canonical cell is ._; the separator is _; the terminator is __. Thus: + + ~zod/try=> ._3_4__ + [3 4] + + ~zod/try=> :type; ._.127.0.0.1_._0x12_19___~tasfyn-partyv__ + [.127.0.0.1 [0x12 19] ~tasfyn-partyv] + [@if [@ux @ud] @p] + +Those who don't see utility in this strange feature have perhaps never needed +to jam a data structure into a URL. + +###Opaque noun syntax + +Speaking of jam, sometimes we really don't care what's inside our noun. Then, +the syntax to use is a variant of @uw prefixed by ~, which incorporates the +built-in jam and cue marshallers: + + ~zod/try=> (jam [3 4]) + 78.241 + ~zod/try=> `@uw`(jam [3 4]) + 0wj6x + ~zod/try=> (cue 0wj6x) + [3 4] + ~zod/try=> ~0wj6x + [3 4] + +###Noncanonical syntaxes + +These are syntaxes for constants which don't fit the canonical character-set +constraints. + +####Hoon symbol, @tas + +@tas, a term, is our most exclusive odor. The only characters permitted are +lowercase ASCII, - except as the first or last character, and 0-9 except as the +first character. + +The syntax for @tas is the text itself, always preceded by %. This means a term +is always cubical. You can cast it to @tas if you like, but we just about +always want the cube: + + ~zod/try=> %dead-fish9 + %dead-fish9 + + ~zod/try=> -:!>(%dead-fish9) + [%cube p=271.101.667.197.767.630.546.276 q=[%atom p=%tas]] + +The empty @tas has a special syntax, $: + + ~zod/try=> %$ + %$ + +A term without % is not a constant, but a name: + + ~zod/try=> dead-fish9 + ! -find-limb.dead-fish9 + ! find-none + ! exit + +####Loobeans, @f + + .y is a little cumbersome, so we can say & and |. The % prefix cubes as usual. + + ~zod/try=> `@ud`& + 0 + ~zod/try=> `@ud`| + 1 + +####Cords, @t + +The canonical ~~ syntax for @t, while it has its place, is intolerable in a +number of ways - especially when it comes to escaping capitals. So @t is both +printed and parsed in a conventional-looking single-quote syntax: + + ~zod/try=> 'foo bar' + 'foo bar' + ~zod/try=> `@ux`'foo bar' + 0x72.6162.206f.6f66 + Escape ' with \: + + ~zod/try=> 'Foo \'bar' + 'Foo \'bar' + ~zod/try=> `@ux`'\'' + 0x27 + +####Strings + +Text in Hoon is generally manipulated in two ways, depending on what you're +doing: as an atomic cord/span/term, or as a tape which is a list of bytes (not +codepoints). + +To generate a tape, use double quotes: + + ~zod/try=> "foo" + "foo" + ~zod/try=> `*`"foo" + [102 111 111 0] + +We're getting off the constant reservation, but strings also interpolate with curly-braces: + + ~zod/try=> "hello {(weld "wor" "ld")} is a fun thing to say" + "hello world is a fun thing to say" + +And they can be joined across space or lines with a .: + + ~zod/try=> "hello"."world" + "helloworld" + ~zod/try=> "hello". "world" + "helloworld" + +Runes: + + | bar core construction + |_ dry %gold door + |% generic %gold core + |. dry %gold trap + |/ vulcanized gold door + |^ kick a %gold book + |- kick a %gold trap + |+ dry %iron gate + |* vulcanized wet gate + |= dry %gold gate + |? dry %lead trap + + $ buc tiles and tiling + $_ bunt a tile + $, clam a tile + $@ whip a wing into a tile + $* bunt a tile statically + $! bunt an axil + + Tile runes: + $^ plant a %herb + $: build a tile + $= plant a %bark + $& plant a %bush + $? plant a %fern + $% plant a %kelp + $| plant a %reed + @ atom axil + ^ cell axil + * noun axil + ? bean axil + ~ null axil + + % cen invocations + %_ invoke with changes and cast + %: pull %$ of a door with a sample + %. inverse order %- + %- slam a core with a sample + %* + %^ + %+ + %~ + %= + + : col tuples + :_ reverse pair [q p] + :% + :/ + :^ + :- + :+ + :~ + :* + + . dot nock operators + .^ + .+ + .* + .= + .? + + ^ ket type conversions + ^| + ^. + ^+ + ^- + ^& + ^~ + ^= + ^? + + ; sem miscellaneous macros + ;: + ;. + ;" + ;~ + ;; + + ~ sig hints + ~| + ~_ + ~% + ~/ + ~< + ~> + ~$ + ~+ + ~& + ~= + ~? + ~! + + = tis compositions + =| + =: + =% + =. + =/ + => + =< + =- + =^ + =+ + =& + =@ + =* + =~ + + ? wut conditionals, booleans, tests + ?| + ?- + ?: + ?. + ?^ + ?> + ?< + ?+ + ?& + ?~ + ?= + ?! + + ! zap special operations + !: + !_ + !, + !% + !/ + !; + !? + !! + +Wing Runes + +Limbs + Names + a + ^a + + Axes + . + +3 + &3 + ->- + +Wings: concatenate limbs separated by . + +Punctuation runes + +++ dry arm ++- wet arm + +== terminate list +-- terminate map or set + + +Irregular Rune Forms + +,p $,(p) +*p $*(p) +_p $_(p) +p@q $@(p q) +!p ?!(p) +&(p q) ?&(p q) +|(p q) ?|(p q) +`p`q ^-(p q) +p=q ^=(p q) +~[p q] :~(a b) +[p q]~ :~(a) +`[p] [~ p] +p^q [p q] +[p q] :*(p) ++(p) .+(p) +=(p q) .=(p) +p:q =<(p q) +p(q r) %=(p q r) +(p list) %-(p) +~(p q r) %~(p q r) +>p< #<(p) +

#>(p) +:(p q) ;:(p q) + +Twigs +----- + +There are 112 cases of ++twig + + [p=twig q=twig] + +A twig can be a pair of twigs. + + [%$ p=axis] + +Refers to a nock axis. + + [%bccb p=tile] + +$_ ("buccab") is a synthetic hoon that produces the bunt (default +value) for p. + + Tall + $_ p + + Wide + $_(p) + + Irregular + _p + + Reduction + See ++open + + [%bccm p=tile] + +$, ("buccom") is a synthetic rune that produces a normalizing gate +(clam) for p. + + Talln + $, p + + Wide + none + + Irregular + ,p + + Reduction + ~(clam al p) + + See ++clam in ++al. + + [%bcpt p=wing q=tile] + +$@ ("bucpat") is a (just barely) natural hoon that whips wing p +into tile q. + + Tall + $@ p + q + + Wide + $@(p q) + + Irregular + p@q + + Reduction + none, natural + + [%bctr p=tile] + +$* ("buctar") is a synthetic rune that produces the bunt (default +value) for p as a compile-time constant. + + Tall + $* p + + Wide + $*(p) + + Reduction + ^~ ~(bunt al p) + + See ++bunt in al. + + [%bczp p=base] + +$! ("buczap") is a synthetic internal rune that produces the bunt +(default value) for [%axil p]. + + Reduction + See ++open + + [%brcb p=tile q=(map term foot)] + +|_ ("barcab") is a synthetic rune that produces a %gold tray with +sample p, arms q. q is an associative array of names and +expressions, each pair of which is called an arm. After any number +of dry (%ash, ++) and/or wet (%elm, +-) arms, the array is +terminated with -- + + Tall + |_ p + ++ p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brcn p=(map term foot)] + +|% ("barcen") is a natural rune that produces a %gold core from an +associative array of names and expressions, each pair of which is +called an arm. After any number of dry (%ash, ++) and/or wet (%elm, ++-) arms, the array is terminated with -- + + Tall + |% + ++ p.n.q + q.n.q + +- p.n.l.q + q.n.l.q + -- + + Wide + none + + Irregular + none + + Reduction + none, natural + + [%brdt p=twig] + +|. ("bardot") is a synthetic rune that produces a dry %gold trap +from twig p. + + Tall + |. p + + Wide + |.(p) + + Irregular + none + + Reduction + See ++open + + [%brfs p=tile q=(map term foot)] + +|/ ("barfas") is a synthetic rune that produces a vulcanized %gold +tray with arms q, sample p. + + Tall + |/ p + +- p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brkt p=twig q=(map term foot)] + +|^ ("barket") is a synthetic rune that produces a %gold book with +arms q, with p as %$, and kicks it. + + Tall + |^ p + ++ p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brhp p=twig] + +|- ("barhep") is a synthetic rune that produces a dry %gold trap +from twig p, and kicks it. + + Tall + |- + p + + Wide + |-(p) + + Irregular + none + + Reduction + See ++open + + [%brls p=tile q=twig] + +|+ ("barlus") is a synthetic rune that produces a dry %iron gate +with arm q, sample p. + + Tall + |+ p + q + + Wide + |+(p q) + + Irregular + none + + Reduction + See ++open + + [%brpt p=tile q=tile r=twig] + + XX not used + + [%brtr p=tile q=twig] + +|* ("bartar") is a synthetic rune that produces a vulcanized wet +gate with arm q, sample p. + + Tall + |* p + q + + Wide + |*(p q) + + Irregular + none + + Reduction + See ++open + + [%brts p=tile q=twig] + +|= ("bartis") is a synthetic hoon that produces a dry %gold gate +with arm q, sample p. + + Tall + |= p + q + + Wide + |=(p q) + + Irregular + none + + Reduction + See ++open + + [%brwt p=twig] + +|? ("barwut") is a synthetic rune that produces a dry %lead trap. + + Tall + |? p + + Wide + |?(p) + + Irregular + none + + Reduction + See ++open + + [%clcb p=twig q=twig] + +:_ ("colcab") is a synthetic rune that produces the cell [q p]. + + Tall + :_ p + q + + Wide + :_(p q) + + Irregular + none + + Reduction + See ++open + + [%clcn p=tusk] + +:% ("colcen") is a synthetic rune that produces a cell [[p ~] ~] +from a list of twigs p, terminated by a == + + Tall + :% i.p + i.t.p + i.t.t.p + == + + Wide + :%(i.p i.t.p i.t.t.p) + + Irregular + %[i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%clfs p=twig] + +:/ ("colfas") is a synthetic rune that, given a twig p, produces +[%$ [%$ p ~] ~], i.e., [0 [0 p 0] 0]. Used in practice only in +string interpolation. + + Tall + :/ p + + Wide + :/(p) + + Irregular + none + + Reduction + See ++open + + [%clkt p=twig q=twig r=twig s=twig] + +:^ ("colket") is a synthetic rune that produces a cell [p q r s] +from twigs p, q, r, and s. + + Tall + :^ p + q + r + s + + Wide + :^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%clhp p=twig q=twig] + +:- ("colhep") is a synthetic rune that produces the cell [p q] from +twigs p and q. + + Tall + :- p + q + + Wide + :-(p q) + + Irregular + [p q] + + Reduction + See ++open + + [%clls p=twig q=twig r=twig] + +:+ ("collus") is a synthetic rune that produces a cell [p q r] from +twigs p, q, and r. + + Tall + :+ p + q + r + + Wide + :+(p q r) + + Irregular + none + + Reduction + See ++open + + [%clsg p=tusk] + +:~ ("colsig") is a synthetic rune that produces a null-terminated +tuple of a list of twigs p. + + Tall + :~ i.p + i.t.p + i.t.t.p + == + + Wide + :~(i.p i.t.p i.t.t.p) + + Irregular + ~[i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%cltr p=tusk] + +:* ("coltar") is a synthetic hoon that produces a tuple from p, a +list of twigs. + + Tall + :* i.p + i.t.p + i.t.t.p + == + + Wide + :*(i.p i.t.p i.t.t.p) + + Irregular + [i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%clzz p=tusk] + +"colzaz" is a synthetic internal rune that promotes its tusk p +within a %clsg or %cltr tusk. + + Not used at present. + + [%cncb p=wing q=tram] + +%_ ("cencab") is a synthetic rune that evaluates the wing p with +the changes specified in tram q, then casts the product back to p. + + Tall + %_ p + p.i.q q.i.q + p.i.t.q q.i.t.q + == + + Wide + %_(p p.i.q q.i.q, p.i.t.q q.i.t.q) + + Irregular + none + + Reduction + See ++open + + [%cncl p=twig q=twig] + +%: ("cencol") is a synthetic rune that pulls %$ from the twig p +with the with its sample set to q. + + Tall + %: p + q + + Wide + %:(p q) + + Irregular + none + + Reduction + See ++open + + [%cndt p=twig q=twig] + +%. ("cendot") is a synthetic rune that slams the gate q with +[%cltr p]. The dual of %cnhp. + + Tall + %. p + q + + Wide + %.(p q) + + Irregular + none + + Reduction + %- q + p + + See ++open + + [%cnhp p=twig q=tusk] + +%- ("cenhep") is a synthetic rune that slams the gate p with +[%cltr q]. + + Tall + %- p + q + + Wide + %-(p q) + + Irregular + (p q) + + Reduction + See ++open + + [%cntr p=wing q=twig r=tram] + +%* is a synthetic rune that pulls the wing p from tray q with changes r. + + Tall + %* p q + p.i.r q.i.r + p.i.t.r q.i.t.r + == + + Wide + %*(p q p.i.r q.i.r, p.i.t.r q.i.t.r) + + Irregular + none + + Reduction + See ++open + + [%cnkt p=twig q=twig r=twig s=twig] + +%^ ("cenket") is a synthetic rune that slams gate p with [%cntr q r s]. + + Tall + %^ p + q + r + s + + Wide + %^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%cnls p=twig q=twig r=twig] + +%+ ("cenlus") is a synthetic rune that slams gate p with [%cntr q r]. + + Tall + %+ p + r + s + + Wide + %+(p q r) + + Irregular + none + + Reduction + See ++open + + [%cnsg p=wing q=twig r=twig] + +%~ ("censig") is a synthetic rune that pulls p from the tray q with its +sample set to r. + + Tall + %~ p + q + r + + Wide + %~(p q r) + + Irregular + ~(p q r) + + Reduction + See ++open + + [%cnts p=wing q=tram] + +%= ("centis") is a natural rune that evaluates p with the changes +specified in q. + + Tall + %= p + p.i.q q.i.q + p.i.t.q q.i.t.q + == + + Wide + %=(p p.i.q q.i.q, p.i.t.q q.i.t.q) + + Irregular + p(p.i.q q.i.q, p.i.t.q q.i.t.q) + + Reduction + See ++open + + [%cnzy p=term] + +"cenzey" is a synthetic internal rune that pulls limb p from the subject. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%cnzz p=wing] + +"cenzaz" is a synthetic internal rune that pulls wing p from the subject. + + Form + none, internal + + Reduction + See ++open + + [%dtkt p=twig] + +.^ ("dotket") is a natural rune that generates Nock operator 11, which in +virtual userspace Nock (++mock) loads a file from the global namespace. + + Tall + .^ p + + Wide + .^(p) + + Irregular + ^:type/path + + ^/path + + Reduction + none, natural + + [%dtls p=twig] + +.+ ("dotlus") is a natural rune that generates Nock operator 4, which +increments an atomic operand. + + Tall + .+ p + + Wide + .+(p) + + Irregular + +(p) + + Reduction + none, natural + + [%dtzy p=term q=@] + +"dotzey" is a natural internal rune that produces a non-cubed atomic +constant of odor p and value q. + + Tall/Wide/Irregular + none, internal + + Reduction + none, natural + + [%dtzz p=term q=*] + +"dotzaz" is a natural internal rune that produces a cubed noun constant of +value q and odor p, if q is an atom. + + Tall/Wide/Irregular + none, internal + + Reduction + none, natural + + [%dttr p=twig q=twig] + +.* ("dottar") is a natural rune that calculates the Nock of subject p, +formula q. + + Tall + .* p + q + + Wide + .*(p q) + + Irregular + none + + Reduction + none, natural + + [%dtts p=twig q=twig] + +.= ("dottis") is a natural rune that applies Nock 5 (equals) to determine +if the products of p and q are equivalent. + + Tall + .= p + q + + Wide + .=(p q) + + Irregular + =(p q) + + Reduction + none, natural + + [%dtwt p=twig] + +.? ("dotwut") is a natural hoon that applies Nock 3 to a noun: if the +noun is a cell, it returns the loobean & (true); if the noun is an atom, +it returns the loobean | (false). + + Tall + .? p + + Wide + .?(p) + + Irregular + none + + Reduction + none, natural + + [%hxgl p=tusk] + +#< ("haxgal") is a synthetic rune that slams the assumed gate noah on +[%zpgr %cntr p]. See the Biblical names. + + Tall/Wide + none + + Irregular + >i.p i.t.p i.t.t.p< + + Reduction + See ++open + + [%hxgr p=tusk] + +#> ("haxgar") is a synthetic rune that slams the assumed gate cain on +[%zpgr %cntr p]. See the Biblical names. + + Tall/Wide + none + + Irregular + + + Reduction + See ++open + + [%ktbr p=twig] + +^| ("ketbar") is a natural rune that converts a %gold core into an %iron +core. See geometric polymorphism. + + Tall + ^| p + + Wide + ^|(p) + + Irregular + none + + Reduction + none, natural + + [%ktdt p=twig q=twig] + +^. ("ketdot") is a synthetic rune that casts q to the type of (p q). + + Tall + ^. p + q + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%ktls p=twig q=twig] + +^+ ("ketlus") is a natural rune that casts the product of q to the +type of p, verifying that it contains the type of q. + + Tall + +^ p + q + + Wide + ^+(p q) + + Irregular + none + + Reduction + none, natural + + [%kthp p=tile q=twig] + +^- ("kethep") is a synthetic rune that casts q to ~(bunt al p), +i.e., the icon of p. + + Tall + ^- p + q + + Wide + ^-(p q) + + Irregular + `p`q + + Reduction + See ++open + + [%ktpm p=twig] + +^& ("ketpam") is a natural rune that converts a %gold core to %zinc core. +See geometric polymorphism. + + Tall + ^& p + + Wide + ^&(p) + + Irregular + none + + Reduction + none, natural + + [%ktsg p=twig] + +^~ ("ketsig") is a natural rune that tries to execute p statically at +compile time; if this fails, p remains dynamic. + + Tall + ^~ p + + Wide + ^~(a) + + Irregular + none + + Reduction + none, natural + + [%ktts p=toga q=twig] + +^= ("kettis") is a natural rune that wraps q in the toga p. The +toga is a powerful naming device that can assign an entire name +tree to a properly typed result. For instance, if foo produces +an unlabeled tuple [x y z], [a b=[c d]]=foo produces +[a=x b=[c=y d=z]]. + + Tall + ^= p + q + + Wide + ^=(p q) + + Irregular + none + + Reduction + none, natural + + [%ktwt p=twig] + +^? ("ketwut") is a natural hoon that converts a %gold core into a +%lead core. See geometric polymorphism. + + Tall + ^? p + + Wide + ^?(p) + + Irregular + none + + Reduction + none, natural + + [%sgbr p=twig q=twig] + +~| ("sigbar") is a synthetic rune that presents the product of p +in the stack trace if q crashes. Only performed as needed. +Generates %cain - see the Biblical names. + + Tall + ~| p + q + + Wide + ~|(p q) + + Irregular + none + + Reduction + See ++open, ++feck + + [%sgcb p=twig q=twig] + +~_ ("sigcab") is a synthetic rune that inserts p, a trap producing a tank, +into the trace of q. + + Tall + ~_ p + q + + Wide + ~_(p q) + + Irregular + none + + Reduction + See ++open + + [%sgcn p=chum q=twig r=tyre s=twig] + +~% ("sigcen") is a synthetic rune that identifies a core for specific +optimization. See jet propulsion. + + Tall + ~% p + q + == + p.i.r q.i.r + p.i.t.r q.i.t.r + == + s + + ~% p + q + ~ + s + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%sgfs p=chum q=twig] + +~/ ("sigfas") is a synthetic rune that identifies an arm for specific +optimization. See jet propulsion. + + Tall + ~/ p + q + + Wide + ~/(p q) + + Irregular + none + + Reduction + See ++open + + [%sggl p=$|(term [p=term q=twig]) q=twig] + +~< ("siggal") is a synthetic rune that applies arbitrary hint p to +the product of q. Does not wake the hint engine until the +computation is finished. + + Tall + ~< p + q + + Wide + ~<(p q) + + Irregular + none + + Reduction + See ++open + + [%sggr p=$|(term [p=term q=twig]) q=twig] + +~> ("siggar") is a natural rune that applies arbitrary hint p to q. + + Tall + ~> p + q + + Wide + ~>(p q) + + Irregular + none + + Reduction + See ++open + + [%sgbc p=term q=twig] + +~$ ("sigbuc") is a synthetic rune that labels computation q as p +for profiling (not currently enabled). + + Tall + ~$ p + q + + Wide + ~$(p q) + + Irregular + none + + Reduction + See ++open + + [%sgls p=@ q=twig] + +XX Solve ~+ ("siglus") is a synthetic rune that memoizes computation q + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%sgpm p=@ud q=twig r=twig] + +~& ("sigpam") is a synthetic rune that prints q on the console +before computing r. p is the log priority 0-3, defaulting to 0. + + Tall + 0, debug + ~& q + r + + 1, notice + ~& > q + r + + 2, warning + ~& >> q + r + + 3, alarm + ~& >>> q + r + + Wide + ~&(>>> q r) + + Irregular + none + + Reduction + See ++open + + [%sgts p=twig q=twig] + +~= ("sigtis") is a synthetic rune that hints to the interpreter +that q may produce a noun equal to the already existing p, +avoiding duplication. + + Tall + ~= p + q + + Wide + ~=(p q) + + Irregular + none + + Reduction + See ++open + + [%sgwt p=@ud q=twig r=twig s=twig] + +~? ("sigwut") is a synthetic rune that prints r to the console +before computing s, iff q produces yes. p is the log priority, +0-3, 0 by default + + Tall + 0, debug + ~? q + r + s + + 1, notice + ~? > q + r + s + + 2, warning + ~? >> q + r + s + + 3, alarm + ~? >>> q + r + s + + Wide + ~?(>>> q r s) + + Irregular + none + + Reduction + See ++open + + [%sgzp p=twig q=twig] + +~! ("sigzap") is a natural rune for debugging uses only, +semantically equivalent to its own twig q. Should compilation +fail within q, ~! will show the type of p on the stacktrace. + + Tall + ~! p + q + + Wide + ~!(p q) + + Irregular + none + + Reduction + none, natural + + [%smcl p=twig q=tusk] + +;: ("semcol") is a synthetic gate that applies p, a binary gate, +to the n-ary tuple q. + + Tall + ;: p + i.q + i.t.q + i.t.t.q + == + + Wide + ;:(p i.q i.t.q i.t.t.q) + + Irregular + :(p i.q i.t.q i.t.t.q) + + Reduction + See ++open + + [%smdt p=twig q=tusk] +XX determine function + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smdq p=(list beer)] +XX determine if internal/external + +;" ("semdoq") is a synthetic rune used to make strings, +interpolated or not. + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smsg p=twig q=tusk] + +XX to do + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smsm p=twig q=twig] + +;; ("semsem") is a synthetic rune that types q as a fixpoint of p. +Semantically identical to ((hard p) q). + + Tall + ;; p + q + + Wide + ;;(p q) + + Irregular + none + + Reduction + See ++open + + [%tsbr p=tile q=twig] + +=| ("tisbar") is a synthetic rune that pushes ~(bunt al p) on the +subject and sends it to q. + + Tall + =| p + q + + Wide + =|(p q) + + Irregular + none + + Reduction + =+(_p q) + See ++open, ++bunt in ++al + + [%tscl p=tram q=twig] + +=: ("tiscol") is a synthetic rune that produces q with the subject +by p. Uses %cncb, and so cannot change the subject type. + + Tall + =: p.i.p q.i.p + p.i.t.p q.i.t.p + p.i.t.t.p q.i.t.t.p + == + q + + Wide + none + + Irregular + noen + + Reduction + See ++open + + [%tscn p=twig q=twig] +XX to do + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%tsdt p=wing q=twig r=twig] + +=. ("tisdot") is a synthetic rune that produces r with p in the +subject set to q. Uses %cncb, and so cannot change the subject + p. + + Tall + =. p + q + r + + =. p q + r + + Wide + =.(p q r) + + Irregular + none + + Reduction + See ++open + + [%tsfs p=twig q=twig] + XX not used + + [%tsgl p=twig q=twig] + +=< ("tisgal") is a synthetic rune that uses the product of q as +the subject of p. + + Tall + =< p + q + + Wide + =<(p q) + + Irregular + + Reduction + See ++open + + [%tshp p=twig q=twig] + +=- ("tishep") is a synthetic rune that pushes q on the subject +and sends it to p. Dual of =+ ("tislup") + + + Tall + =- p + q + + Wide + =- + + Irregular + none + + Reduction + See ++open + + [%tsgr p=twig q=twig] + +=> ("tisgar") is a natural rune that uses the product of p as the +subject of q. + + Tall + => p + q + + Wide + =>(p q) + + Irregular + none + + Reduction + none, natural + + [%tskt p=twig q=twig r=twig s=twig] + +=^ ("tisket") is a synthetic rune that handles a product which is +a cell of the new result, and a mutation to the subject. + + Tall + Kingside + =^ p + q + r + s + + Queenside + =^ p q + r + s + + Wide + =^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%tsls p=twig q=twig] + +=+ ("tislus") is a synthetic rune that pushes p on the subject +and sends it to q. Semantically equavlent to Nock 8.Dual of =- ("tishep") + + Tall + =+ p + q + + Wide + =+(p q) + + Irregular + none + + Reduction + See ++open + + [%tspm p=tile q=twig] + + XX not used + + [%tspt p=tile q=twig] + + XX not used + + [%tstr p=term q=wing r=twig] + +=* ("tistar") is a natural rune that creates a %bull, or alias, +type. + + Tall + =* p q + r + + Wide + =*(p q r) + + Irregular + none + + Reduction + none, natural + + [%tssg p=tusk] + +=~ ("tissig") is a synthetic rune that composes a list of twigs. + + Tall + Kingside + =~ i.p + i.t.p + i.t.t.p + == + + Queenside + =~ i.p + i.t.p + i.t.t.p + == + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%wtbr p=tusk] + +?| ("wutbar") is a synthetic rune that computes the "or" of the +loobeans in p. + + Tall + ?| i.p + i.t.p + i.t.t.p + == + + Wide + ?|(i.p i.t.p i.t.t.p) + + Irregular + |(i.p i.t.p i.t.t.p) + + Reduction + See ++open + + [%wthp p=wing q=tine] + +?- ("wuthep") is a synthetic rune that selects a case in q for +the actual type of p. + + Tall + Kingside + ?- p + p.i.q q.i.q + p.i.t.q q.i.t.q + p.i.t.t.q q.i.t.t.q + == + + Queenside + ?- p + p.i.q + q.i.q + p.i.t.q + q.i.t.q + p.i.t.t.q + q.i.t.t.q + == + + Wide + ?-(p p.i.q q.i.q, p.i.t.q q.i.t.q, p.i.t.t.q q.i.t.t.q) + + Irregular + none + + Reduction + See ++open + + [%wthz p=tiki q=tine] + +"wuthaz" is a synthetic internal rune that selects a case in q +for the actual type of p. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtcl p=twig q=twig r=twig] + +?: ("wutcol") is a natural rune that produces q if p is yes (&, 0), +or r if p is no (|, 1). + + Tall + ?: p + q + r + + Wide + ?:(p q r) + + Irregular + none + + Reduction + none, natural + + [%wtdt p=twig q=twig r=twig] + +?. ("wutdot") is a synthetic rune that prduces r if p is yes +(&, 0), of q if p is no (|, 1). + + Tall + ?. p + q + r + + Wide + ?:(p q r) + + Irregular + none + + Reduction + none, natural + + [%wtkt p=wing q=twig r=twig] + +?^ ("wutkey") is a synthetic rune that evaluates r if p is +equivalent to the bunt for its tile, otherwise q is evaluted. + + Tall + ?^ p + q + r + + Wide + ?^(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtkz p=tiki q=twig r=twig] + +"wutkaz" is a synthetic, internal rune that evaluates r if p is +equivalent to the bunt for its tile, otherwise q is evaluated. +See tikis. + + Tall + ?^ p + q + r + + Wide + ?^(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtgl p=twig q=twig] + +?< ("wutgal") is a synthetic hoon that produces q, asserting that +p is no (|, 1). + + Tall + ?< p + q + + Wide + ?<(p q) + + Irregular + none + + Reduction + See ++open + + [%wtgr p=twig q=twig] + +?> ("wutgar") is a synthetic hoon that produces q, asserting that +p is yes (&, 0). + + Tall + ?> p + q + + Wide + ?>(p q) + + Irregular + none + + Reduction + See ++open + + [%wtls p=wing q=twig r=tine] + +?+ ("wutlus") is a synthetic rune that selects a case in q for +the actual type of p. + + Tall + Kingside + ?+ p + q + p.i.r q.i.r + p.i.t.r q.i.t.r + p.i.t.t.r q.i.t.t.r + == + + Queenside + ?+ p + q + p.i.r + q.i.r + p.i.t.r + q.i.t.r + p.i.t.t.r + q.i.t.t.r + == + + Wide + ?+(p p.i.r q.i.r, p.i.t.r q.i.t.r, p.i.t.t.r q.i.t.t.r) + + Irregular + none + + Reduction + See ++open + + [%wtlz p=tiki q=twig r=tine] + +"wutlaz" is a synthetic, internal rune that selects a case in q for +the actual type of p. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtpm p=tusk] + +?& ("wutpam") is a synthetic hoon that computes the "and" of the +loobeans in p. + + Tall + ?& i.p + i.t.p + i.t.t.p + == + + Wide + ?&(i.p i.t.p i.t.t.p) + + Irregular + none + + Reduction + See ++open + + [%wtpt p=wing q=twig r=twig] + +?@ ("wutpat") is a synthetic hoon that produces q if p is an +atom, r otherwise. + + Tall + Kingside + ?@ p + q + r + + Queenside + ?@ p + q + r + + Wide + ?@(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtpz p=tiki q=twig r=twig] + +"wutpaz" is a synthetic hoon that produces q if p is an atom, r +otherwise. + + Tall + ?@ p + q + r + + Wide + ?@(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtsg p=wing q=twig r=twig] + +?~ ("wutsig") is a synthetic rune that produces q if p is ~, r +otherwise. + + Tall + ?~ p + q + r + + Wide + ?~(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtsz p=tiki q=twig r=twig] + +"wutsaz" is a synthetic internal rune that produces q if p is ~, +r otherwise. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtts p=tile q=wing] + +?= ("wuttis") is a natural rune that produces true if the leg at +wing q is in tile p. + + Tall + ?= p + q + + Wide + ?=(p q) + + Irregular + none + + Reduction + none, natural + + [%wtzp p=twig] + +?! ("wutzap") is a synthetic rune that produces the logical "not" +of p. + + Tall + ?! p + + Wide + ?!(p) + + Irregular + !p + + Reduction + See ++open + + [%zpcb p=spot q=twig] +XX tall/wide form +!_ ("zapcab") is a natural rune that puts debugging information +in the stack trace. + + Tall + + Wide + + Irregular + none + + Reduction + none, natural + + [%zpcm p=twig q=twig] + +!, ("zapcom") is a natural rune that inserts twig q as a +constant, typed with the type of twig p. + + Tall + !, p + q + + Wide + !,(p q) + + Irregular + none + + Reduction + none, natural + + [%zpcn ~] +XX determine function +!% ("zapcen") + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%zpfs p=twig] +XX tall/wide +!/ ("zapfas") is a natural rune that should never be compiled. +When compiled with error checking turned on, it reports its +subject as an error. + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%zpgr p=twig] + +!> ("zapgar") is a synthetic rune that produces a vase (a +[type noun] cell) with the value p. + + Tall + !> p + + Wide + !>(p) + + Irregular + none + + Reduction + See ++open + + [%zpsm p=twig q=twig] + +!; ("zapsem") is a natural rune that produces the product of twig +q as a [type noun] pair, with twig p defining the type of the type. + + Tall + !; p + q + + Wide + !;(p q) + + Irregular + none + + Reduction + none, natural + + [%zpts p=twig] + +!= ("zaptis") is a natural rune that produces the formula of twig +p as a noun. + + Tall + != p + + Wide + !=(p) + + Irregular + none + + Reduction + none, natural + + [%zpwt p=$|(p=@ [p=@ q=@]) q=twig] + +!? ("zapwut") is a synthetic rune that enforces a Hoon version +restriction. + + Tall + !? p + q + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%zpzp ~] + +!! ("zapzap") is a natural rune that always causes a crash when +executed. + + Tall + none + + Wide + !! + + Irregular + none + + Reduction + none, natural + +--- + diff --git a/main/pub/src/doc/ref/hoon/lex-twig.md b/main/pub/src/doc/ref/hoon/lex-twig.md new file mode 100644 index 000000000..7080fb0cb --- /dev/null +++ b/main/pub/src/doc/ref/hoon/lex-twig.md @@ -0,0 +1,2612 @@ +Lexicon +======= + +Atom Syntax +---------- + + +###Canonical Atom Odors + +An odor is an atom format that specifies an atomic subtype. + +``` +@c UTF-32 codepoint +@d date + @da absolute date + @dr relative date (ie, timespan) +@f yes or no (inverse boolean) +@n nil +@p phonemic base +@r IEEE floating-point + @rd double precision (64 bits) + @rh half precision (16 bits) + @rq quad precision (128 bits) + @rs single precision (32 bits) +@s signed integer, sign bit low + @sb signed binary + @sd signed decimal + @sv signed base32 + @sw signed base64 + @sx signed hexadecimal +@t UTF-8 text (cord) + @ta ASCII text (span) + @tas ASCII symbol (term) +@u unsigned integer + @ub unsigned binary + @ud unsigned decimal + @uv unsigned base32 + @uw unsigned base64 + @ux unsigned hexadecimal +``` + +###Unsigned decimal, @ud + +Hoon's unsigned decimal format is the normal Continental syntax. It differs +from the Anglo-American only in the use of periods, rather than commas, between +groups of 3: + + ~zod/try=> 19 + 19 + ~zod/try=> 1.024 + 1.024 + +An unsigned decimal not broken into groups is a syntax error. Also, whitespace +or even linebreaks can appear between the dot and the next group. + + ~zod/try=> 65. 536 + 65.536 + +###Unsigned hexadecimal, @ux + +@ux has the same syntax as @ud, except that it's prefixed by 0x and uses groups +of four. Hex digits are lowercase only. + + ~zod/try=> 0x0 + 0x0 + ~zod/try=> `@ud`0x17 + 23 + +###Unsigned base64 and base32, @uv, @uw + +The prefix is 0w for base64 and 0v for base32. The digits for @uw are, in +order: 0-9, a-z, A-Z, -, ~: + + ~zod/try=> `@ud`0w- + 62 + +For @uv, the digits are 0-9, a-v. + +Signed integers, @sd, @sx, @sw, @sv, @sb + +Obviously, without finite-sized integers, the sign extension trick does not +work. A signed integer in Hoon is a different way to use atoms than an unsigned +integer; even for positive numbers, the signed integer cannot equal the +unsigned. + +The prefix for a negative signed integer is a single - before the unsigned +syntax. The prefix for a positive signed integer is --. The sign bit is the low +bit: + + ~zod/try=> -1 + -1 + ~zod/try=> --1 + --1 + ~zod/try=> `@ud`-1 + 1 + ~zod/try=> `@ud`--1 + 2 + ~zod/try=> `@ud`-2 + 3 + ~zod/try=> `@ud`--2 + 4 + ~zod/try=> `@ux`-0x10 + 0x1f + ~zod/try=> `@ux`--0x10 + 0x20 + ~zod/try=> `@ud`--0w- + 124 + ~zod/try=> `@sw`124 + --0w- + +###Absolute date, @da + +Urbit dates represent 128-bit chronological time, with 2^64 seconds from the +start of the universe to the end. 2^127 is 3:30:08 PM on December 5, AD 226, +for reasons not clear or relevant: + + ~zod/try=> `@da`(bex 127) + ~226.12.5..15.30.08 + + ~zod/try=> `@da`(dec (bex 127)) + ~226.12.5..15.30.07..ffff.ffff.ffff.ffff + +The time of day and/or second fragment is optional: + + ~zod/try=> `@ux`~2013.12.7 + 0x8000.000d.2140.7280.0000.0000.0000.0000 + + ~zod/try=> `@ux`~2013.12.7..15.30.07 + 0x8000.000d.2141.4c7f.0000.0000.0000.0000 + + ~zod/try=> `@ux`~2013.12.7..15.30.07..1234 + 0x8000.000d.2141.4c7f.1234.0000.0000.0000 + +We also do BC: + + ~zod/try=> `@ux`~226-.12.5 + 0x7fff.fffc.afb1.b800.0000.0000.0000.0000 + +The semantics of the time system are that UGT (Urbit Galactic Time) is GMT/UTC +as of leap second 25. UGT is chronological and will never add leap seconds, +even if UTC continues this mistake. If a gap appears, it must be resolved in +the presentation layer, with timezones and other human curiosities. + +See section 2cH of the source for more details. + +###Relative date, @dr + +It's also nice to have a syntax for basic time intervals: + + ~zod/try=> `@ux`~s1 + 0x1.0000.0000.0000.0000 + + ~zod/try=> `@ux`~m1 + 0x3c.0000.0000.0000.0000 + + ~zod/try=> (div ~m1 ~s1) + 60 + + ~zod/try=> (div ~h1 ~m1) + 60 + + ~zod/try=> (div ~h1 ~s1) + 3.600 + + ~zod/try=> (div ~d1 ~h1) + 24 + + ~zod/try=> `@da`(add ~2013.11.30 ~d1) + ~2013.12.1 + +There are no @dr intervals under a second or over a day. Since the resolution +is so high, though, (div ~s1 1.000.000) produces a pretty accurate microsecond. + +###Loobean, @f + +A loobean, or just bean, is 0 or 1. 0 is yes, 1 is no: + + ~zod/try=> `@ud`.y + 0 + ~zod/try=> `@ud`.n + 1 + +###Nil, @n + +Nil indicates an absence of information, as in a list terminator. The only +value is ~, 0. + + ~zod/try=> `@ud`~ + 0 + +###Unicode text, @t + +@t is a sequence of UTF-8 bytes, LSB first - sometimes called a cord. For +lowercase numbers and letters, the canonical syntax is ~~text: + + ~zod/try=> ~~foo + 'foo' + +Note that the prettyprinter makes an unprincipled exception and prints the text +in a noncanonical format: + + ~zod/try=> `@ux`~~foo + 0x6f.6f66 + +We want to be able to encode an arbitrary Unicode string as a single URL-safe +token, using no punctuation but .~-, in @t. Space is ., . is ~., ~ is ~~, - is +-: + + ~zod/try=> ~~foo.bar + 'foo bar' + ~zod/try=> ~~foo.bar~.baz~~moo-hoo + 'foo bar.baz~moo-hoo' + +For all other ASCII/Unicode characters, insert the Unicode codepoint in +lower-case hexadecimal, followed by .. For example, for U+2605 "BLACK STAR", +write: + + ~zod/try=> ~~foo~2605.bar + 'foo★bar' + +This UTF-32 codepoint is of course converted to UTF-8: + + ~zod/try=> `@ux`~~foo~2605.bar + 0x72.6162.8598.e26f.6f66 + +###URL-safe ASCII text, @ta + +@ta encodes the ASCII subset that all canonical atom syntaxes restrict +themselves to. The prefix is ~.. There are no escape sequences except ~~, which +means ~, and ~-, which means \_. - and . encode themselves. No other characters +besides numbers and lowercase letters need apply. + + ~zod/try=> `@t`~.foo + 'foo' + ~zod/try=> `@t`~.foo.bar + 'foo.bar' + ~zod/try=> `@t`~.foo~~bar + 'foo~bar' + ~zod/try=> `@t`~.foo~-bar + 'foo_bar' + ~zod/try=> `@t`~.foo-bar + 'foo-bar' + +A @ta atom is called a span. + +###Codepoint, @c + +Normally when we build atoms of Unicode text, we use a UTF-8 bytestream, LSB +first. But sometimes it's useful to build atoms of one or more UTF-32 words. + +The codepoint syntax is the same as @t, except with a ~- prefix. Let's repeat +our examples, with hex display: + + ~zod/try=> `@ux`~-foo + 0x6f.0000.006f.0000.0066 + + ~zod/try=> `@ux`~-foo.bar + 0x72.0000.0061.0000.0062.0000.0020.0000.006f.0000.006f.0000.0066 + +###Phonemic, @p + +We've seen @p used for ships, of course. But it's not just for ships - it's for +any short number optimized for memorability, not for arithmetic. @p is great +for checksums, for instance. + +That said, @p is subtly customized for the sociopolitical design of Urbit as a +digital republic. For example, one feature we don't want is the ability to see +at a glance which carrier and cruiser issued a destroyer. Consider the carrier +0x21: + + ~zod/try=> `@p`0x21 + ~mep + +It issues 255 cruisers, including 0x4321: + + ~zod/try=> `@p`0x4321 + ~pasnut + +Which issues 65.535 destroyers, including 0x8765.4321 and several successors: + + ~zod/try=> `@p`0x8765.4321 + ~famsyr-dirwes + ~zod/try=> `@p`0x8766.4321 + ~lidlug-maprec + ~zod/try=> `@p`0x8767.4321 + ~tidlus-roplen + ~zod/try=> `@p`0x8768.4321 + ~lisnel-lonbet + +Of course, anyone who can juggle bits can see that ~famsyr-dirwes is a close +cousin of ~lidlug-maprec. But she actually has to juggle bits to do it. +Obfuscation does not prevent calculated associations, just automatic ones. + +But at the yacht level, we actually want to see a uniform 32-bit space of +yachts directly associated with the destroyer: + + ~zod/try=> `@p`0x9.8765.4321 + ~talfes-sibzod-famsyr-dirwes + ~zod/try=> `@p`0xba9.8765.4321 + ~tacbep-ronreg-famsyr-dirwes + ~zod/try=> `@p`0xd.cba9.8765.4321 + ~bicsub-ritbyt-famsyr-dirwes + ~zod/try=> `@p`0xfed.cba9.8765.4321 + ~sivrep-hadfeb-famsyr-dirwes + +###IPv4 and IPv6 addresses, @if, @is + +Urbit lives atop IP and would be very foolish to not support a syntax for the +large atoms that are IPv4 and IPv6 addresses. + +@if is the standard IPv4 syntax, prefixed with .: + + ~zod/try=> `@ux`.127.0.0.1 + 0x7f00.0001 + +@is is the same as @if, but with 8 groups of 4 hex digits: + + ~zod/try=> `@ux`.dead.beef.0.cafe.42.babe.dead.beef + 0xdead.beef.0000.cafe.0042.babe.dead.beef + + +###Floating Point, @rs, @rd, @rq, @rh + +The syntax for a single-precision float is the normal English syntax, with a . prefix: + + .6.2832 :: τ as @rs + .-6.2832 :: -τ as @rs + .~6.2832 :: τ as @rd + .~-6.2832 :: -τ as @rd + .~~6.2832 :: τ as @rh + .~~~6.2832 :: τ as @rq + +(Hoon is a Tauist language and promotes International Tau Day.) + +###Transparent cell syntax + +By adding _, we can encode arbitrary nouns in our safe subset. The prefix to a +canonical cell is ._; the separator is _; the terminator is __. Thus: + + ~zod/try=> ._3_4__ + [3 4] + + ~zod/try=> :type; ._.127.0.0.1_._0x12_19___~tasfyn-partyv__ + [.127.0.0.1 [0x12 19] ~tasfyn-partyv] + [@if [@ux @ud] @p] + +Those who don't see utility in this strange feature have perhaps never needed +to jam a data structure into a URL. + +###Opaque noun syntax + +Speaking of jam, sometimes we really don't care what's inside our noun. Then, +the syntax to use is a variant of @uw prefixed by ~, which incorporates the +built-in jam and cue marshallers: + + ~zod/try=> (jam [3 4]) + 78.241 + ~zod/try=> `@uw`(jam [3 4]) + 0wj6x + ~zod/try=> (cue 0wj6x) + [3 4] + ~zod/try=> ~0wj6x + [3 4] + +###Noncanonical syntaxes + +These are syntaxes for constants which don't fit the canonical character-set +constraints. + +####Hoon symbol, @tas + +@tas, a term, is our most exclusive odor. The only characters permitted are +lowercase ASCII, - except as the first or last character, and 0-9 except as the +first character. + +The syntax for @tas is the text itself, always preceded by %. This means a term +is always cubical. You can cast it to @tas if you like, but we just about +always want the cube: + + ~zod/try=> %dead-fish9 + %dead-fish9 + + ~zod/try=> -:!>(%dead-fish9) + [%cube p=271.101.667.197.767.630.546.276 q=[%atom p=%tas]] + +The empty @tas has a special syntax, $: + + ~zod/try=> %$ + %$ + +A term without % is not a constant, but a name: + + ~zod/try=> dead-fish9 + ! -find-limb.dead-fish9 + ! find-none + ! exit + +####Loobeans, @f + + .y is a little cumbersome, so we can say & and |. The % prefix cubes as usual. + + ~zod/try=> `@ud`& + 0 + ~zod/try=> `@ud`| + 1 + +####Cords, @t + +The canonical ~~ syntax for @t, while it has its place, is intolerable in a +number of ways - especially when it comes to escaping capitals. So @t is both +printed and parsed in a conventional-looking single-quote syntax: + + ~zod/try=> 'foo bar' + 'foo bar' + ~zod/try=> `@ux`'foo bar' + 0x72.6162.206f.6f66 + Escape ' with \: + + ~zod/try=> 'Foo \'bar' + 'Foo \'bar' + ~zod/try=> `@ux`'\'' + 0x27 + +####Strings + +Text in Hoon is generally manipulated in two ways, depending on what you're +doing: as an atomic cord/span/term, or as a tape which is a list of bytes (not +codepoints). + +To generate a tape, use double quotes: + + ~zod/try=> "foo" + "foo" + ~zod/try=> `*`"foo" + [102 111 111 0] + +We're getting off the constant reservation, but strings also interpolate with curly-braces: + + ~zod/try=> "hello {(weld "wor" "ld")} is a fun thing to say" + "hello world is a fun thing to say" + +And they can be joined across space or lines with a .: + + ~zod/try=> "hello"."world" + "helloworld" + ~zod/try=> "hello". "world" + "helloworld" + +Runes: + + | bar core construction + |_ dry %gold door + |% generic %gold core + |. dry %gold trap + |/ vulcanized gold door + |^ kick a %gold book + |- kick a %gold trap + |+ dry %iron gate + |* vulcanized wet gate + |= dry %gold gate + |? dry %lead trap + + $ buc tiles and tiling + $_ bunt a tile + $, clam a tile + $@ whip a wing into a tile + $* bunt a tile statically + $! bunt an axil + + Tile runes: + $^ plant a %herb + $: build a tile + $= plant a %bark + $& plant a %bush + $? plant a %fern + $% plant a %kelp + $| plant a %reed + @ atom axil + ^ cell axil + * noun axil + ? bean axil + ~ null axil + + % cen invocations + %_ invoke with changes and cast + %: pull %$ of a door with a sample + %. inverse order %- + %- slam a core with a sample + %* + %^ + %+ + %~ + %= + + : col tuples + :_ reverse pair [q p] + :% + :/ + :^ + :- + :+ + :~ + :* + + . dot nock operators + .^ + .+ + .* + .= + .? + + ^ ket type conversions + ^| + ^. + ^+ + ^- + ^& + ^~ + ^= + ^? + + ; sem miscellaneous macros + ;: + ;. + ;" + ;~ + ;; + + ~ sig hints + ~| + ~_ + ~% + ~/ + ~< + ~> + ~$ + ~+ + ~& + ~= + ~? + ~! + + = tis compositions + =| + =: + =% + =. + =/ + => + =< + =- + =^ + =+ + =& + =@ + =* + =~ + + ? wut conditionals, booleans, tests + ?| + ?- + ?: + ?. + ?^ + ?> + ?< + ?+ + ?& + ?~ + ?= + ?! + + ! zap special operations + !: + !_ + !, + !% + !/ + !; + !? + !! + +Wing Runes + +Limbs + Names + a + ^a + + Axes + . + +3 + &3 + ->- + +Wings: concatenate limbs separated by . + +Punctuation runes + +++ dry arm ++- wet arm + +== terminate list +-- terminate map or set + + +Irregular Rune Forms + +,p $,(p) +*p $*(p) +_p $_(p) +p@q $@(p q) +!p ?!(p) +&(p q) ?&(p q) +|(p q) ?|(p q) +`p`q ^-(p q) +p=q ^=(p q) +~[p q] :~(a b) +[p q]~ :~(a) +`[p] [~ p] +p^q [p q] +[p q] :*(p) ++(p) .+(p) +=(p q) .=(p) +p:q =<(p q) +p(q r) %=(p q r) +(p list) %-(p) +~(p q r) %~(p q r) +>p< #<(p) +

#>(p) +:(p q) ;:(p q) + +Twigs +----- + +There are 112 cases of ++twig + + [p=twig q=twig] + +A twig can be a pair of twigs. + + [%$ p=axis] + +Refers to a nock axis. + + [%bccb p=tile] + +$_ ("buccab") is a synthetic hoon that produces the bunt (default +value) for p. + + Tall + $_ p + + Wide + $_(p) + + Irregular + _p + + Reduction + See ++open + + [%bccm p=tile] + +$, ("buccom") is a synthetic rune that produces a normalizing gate +(clam) for p. + + Talln + $, p + + Wide + none + + Irregular + ,p + + Reduction + ~(clam al p) + + See ++clam in ++al. + + [%bcpt p=wing q=tile] + +$@ ("bucpat") is a (just barely) natural hoon that whips wing p +into tile q. + + Tall + $@ p + q + + Wide + $@(p q) + + Irregular + p@q + + Reduction + none, natural + + [%bctr p=tile] + +$* ("buctar") is a synthetic rune that produces the bunt (default +value) for p as a compile-time constant. + + Tall + $* p + + Wide + $*(p) + + Reduction + ^~ ~(bunt al p) + + See ++bunt in al. + + [%bczp p=base] + +$! ("buczap") is a synthetic internal rune that produces the bunt +(default value) for [%axil p]. + + Reduction + See ++open + + [%brcb p=tile q=(map term foot)] + +|_ ("barcab") is a synthetic rune that produces a %gold tray with +sample p, arms q. q is an associative array of names and +expressions, each pair of which is called an arm. After any number +of dry (%ash, ++) and/or wet (%elm, +-) arms, the array is +terminated with -- + + Tall + |_ p + ++ p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brcn p=(map term foot)] + +|% ("barcen") is a natural rune that produces a %gold core from an +associative array of names and expressions, each pair of which is +called an arm. After any number of dry (%ash, ++) and/or wet (%elm, ++-) arms, the array is terminated with -- + + Tall + |% + ++ p.n.q + q.n.q + +- p.n.l.q + q.n.l.q + -- + + Wide + none + + Irregular + none + + Reduction + none, natural + + [%brdt p=twig] + +|. ("bardot") is a synthetic rune that produces a dry %gold trap +from twig p. + + Tall + |. p + + Wide + |.(p) + + Irregular + none + + Reduction + See ++open + + [%brfs p=tile q=(map term foot)] + +|/ ("barfas") is a synthetic rune that produces a vulcanized %gold +tray with arms q, sample p. + + Tall + |/ p + +- p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brkt p=twig q=(map term foot)] + +|^ ("barket") is a synthetic rune that produces a %gold book with +arms q, with p as %$, and kicks it. + + Tall + |^ p + ++ p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brhp p=twig] + +|- ("barhep") is a synthetic rune that produces a dry %gold trap +from twig p, and kicks it. + + Tall + |- + p + + Wide + |-(p) + + Irregular + none + + Reduction + See ++open + + [%brls p=tile q=twig] + +|+ ("barlus") is a synthetic rune that produces a dry %iron gate +with arm q, sample p. + + Tall + |+ p + q + + Wide + |+(p q) + + Irregular + none + + Reduction + See ++open + + [%brpt p=tile q=tile r=twig] + + XX not used + + [%brtr p=tile q=twig] + +|* ("bartar") is a synthetic rune that produces a vulcanized wet +gate with arm q, sample p. + + Tall + |* p + q + + Wide + |*(p q) + + Irregular + none + + Reduction + See ++open + + [%brts p=tile q=twig] + +|= ("bartis") is a synthetic hoon that produces a dry %gold gate +with arm q, sample p. + + Tall + |= p + q + + Wide + |=(p q) + + Irregular + none + + Reduction + See ++open + + [%brwt p=twig] + +|? ("barwut") is a synthetic rune that produces a dry %lead trap. + + Tall + |? p + + Wide + |?(p) + + Irregular + none + + Reduction + See ++open + + [%clcb p=twig q=twig] + +:_ ("colcab") is a synthetic rune that produces the cell [q p]. + + Tall + :_ p + q + + Wide + :_(p q) + + Irregular + none + + Reduction + See ++open + + [%clcn p=tusk] + +:% ("colcen") is a synthetic rune that produces a cell [[p ~] ~] +from a list of twigs p, terminated by a == + + Tall + :% i.p + i.t.p + i.t.t.p + == + + Wide + :%(i.p i.t.p i.t.t.p) + + Irregular + %[i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%clfs p=twig] + +:/ ("colfas") is a synthetic rune that, given a twig p, produces +[%$ [%$ p ~] ~], i.e., [0 [0 p 0] 0]. Used in practice only in +string interpolation. + + Tall + :/ p + + Wide + :/(p) + + Irregular + none + + Reduction + See ++open + + [%clkt p=twig q=twig r=twig s=twig] + +:^ ("colket") is a synthetic rune that produces a cell [p q r s] +from twigs p, q, r, and s. + + Tall + :^ p + q + r + s + + Wide + :^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%clhp p=twig q=twig] + +:- ("colhep") is a synthetic rune that produces the cell [p q] from +twigs p and q. + + Tall + :- p + q + + Wide + :-(p q) + + Irregular + [p q] + + Reduction + See ++open + + [%clls p=twig q=twig r=twig] + +:+ ("collus") is a synthetic rune that produces a cell [p q r] from +twigs p, q, and r. + + Tall + :+ p + q + r + + Wide + :+(p q r) + + Irregular + none + + Reduction + See ++open + + [%clsg p=tusk] + +:~ ("colsig") is a synthetic rune that produces a null-terminated +tuple of a list of twigs p. + + Tall + :~ i.p + i.t.p + i.t.t.p + == + + Wide + :~(i.p i.t.p i.t.t.p) + + Irregular + ~[i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%cltr p=tusk] + +:* ("coltar") is a synthetic hoon that produces a tuple from p, a +list of twigs. + + Tall + :* i.p + i.t.p + i.t.t.p + == + + Wide + :*(i.p i.t.p i.t.t.p) + + Irregular + [i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%clzz p=tusk] + +"colzaz" is a synthetic internal rune that promotes its tusk p +within a %clsg or %cltr tusk. + + Not used at present. + + [%cncb p=wing q=tram] + +%_ ("cencab") is a synthetic rune that evaluates the wing p with +the changes specified in tram q, then casts the product back to p. + + Tall + %_ p + p.i.q q.i.q + p.i.t.q q.i.t.q + == + + Wide + %_(p p.i.q q.i.q, p.i.t.q q.i.t.q) + + Irregular + none + + Reduction + See ++open + + [%cncl p=twig q=twig] + +%: ("cencol") is a synthetic rune that pulls %$ from the twig p +with the with its sample set to q. + + Tall + %: p + q + + Wide + %:(p q) + + Irregular + none + + Reduction + See ++open + + [%cndt p=twig q=twig] + +%. ("cendot") is a synthetic rune that slams the gate q with +[%cltr p]. The dual of %cnhp. + + Tall + %. p + q + + Wide + %.(p q) + + Irregular + none + + Reduction + %- q + p + + See ++open + + [%cnhp p=twig q=tusk] + +%- ("cenhep") is a synthetic rune that slams the gate p with +[%cltr q]. + + Tall + %- p + q + + Wide + %-(p q) + + Irregular + (p q) + + Reduction + See ++open + + [%cntr p=wing q=twig r=tram] + +%* is a synthetic rune that pulls the wing p from tray q with changes r. + + Tall + %* p q + p.i.r q.i.r + p.i.t.r q.i.t.r + == + + Wide + %*(p q p.i.r q.i.r, p.i.t.r q.i.t.r) + + Irregular + none + + Reduction + See ++open + + [%cnkt p=twig q=twig r=twig s=twig] + +%^ ("cenket") is a synthetic rune that slams gate p with [%cntr q r s]. + + Tall + %^ p + q + r + s + + Wide + %^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%cnls p=twig q=twig r=twig] + +%+ ("cenlus") is a synthetic rune that slams gate p with [%cntr q r]. + + Tall + %+ p + r + s + + Wide + %+(p q r) + + Irregular + none + + Reduction + See ++open + + [%cnsg p=wing q=twig r=twig] + +%~ ("censig") is a synthetic rune that pulls p from the tray q with its +sample set to r. + + Tall + %~ p + q + r + + Wide + %~(p q r) + + Irregular + ~(p q r) + + Reduction + See ++open + + [%cnts p=wing q=tram] + +%= ("centis") is a natural rune that evaluates p with the changes +specified in q. + + Tall + %= p + p.i.q q.i.q + p.i.t.q q.i.t.q + == + + Wide + %=(p p.i.q q.i.q, p.i.t.q q.i.t.q) + + Irregular + p(p.i.q q.i.q, p.i.t.q q.i.t.q) + + Reduction + See ++open + + [%cnzy p=term] + +"cenzey" is a synthetic internal rune that pulls limb p from the subject. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%cnzz p=wing] + +"cenzaz" is a synthetic internal rune that pulls wing p from the subject. + + Form + none, internal + + Reduction + See ++open + + [%dtkt p=twig] + +.^ ("dotket") is a natural rune that generates Nock operator 11, which in +virtual userspace Nock (++mock) loads a file from the global namespace. + + Tall + .^ p + + Wide + .^(p) + + Irregular + ^:type/path + + ^/path + + Reduction + none, natural + + [%dtls p=twig] + +.+ ("dotlus") is a natural rune that generates Nock operator 4, which +increments an atomic operand. + + Tall + .+ p + + Wide + .+(p) + + Irregular + +(p) + + Reduction + none, natural + + [%dtzy p=term q=@] + +"dotzey" is a natural internal rune that produces a non-cubed atomic +constant of odor p and value q. + + Tall/Wide/Irregular + none, internal + + Reduction + none, natural + + [%dtzz p=term q=*] + +"dotzaz" is a natural internal rune that produces a cubed noun constant of +value q and odor p, if q is an atom. + + Tall/Wide/Irregular + none, internal + + Reduction + none, natural + + [%dttr p=twig q=twig] + +.* ("dottar") is a natural rune that calculates the Nock of subject p, +formula q. + + Tall + .* p + q + + Wide + .*(p q) + + Irregular + none + + Reduction + none, natural + + [%dtts p=twig q=twig] + +.= ("dottis") is a natural rune that applies Nock 5 (equals) to determine +if the products of p and q are equivalent. + + Tall + .= p + q + + Wide + .=(p q) + + Irregular + =(p q) + + Reduction + none, natural + + [%dtwt p=twig] + +.? ("dotwut") is a natural hoon that applies Nock 3 to a noun: if the +noun is a cell, it returns the loobean & (true); if the noun is an atom, +it returns the loobean | (false). + + Tall + .? p + + Wide + .?(p) + + Irregular + none + + Reduction + none, natural + + [%hxgl p=tusk] + +#< ("haxgal") is a synthetic rune that slams the assumed gate noah on +[%zpgr %cntr p]. See the Biblical names. + + Tall/Wide + none + + Irregular + >i.p i.t.p i.t.t.p< + + Reduction + See ++open + + [%hxgr p=tusk] + +#> ("haxgar") is a synthetic rune that slams the assumed gate cain on +[%zpgr %cntr p]. See the Biblical names. + + Tall/Wide + none + + Irregular + + + Reduction + See ++open + + [%ktbr p=twig] + +^| ("ketbar") is a natural rune that converts a %gold core into an %iron +core. See geometric polymorphism. + + Tall + ^| p + + Wide + ^|(p) + + Irregular + none + + Reduction + none, natural + + [%ktdt p=twig q=twig] + +^. ("ketdot") is a synthetic rune that casts q to the type of (p q). + + Tall + ^. p + q + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%ktls p=twig q=twig] + +^+ ("ketlus") is a natural rune that casts the product of q to the +type of p, verifying that it contains the type of q. + + Tall + +^ p + q + + Wide + ^+(p q) + + Irregular + none + + Reduction + none, natural + + [%kthp p=tile q=twig] + +^- ("kethep") is a synthetic rune that casts q to ~(bunt al p), +i.e., the icon of p. + + Tall + ^- p + q + + Wide + ^-(p q) + + Irregular + `p`q + + Reduction + See ++open + + [%ktpm p=twig] + +^& ("ketpam") is a natural rune that converts a %gold core to %zinc core. +See geometric polymorphism. + + Tall + ^& p + + Wide + ^&(p) + + Irregular + none + + Reduction + none, natural + + [%ktsg p=twig] + +^~ ("ketsig") is a natural rune that tries to execute p statically at +compile time; if this fails, p remains dynamic. + + Tall + ^~ p + + Wide + ^~(a) + + Irregular + none + + Reduction + none, natural + + [%ktts p=toga q=twig] + +^= ("kettis") is a natural rune that wraps q in the toga p. The +toga is a powerful naming device that can assign an entire name +tree to a properly typed result. For instance, if foo produces +an unlabeled tuple [x y z], [a b=[c d]]=foo produces +[a=x b=[c=y d=z]]. + + Tall + ^= p + q + + Wide + ^=(p q) + + Irregular + none + + Reduction + none, natural + + [%ktwt p=twig] + +^? ("ketwut") is a natural hoon that converts a %gold core into a +%lead core. See geometric polymorphism. + + Tall + ^? p + + Wide + ^?(p) + + Irregular + none + + Reduction + none, natural + + [%sgbr p=twig q=twig] + +~| ("sigbar") is a synthetic rune that presents the product of p +in the stack trace if q crashes. Only performed as needed. +Generates %cain - see the Biblical names. + + Tall + ~| p + q + + Wide + ~|(p q) + + Irregular + none + + Reduction + See ++open, ++feck + + [%sgcb p=twig q=twig] + +~_ ("sigcab") is a synthetic rune that inserts p, a trap producing a tank, +into the trace of q. + + Tall + ~_ p + q + + Wide + ~_(p q) + + Irregular + none + + Reduction + See ++open + + [%sgcn p=chum q=twig r=tyre s=twig] + +~% ("sigcen") is a synthetic rune that identifies a core for specific +optimization. See jet propulsion. + + Tall + ~% p + q + == + p.i.r q.i.r + p.i.t.r q.i.t.r + == + s + + ~% p + q + ~ + s + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%sgfs p=chum q=twig] + +~/ ("sigfas") is a synthetic rune that identifies an arm for specific +optimization. See jet propulsion. + + Tall + ~/ p + q + + Wide + ~/(p q) + + Irregular + none + + Reduction + See ++open + + [%sggl p=$|(term [p=term q=twig]) q=twig] + +~< ("siggal") is a synthetic rune that applies arbitrary hint p to +the product of q. Does not wake the hint engine until the +computation is finished. + + Tall + ~< p + q + + Wide + ~<(p q) + + Irregular + none + + Reduction + See ++open + + [%sggr p=$|(term [p=term q=twig]) q=twig] + +~> ("siggar") is a natural rune that applies arbitrary hint p to q. + + Tall + ~> p + q + + Wide + ~>(p q) + + Irregular + none + + Reduction + See ++open + + [%sgbc p=term q=twig] + +~$ ("sigbuc") is a synthetic rune that labels computation q as p +for profiling (not currently enabled). + + Tall + ~$ p + q + + Wide + ~$(p q) + + Irregular + none + + Reduction + See ++open + + [%sgls p=@ q=twig] + +XX Solve ~+ ("siglus") is a synthetic rune that memoizes computation q + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%sgpm p=@ud q=twig r=twig] + +~& ("sigpam") is a synthetic rune that prints q on the console +before computing r. p is the log priority 0-3, defaulting to 0. + + Tall + 0, debug + ~& q + r + + 1, notice + ~& > q + r + + 2, warning + ~& >> q + r + + 3, alarm + ~& >>> q + r + + Wide + ~&(>>> q r) + + Irregular + none + + Reduction + See ++open + + [%sgts p=twig q=twig] + +~= ("sigtis") is a synthetic rune that hints to the interpreter +that q may produce a noun equal to the already existing p, +avoiding duplication. + + Tall + ~= p + q + + Wide + ~=(p q) + + Irregular + none + + Reduction + See ++open + + [%sgwt p=@ud q=twig r=twig s=twig] + +~? ("sigwut") is a synthetic rune that prints r to the console +before computing s, iff q produces yes. p is the log priority, +0-3, 0 by default + + Tall + 0, debug + ~? q + r + s + + 1, notice + ~? > q + r + s + + 2, warning + ~? >> q + r + s + + 3, alarm + ~? >>> q + r + s + + Wide + ~?(>>> q r s) + + Irregular + none + + Reduction + See ++open + + [%sgzp p=twig q=twig] + +~! ("sigzap") is a natural rune for debugging uses only, +semantically equivalent to its own twig q. Should compilation +fail within q, ~! will show the type of p on the stacktrace. + + Tall + ~! p + q + + Wide + ~!(p q) + + Irregular + none + + Reduction + none, natural + + [%smcl p=twig q=tusk] + +;: ("semcol") is a synthetic gate that applies p, a binary gate, +to the n-ary tuple q. + + Tall + ;: p + i.q + i.t.q + i.t.t.q + == + + Wide + ;:(p i.q i.t.q i.t.t.q) + + Irregular + :(p i.q i.t.q i.t.t.q) + + Reduction + See ++open + + [%smdt p=twig q=tusk] +XX determine function + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smdq p=(list beer)] +XX determine if internal/external + +;" ("semdoq") is a synthetic rune used to make strings, +interpolated or not. + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smsg p=twig q=tusk] + +XX to do + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smsm p=twig q=twig] + +;; ("semsem") is a synthetic rune that types q as a fixpoint of p. +Semantically identical to ((hard p) q). + + Tall + ;; p + q + + Wide + ;;(p q) + + Irregular + none + + Reduction + See ++open + + [%tsbr p=tile q=twig] + +=| ("tisbar") is a synthetic rune that pushes ~(bunt al p) on the +subject and sends it to q. + + Tall + =| p + q + + Wide + =|(p q) + + Irregular + none + + Reduction + =+(_p q) + See ++open, ++bunt in ++al + + [%tscl p=tram q=twig] + +=: ("tiscol") is a synthetic rune that produces q with the subject +by p. Uses %cncb, and so cannot change the subject type. + + Tall + =: p.i.p q.i.p + p.i.t.p q.i.t.p + p.i.t.t.p q.i.t.t.p + == + q + + Wide + none + + Irregular + noen + + Reduction + See ++open + + [%tscn p=twig q=twig] +XX to do + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%tsdt p=wing q=twig r=twig] + +=. ("tisdot") is a synthetic rune that produces r with p in the +subject set to q. Uses %cncb, and so cannot change the subject + p. + + Tall + =. p + q + r + + =. p q + r + + Wide + =.(p q r) + + Irregular + none + + Reduction + See ++open + + [%tsfs p=twig q=twig] + XX not used + + [%tsgl p=twig q=twig] + +=< ("tisgal") is a synthetic rune that uses the product of q as +the subject of p. + + Tall + =< p + q + + Wide + =<(p q) + + Irregular + + Reduction + See ++open + + [%tshp p=twig q=twig] + +=- ("tishep") is a synthetic rune that pushes q on the subject +and sends it to p. Dual of =+ ("tislup") + + + Tall + =- p + q + + Wide + =- + + Irregular + none + + Reduction + See ++open + + [%tsgr p=twig q=twig] + +=> ("tisgar") is a natural rune that uses the product of p as the +subject of q. + + Tall + => p + q + + Wide + =>(p q) + + Irregular + none + + Reduction + none, natural + + [%tskt p=twig q=twig r=twig s=twig] + +=^ ("tisket") is a synthetic rune that handles a product which is +a cell of the new result, and a mutation to the subject. + + Tall + Kingside + =^ p + q + r + s + + Queenside + =^ p q + r + s + + Wide + =^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%tsls p=twig q=twig] + +=+ ("tislus") is a synthetic rune that pushes p on the subject +and sends it to q. Semantically equavlent to Nock 8.Dual of =- ("tishep") + + Tall + =+ p + q + + Wide + =+(p q) + + Irregular + none + + Reduction + See ++open + + [%tspm p=tile q=twig] + + XX not used + + [%tspt p=tile q=twig] + + XX not used + + [%tstr p=term q=wing r=twig] + +=* ("tistar") is a natural rune that creates a %bull, or alias, +type. + + Tall + =* p q + r + + Wide + =*(p q r) + + Irregular + none + + Reduction + none, natural + + [%tssg p=tusk] + +=~ ("tissig") is a synthetic rune that composes a list of twigs. + + Tall + Kingside + =~ i.p + i.t.p + i.t.t.p + == + + Queenside + =~ i.p + i.t.p + i.t.t.p + == + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%wtbr p=tusk] + +?| ("wutbar") is a synthetic rune that computes the "or" of the +loobeans in p. + + Tall + ?| i.p + i.t.p + i.t.t.p + == + + Wide + ?|(i.p i.t.p i.t.t.p) + + Irregular + |(i.p i.t.p i.t.t.p) + + Reduction + See ++open + + [%wthp p=wing q=tine] + +?- ("wuthep") is a synthetic rune that selects a case in q for +the actual type of p. + + Tall + Kingside + ?- p + p.i.q q.i.q + p.i.t.q q.i.t.q + p.i.t.t.q q.i.t.t.q + == + + Queenside + ?- p + p.i.q + q.i.q + p.i.t.q + q.i.t.q + p.i.t.t.q + q.i.t.t.q + == + + Wide + ?-(p p.i.q q.i.q, p.i.t.q q.i.t.q, p.i.t.t.q q.i.t.t.q) + + Irregular + none + + Reduction + See ++open + + [%wthz p=tiki q=tine] + +"wuthaz" is a synthetic internal rune that selects a case in q +for the actual type of p. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtcl p=twig q=twig r=twig] + +?: ("wutcol") is a natural rune that produces q if p is yes (&, 0), +or r if p is no (|, 1). + + Tall + ?: p + q + r + + Wide + ?:(p q r) + + Irregular + none + + Reduction + none, natural + + [%wtdt p=twig q=twig r=twig] + +?. ("wutdot") is a synthetic rune that prduces r if p is yes +(&, 0), of q if p is no (|, 1). + + Tall + ?. p + q + r + + Wide + ?:(p q r) + + Irregular + none + + Reduction + none, natural + + [%wtkt p=wing q=twig r=twig] + +?^ ("wutkey") is a synthetic rune that evaluates r if p is +equivalent to the bunt for its tile, otherwise q is evaluted. + + Tall + ?^ p + q + r + + Wide + ?^(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtkz p=tiki q=twig r=twig] + +"wutkaz" is a synthetic, internal rune that evaluates r if p is +equivalent to the bunt for its tile, otherwise q is evaluated. +See tikis. + + Tall + ?^ p + q + r + + Wide + ?^(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtgl p=twig q=twig] + +?< ("wutgal") is a synthetic hoon that produces q, asserting that +p is no (|, 1). + + Tall + ?< p + q + + Wide + ?<(p q) + + Irregular + none + + Reduction + See ++open + + [%wtgr p=twig q=twig] + +?> ("wutgar") is a synthetic hoon that produces q, asserting that +p is yes (&, 0). + + Tall + ?> p + q + + Wide + ?>(p q) + + Irregular + none + + Reduction + See ++open + + [%wtls p=wing q=twig r=tine] + +?+ ("wutlus") is a synthetic rune that selects a case in q for +the actual type of p. + + Tall + Kingside + ?+ p + q + p.i.r q.i.r + p.i.t.r q.i.t.r + p.i.t.t.r q.i.t.t.r + == + + Queenside + ?+ p + q + p.i.r + q.i.r + p.i.t.r + q.i.t.r + p.i.t.t.r + q.i.t.t.r + == + + Wide + ?+(p p.i.r q.i.r, p.i.t.r q.i.t.r, p.i.t.t.r q.i.t.t.r) + + Irregular + none + + Reduction + See ++open + + [%wtlz p=tiki q=twig r=tine] + +"wutlaz" is a synthetic, internal rune that selects a case in q for +the actual type of p. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtpm p=tusk] + +?& ("wutpam") is a synthetic hoon that computes the "and" of the +loobeans in p. + + Tall + ?& i.p + i.t.p + i.t.t.p + == + + Wide + ?&(i.p i.t.p i.t.t.p) + + Irregular + none + + Reduction + See ++open + + [%wtpt p=wing q=twig r=twig] + +?@ ("wutpat") is a synthetic hoon that produces q if p is an +atom, r otherwise. + + Tall + Kingside + ?@ p + q + r + + Queenside + ?@ p + q + r + + Wide + ?@(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtpz p=tiki q=twig r=twig] + +"wutpaz" is a synthetic hoon that produces q if p is an atom, r +otherwise. + + Tall + ?@ p + q + r + + Wide + ?@(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtsg p=wing q=twig r=twig] + +?~ ("wutsig") is a synthetic rune that produces q if p is ~, r +otherwise. + + Tall + ?~ p + q + r + + Wide + ?~(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtsz p=tiki q=twig r=twig] + +"wutsaz" is a synthetic internal rune that produces q if p is ~, +r otherwise. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtts p=tile q=wing] + +?= ("wuttis") is a natural rune that produces true if the leg at +wing q is in tile p. + + Tall + ?= p + q + + Wide + ?=(p q) + + Irregular + none + + Reduction + none, natural + + [%wtzp p=twig] + +?! ("wutzap") is a synthetic rune that produces the logical "not" +of p. + + Tall + ?! p + + Wide + ?!(p) + + Irregular + !p + + Reduction + See ++open + + [%zpcb p=spot q=twig] +XX tall/wide form +!_ ("zapcab") is a natural rune that puts debugging information +in the stack trace. + + Tall + + Wide + + Irregular + none + + Reduction + none, natural + + [%zpcm p=twig q=twig] + +!, ("zapcom") is a natural rune that inserts twig q as a +constant, typed with the type of twig p. + + Tall + !, p + q + + Wide + !,(p q) + + Irregular + none + + Reduction + none, natural + + [%zpcn ~] +XX determine function +!% ("zapcen") + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%zpfs p=twig] +XX tall/wide +!/ ("zapfas") is a natural rune that should never be compiled. +When compiled with error checking turned on, it reports its +subject as an error. + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%zpgr p=twig] + +!> ("zapgar") is a synthetic rune that produces a vase (a +[type noun] cell) with the value p. + + Tall + !> p + + Wide + !>(p) + + Irregular + none + + Reduction + See ++open + + [%zpsm p=twig q=twig] + +!; ("zapsem") is a natural rune that produces the product of twig +q as a [type noun] pair, with twig p defining the type of the type. + + Tall + !; p + q + + Wide + !;(p q) + + Irregular + none + + Reduction + none, natural + + [%zpts p=twig] + +!= ("zaptis") is a natural rune that produces the formula of twig +p as a noun. + + Tall + != p + + Wide + !=(p) + + Irregular + none + + Reduction + none, natural + + [%zpwt p=$|(p=@ [p=@ q=@]) q=twig] + +!? ("zapwut") is a synthetic rune that enforces a Hoon version +restriction. + + Tall + !? p + q + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%zpzp ~] + +!! ("zapzap") is a natural rune that always causes a crash when +executed. + + Tall + none + + Wide + !! + + Irregular + none + + Reduction + none, natural + +--- + diff --git a/main/pub/src/doc/ref/hoon/lexicon.md b/main/pub/src/doc/ref/hoon/lexicon.md new file mode 100644 index 000000000..015b09542 --- /dev/null +++ b/main/pub/src/doc/ref/hoon/lexicon.md @@ -0,0 +1,2546 @@ +Lexicon +======= + +Atom Odors: + +@c UTF-32 codepoint +@d date + @da absolute date + @dr relative date (ie, timespan) +@f yes or no (inverse boolean) +@n nil +@p phonemic base +@r IEEE floating-point + @rd double precision (64 bits) + @rh half precision (16 bits) + @rq quad precision (128 bits) + @rs single precision (32 bits) +@s signed integer, sign bit low + @sb signed binary + @sd signed decimal + @sv signed base32 + @sw signed base64 + @sx signed hexadecimal +@t UTF-8 text (cord) + @ta ASCII text (span) + @tas ASCII symbol (term) +@u unsigned integer + @ub unsigned binary + @ud unsigned decimal + @uv unsigned base32 + @uw unsigned base64 + @ux unsigned hexadecimal + +Canonical atom syntaxes + +Unsigned decimal, @ud + + +Hoon's unsigned decimal format is the normal Continental syntax. It differs from the Anglo-American only in the use of periods, rather than commas, between groups of 3: + +~waclux-tomwyc/try=> 19 +19 +~waclux-tomwyc/try=> 1.024 +1.024 + +An unsigned decimal not broken into groups is a syntax error. Also, whitespace or even linebreaks can appear between the dot and the next group. + +~waclux-tomwyc/try=> 65. 536 +65.536 + +Unsigned hexadecimal, @ux + +@ux has the same syntax as @ud, except that it's prefixed by 0x and uses groups of four. Hex digits are lowercase only. + +~waclux-tomwyc/try=> 0x0 +0x0 +~waclux-tomwyc/try=> `@ud`0x17 +23 + +Unsigned base64, @uw + +Unsigned base32, @uv + +The prefix is 0w for base64 and 0v for base32. The digits for @uw are, in order: 0-9, a-z, A-Z, -, ~: + +~waclux-tomwyc/try=> `@ud`0w- +62 +For @uv, the digits are 0-9, a-v. + +Signed decimal, @sd + +Signed hexadecimal, @sx + +Signed base64, @sw + +Signed base32, @sv + +Signed binary, @sb + +Obviously, without finite-sized integers, the sign extension trick does not work. A signed integer in Hoon is a different way to use atoms than an unsigned integer; even for positive numbers, the signed integer cannot equal the unsigned. + +The prefix for a negative signed integer is a single - before the unsigned syntax. The prefix for a positive signed integer is --. The sign bit is the low bit: + +~waclux-tomwyc/try=> -1 +-1 +~waclux-tomwyc/try=> --1 +--1 +~waclux-tomwyc/try=> `@ud`-1 +1 +~waclux-tomwyc/try=> `@ud`--1 +2 +~waclux-tomwyc/try=> `@ud`-2 +3 +~waclux-tomwyc/try=> `@ud`--2 +4 +~waclux-tomwyc/try=> `@ux`-0x10 +0x1f +~waclux-tomwyc/try=> `@ux`--0x10 +0x20 +~waclux-tomwyc/try=> `@ud`--0w- +124 +~waclux-tomwyc/try=> `@sw`124 +--0w- + +Absolute date, @da + +Urbit dates represent 128-bit chronological time, with 2^64 seconds from the start of the universe to the end. 2^127 is 3:30:08 PM on December 5, AD 226, for reasons not clear or relevant: + +~waclux-tomwyc/try=> `@da`(bex 127) +~226.12.5..15.30.08 + +~waclux-tomwyc/try=> `@da`(dec (bex 127)) +~226.12.5..15.30.07..ffff.ffff.ffff.ffff +The time of day and/or second fragment is optional: + +~waclux-tomwyc/try=> `@ux`~2013.12.7 +0x8000.000d.2140.7280.0000.0000.0000.0000 + +~waclux-tomwyc/try=> `@ux`~2013.12.7..15.30.07 +0x8000.000d.2141.4c7f.0000.0000.0000.0000 + +~waclux-tomwyc/try=> `@ux`~2013.12.7..15.30.07..1234 +0x8000.000d.2141.4c7f.1234.0000.0000.0000 +We also do BC: + +~waclux-tomwyc/try=> `@ux`~226-.12.5 +0x7fff.fffc.afb1.b800.0000.0000.0000.0000 + +The semantics of the time system are that UGT (Urbit Galactic Time) is GMT/UTC as of leap second 25. UGT is chronological and will never add leap seconds, even if UTC continues this mistake. If a gap appears, it must be resolved in the presentation layer, with timezones and other human curiosities. + +Relative date, @dr + +It's also nice to have a syntax for basic time intervals: + +~waclux-tomwyc/try=> `@ux`~s1 +0x1.0000.0000.0000.0000 + +~waclux-tomwyc/try=> `@ux`~m1 +0x3c.0000.0000.0000.0000 + +~waclux-tomwyc/try=> (div ~m1 ~s1) +60 + +~waclux-tomwyc/try=> (div ~h1 ~m1) +60 + +~waclux-tomwyc/try=> (div ~h1 ~s1) +3.600 + +~waclux-tomwyc/try=> (div ~d1 ~h1) +24 + +~waclux-tomwyc/try=> `@da`(add ~2013.11.30 ~d1) +~2013.12.1 +There are no @dr intervals under a second or over a day. Since the resolution is so high, though, (div ~s1 1.000.000) produces a pretty accurate microsecond. + +Loobean, @f + +A loobean, or just bean, is 0 or 1. 0 is yes, 1 is no: + +~waclux-tomwyc/try=> `@ud`.y +0 +~waclux-tomwyc/try=> `@ud`.n +1 +People who find this strange are probably strange themselves. + +Nil, @n + +Nil indicates an absence of information, as in a list terminator. The only value is ~, 0. + +~waclux-tomwyc/try=> `@ud`~ +0 +Unicode text, @t + +@t is a sequence of UTF-8 bytes, LSB first - sometimes called a cord. For lowercase numbers and letters, the canonical syntax is ~~text: + +~waclux-tomwyc/try=> ~~foo +'foo' +Note that the prettyprinter makes an unprincipled exception and prints the text in a noncanonical format: + +~waclux-tomwyc/try=> `@ux`~~foo +0x6f.6f66 +We want to be able to encode an arbitrary Unicode string as a single URL-safe token, using no punctuation but .~-, in @t. Space is ., . is ~., ~ is ~~, - is -: + +~waclux-tomwyc/try=> ~~foo.bar +'foo bar' +~waclux-tomwyc/try=> ~~foo.bar~.baz~~moo-hoo +'foo bar.baz~moo-hoo' +For all other ASCII/Unicode characters, insert the Unicode codepoint in lower-case hexadecimal, followed by .. For example, for U+2605 "BLACK STAR", write: + +~waclux-tomwyc/try=> ~~foo~2605.bar +'foo★bar' +This UTF-32 codepoint is of course converted to UTF-8: + +~waclux-tomwyc/try=> `@ux`~~foo~2605.bar +0x72.6162.8598.e26f.6f66 +URL-safe ASCII text, @ta + +@ta encodes the ASCII subset that all canonical atom syntaxes restrict themselves to. The prefix is ~.. There are no escape sequences except ~~, which means ~, and ~-, which means \_. - and . encode themselves. No other characters besides numbers and lowercase letters need apply. + +Let's cast these to @t to see them quoted: + +~waclux-tomwyc/try=> `@t`~.foo +'foo' +~waclux-tomwyc/try=> `@t`~.foo.bar +'foo.bar' +~waclux-tomwyc/try=> `@t`~.foo~~bar +'foo~bar' +~waclux-tomwyc/try=> `@t`~.foo~-bar +'foo_bar' +~waclux-tomwyc/try=> `@t`~.foo-bar +'foo-bar' +A @ta atom is called a span. + +Codepoint, @c + +Normally when we build atoms of Unicode text, we use a UTF-8 bytestream, LSB first. But sometimes it's useful to build atoms of one or more UTF-32 words. + +The codepoint syntax is the same as @t, except with a ~- prefix. Let's repeat our examples, with hex display: + +~waclux-tomwyc/try=> `@ux`~-foo +0x6f.0000.006f.0000.0066 + +~waclux-tomwyc/try=> `@ux`~-foo.bar +0x72.0000.0061.0000.0062.0000.0020.0000.006f.0000.006f.0000.0066 +Phonemic, @p + +We've seen @p used for ships, of course. But it's not just for ships - it's for any short number optimized for memorability, not for arithmetic. @p is great for checksums, for instance. + +That said, @p is subtly customized for the sociopolitical design of Urbit as a digital republic. For example, one feature we don't want is the ability to see at a glance which carrier and cruiser issued a destroyer. Consider the carrier 0x21: + +~waclux-tomwyc/try=> `@p`0x21 +~mep +It issues 255 cruisers, including 0x4321: + +~waclux-tomwyc/try=> `@p`0x4321 +~pasnut +Which issues 65.535 destroyers, including 0x8765.4321 and several successors: + +~waclux-tomwyc/try=> `@p`0x8765.4321 +~famsyr-dirwes +~waclux-tomwyc/try=> `@p`0x8766.4321 +~lidlug-maprec +~waclux-tomwyc/try=> `@p`0x8767.4321 +~tidlus-roplen +~waclux-tomwyc/try=> `@p`0x8768.4321 +~lisnel-lonbet +Of course, anyone who can juggle bits can see that ~famsyr-dirwes is a close cousin of ~lidlug-maprec. But she actually has to juggle bits to do it. Obfuscation does not prevent calculated associations, just automatic ones. + +But at the yacht level, we actually want to see a uniform 32-bit space of yachts directly associated with the destroyer: + +~waclux-tomwyc/try=> `@p`0x9.8765.4321 +~talfes-sibzod-famsyr-dirwes +~waclux-tomwyc/try=> `@p`0xba9.8765.4321 +~tacbep-ronreg-famsyr-dirwes +~waclux-tomwyc/try=> `@p`0xd.cba9.8765.4321 +~bicsub-ritbyt-famsyr-dirwes +~waclux-tomwyc/try=> `@p`0xfed.cba9.8765.4321 +~sivrep-hadfeb-famsyr-dirwes + +IPv4 address, @if + +IPv6 address, @is + +Urbit lives atop IP and would be very foolish to not support a syntax for the large atoms that are IPv4 and IPv6 addresses. + +@if is the standard IPv4 syntax, prefixed with .: + +~waclux-tomwyc/try=> `@ux`.127.0.0.1 +0x7f00.0001 +@is is the same as @if, but with 8 groups of 4 hex digits: + +~waclux-tomwyc/try=> `@ux`.dead.beef.0.cafe.42.babe.dead.beef +0xdead.beef.0000.cafe.0042.babe.dead.beef +IEEE single-precision, @rs + +IEEE double-precision, @rd + +IEEE quad-precision, @rq + +IEEE half-precision, @rh + +Hoon does not yet support floating point, so these syntaxes don't actually work. But the syntax for a single-precision float is the normal English syntax, with a . prefix: + +.6.2832 :: τ as @rs +.-6.2832 :: -τ as @rs +.~6.2832 :: τ as @rd +.~-6.2832 :: -τ as @rd +.~~6.2832 :: τ as @rh +.~~~6.2832 :: τ as @rq +(Hoon is a Tauist language and promotes International Tau Day.) + +Transparent cell syntax + +By adding _, we can encode arbitrary nouns in our safe subset. The prefix to a canonical cell is ._; the separator is _; the terminator is __. Thus: + +~waclux-tomwyc/try=> ._3_4__ +[3 4] + +~waclux-tomwyc/try=> :type; ._.127.0.0.1_._0x12_19___~tasfyn-partyv__ +[.127.0.0.1 [0x12 19] ~tasfyn-partyv] +[@if [@ux @ud] @p] +Those who don't see utility in this strange feature have perhaps never needed to jam a data structure into a URL. + +Opaque noun syntax + +Speaking of jam, sometimes we really don't care what's inside our noun. Then, the syntax to use is a variant of @uw prefixed by ~, which incorporates the built-in jam and cue marshallers: + +~waclux-tomwyc/try=> (jam [3 4]) +78.241 +~waclux-tomwyc/try=> `@uw`(jam [3 4]) +0wj6x +~waclux-tomwyc/try=> (cue 0wj6x) +[3 4] +~waclux-tomwyc/try=> ~0wj6x +[3 4] +Noncanonical syntaxes + +These are syntaxes for constants which don't fit the canonical character-set constraints. + +Hoon symbol, @tas + +@tas, a term, is our most exclusive odor. The only characters permitted are lowercase ASCII, - except as the first or last character, and 0-9 except as the first character. + +The syntax for @tas is the text itself, always preceded by %. This means a term is always cubical. You can cast it to @tas if you like, but we just about always want the cube: + +~waclux-tomwyc/try=> %dead-fish9 +%dead-fish9 + +~waclux-tomwyc/try=> -:!>(%dead-fish9) +[%cube p=271.101.667.197.767.630.546.276 q=[%atom p=%tas]] +The empty @tas has a special syntax, $: + +~waclux-tomwyc/try=> %$ +%$ +A term without % is not a constant, but a name: + +~waclux-tomwyc/try=> dead-fish9 +! -find-limb.dead-fish9 +! find-none +! exit +Loobeans, @f + +.y is a little cumbersome, so we can say & and |. The % prefix cubes as usual. + +~waclux-tomwyc/try=> `@ud`& +0 +~waclux-tomwyc/try=> `@ud`| +1 +Cords, @t + +The canonical ~~ syntax for @t, while it has its place, is intolerable in a number of ways - especially when it comes to escaping capitals. So @t is both printed and parsed in a conventional-looking single-quote syntax: + +~waclux-tomwyc/try=> 'foo bar' +'foo bar' +~waclux-tomwyc/try=> `@ux`'foo bar' +0x72.6162.206f.6f66 +Escape ' with \: + +~waclux-tomwyc/try=> 'Foo \'bar' +'Foo \'bar' +~waclux-tomwyc/try=> `@ux`'\'' +0x27 +Strings + +Text in Hoon is generally manipulated in two ways, depending on what you're doing: as an atomic cord/span/term, or as a tape which is a list of bytes (not codepoints). + +To generate a tape, use double quotes: + +~waclux-tomwyc/try=> "foo" +"foo" +~waclux-tomwyc/try=> `*`"foo" +[102 111 111 0] +We're getting off the constant reservation, but strings also interpolate with curly-braces: + +~waclux-tomwyc/try=> "hello {(weld "wor" "ld")} is a fun thing to say" +"hello world is a fun thing to say" +And they can be joined across space or lines with a .: + +~waclux-tomwyc/try=> "hello"."world" +"helloworld" +~waclux-tomwyc/try=> "hello". "world" +"helloworld" + +Runes: + + | bar core construction + |_ dry %gold door + |% generic %gold core + |. dry %gold trap + |/ vulcanized gold door + |^ kick a %gold book + |- kick a %gold trap + |+ dry %iron gate + |* vulcanized wet gate + |= dry %gold gate + |? dry %lead trap + + $ buc tiles and tiling + $_ bunt a tile + $, clam a tile + $@ whip a wing into a tile + $* bunt a tile statically + $! bunt an axil + + Tile runes: + $^ plant a %herb + $: build a tile + $= plant a %bark + $& plant a %bush + $? plant a %fern + $% plant a %kelp + $| plant a %reed + @ atom axil + ^ cell axil + * noun axil + ? bean axil + ~ null axil + + % cen invocations + %_ invoke with changes and cast + %: pull %$ of a door with a sample + %. inverse order %- + %- slam a core with a sample + %* + %^ + %+ + %~ + %= + + : col tuples + :_ reverse pair [q p] + :% + :/ + :^ + :- + :+ + :~ + :* + + . dot nock operators + .^ + .+ + .* + .= + .? + + ^ ket type conversions + ^| + ^. + ^+ + ^- + ^& + ^~ + ^= + ^? + + ; sem miscellaneous macros + ;: + ;. + ;" + ;~ + ;; + + ~ sig hints + ~| + ~_ + ~% + ~/ + ~< + ~> + ~$ + ~+ + ~& + ~= + ~? + ~! + + = tis compositions + =| + =: + =% + =. + =/ + => + =< + =- + =^ + =+ + =& + =@ + =* + =~ + + ? wut conditionals, booleans, tests + ?| + ?- + ?: + ?. + ?^ + ?> + ?< + ?+ + ?& + ?~ + ?= + ?! + + ! zap special operations + !: + !_ + !, + !% + !/ + !; + !? + !! + +Wing Runes + +Limbs + Names + a + ^a + + Axes + . + +3 + &3 + ->- + +Wings: concatenate limbs separated by . + +Punctuation runes + +++ dry arm ++- wet arm + +== terminate list +-- terminate map or set + + +Irregular Rune Forms + +,p $,(p) +*p $*(p) +_p $_(p) +p@q $@(p q) +!p ?!(p) +&(p q) ?&(p q) +|(p q) ?|(p q) +`p`q ^-(p q) +p=q ^=(p q) +~[p q] :~(a b) +[p q]~ :~(a) +`[p] [~ p] +p^q [p q] +[p q] :*(p) ++(p) .+(p) +=(p q) .=(p) +p:q =<(p q) +p(q r) %=(p q r) +(p list) %-(p) +~(p q r) %~(p q r) +>p< #<(p) +

#>(p) +:(p q) ;:(p q) + + +There are 112 cases of ++twig + + [p=twig q=twig] + +A twig can be a pair of twigs. + + [%$ p=axis] + +Refers to a nock axis. + + [%bccb p=tile] + +$_ ("buccab") is a synthetic hoon that produces the bunt (default +value) for p. + + Tall + $_ p + + Wide + $_(p) + + Irregular + _p + + Reduction + See ++open + + [%bccm p=tile] + +$, ("buccom") is a synthetic rune that produces a normalizing gate +(clam) for p. + + Talln + $, p + + Wide + none + + Irregular + ,p + + Reduction + ~(clam al p) + + See ++clam in ++al. + + [%bcpt p=wing q=tile] + +$@ ("bucpat") is a (just barely) natural hoon that whips wing p +into tile q. + + Tall + $@ p + q + + Wide + $@(p q) + + Irregular + p@q + + Reduction + none, natural + + [%bctr p=tile] + +$* ("buctar") is a synthetic rune that produces the bunt (default +value) for p as a compile-time constant. + + Tall + $* p + + Wide + $*(p) + + Reduction + ^~ ~(bunt al p) + + See ++bunt in al. + + [%bczp p=base] + +$! ("buczap") is a synthetic internal rune that produces the bunt +(default value) for [%axil p]. + + Reduction + See ++open + + [%brcb p=tile q=(map term foot)] + +|_ ("barcab") is a synthetic rune that produces a %gold tray with +sample p, arms q. q is an associative array of names and +expressions, each pair of which is called an arm. After any number +of dry (%ash, ++) and/or wet (%elm, +-) arms, the array is +terminated with -- + + Tall + |_ p + ++ p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brcn p=(map term foot)] + +|% ("barcen") is a natural rune that produces a %gold core from an +associative array of names and expressions, each pair of which is +called an arm. After any number of dry (%ash, ++) and/or wet (%elm, ++-) arms, the array is terminated with -- + + Tall + |% + ++ p.n.q + q.n.q + +- p.n.l.q + q.n.l.q + -- + + Wide + none + + Irregular + none + + Reduction + none, natural + + [%brdt p=twig] + +|. ("bardot") is a synthetic rune that produces a dry %gold trap +from twig p. + + Tall + |. p + + Wide + |.(p) + + Irregular + none + + Reduction + See ++open + + [%brfs p=tile q=(map term foot)] + +|/ ("barfas") is a synthetic rune that produces a vulcanized %gold +tray with arms q, sample p. + + Tall + |/ p + +- p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brkt p=twig q=(map term foot)] + +|^ ("barket") is a synthetic rune that produces a %gold book with +arms q, with p as %$, and kicks it. + + Tall + |^ p + ++ p.n.q + q.n.q + -- + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%brhp p=twig] + +|- ("barhep") is a synthetic rune that produces a dry %gold trap +from twig p, and kicks it. + + Tall + |- + p + + Wide + |-(p) + + Irregular + none + + Reduction + See ++open + + [%brls p=tile q=twig] + +|+ ("barlus") is a synthetic rune that produces a dry %iron gate +with arm q, sample p. + + Tall + |+ p + q + + Wide + |+(p q) + + Irregular + none + + Reduction + See ++open + + [%brpt p=tile q=tile r=twig] + + XX not used + + [%brtr p=tile q=twig] + +|* ("bartar") is a synthetic rune that produces a vulcanized wet +gate with arm q, sample p. + + Tall + |* p + q + + Wide + |*(p q) + + Irregular + none + + Reduction + See ++open + + [%brts p=tile q=twig] + +|= ("bartis") is a synthetic hoon that produces a dry %gold gate +with arm q, sample p. + + Tall + |= p + q + + Wide + |=(p q) + + Irregular + none + + Reduction + See ++open + + [%brwt p=twig] + +|? ("barwut") is a synthetic rune that produces a dry %lead trap. + + Tall + |? p + + Wide + |?(p) + + Irregular + none + + Reduction + See ++open + + [%clcb p=twig q=twig] + +:_ ("colcab") is a synthetic rune that produces the cell [q p]. + + Tall + :_ p + q + + Wide + :_(p q) + + Irregular + none + + Reduction + See ++open + + [%clcn p=tusk] + +:% ("colcen") is a synthetic rune that produces a cell [[p ~] ~] +from a list of twigs p, terminated by a == + + Tall + :% i.p + i.t.p + i.t.t.p + == + + Wide + :%(i.p i.t.p i.t.t.p) + + Irregular + %[i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%clfs p=twig] + +:/ ("colfas") is a synthetic rune that, given a twig p, produces +[%$ [%$ p ~] ~], i.e., [0 [0 p 0] 0]. Used in practice only in +string interpolation. + + Tall + :/ p + + Wide + :/(p) + + Irregular + none + + Reduction + See ++open + + [%clkt p=twig q=twig r=twig s=twig] + +:^ ("colket") is a synthetic rune that produces a cell [p q r s] +from twigs p, q, r, and s. + + Tall + :^ p + q + r + s + + Wide + :^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%clhp p=twig q=twig] + +:- ("colhep") is a synthetic rune that produces the cell [p q] from +twigs p and q. + + Tall + :- p + q + + Wide + :-(p q) + + Irregular + [p q] + + Reduction + See ++open + + [%clls p=twig q=twig r=twig] + +:+ ("collus") is a synthetic rune that produces a cell [p q r] from +twigs p, q, and r. + + Tall + :+ p + q + r + + Wide + :+(p q r) + + Irregular + none + + Reduction + See ++open + + [%clsg p=tusk] + +:~ ("colsig") is a synthetic rune that produces a null-terminated +tuple of a list of twigs p. + + Tall + :~ i.p + i.t.p + i.t.t.p + == + + Wide + :~(i.p i.t.p i.t.t.p) + + Irregular + ~[i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%cltr p=tusk] + +:* ("coltar") is a synthetic hoon that produces a tuple from p, a +list of twigs. + + Tall + :* i.p + i.t.p + i.t.t.p + == + + Wide + :*(i.p i.t.p i.t.t.p) + + Irregular + [i.p i.t.p i.t.t.p] + + Reduction + See ++open + + [%clzz p=tusk] + +"colzaz" is a synthetic internal rune that promotes its tusk p +within a %clsg or %cltr tusk. + + Not used at present. + + [%cncb p=wing q=tram] + +%_ ("cencab") is a synthetic rune that evaluates the wing p with +the changes specified in tram q, then casts the product back to p. + + Tall + %_ p + p.i.q q.i.q + p.i.t.q q.i.t.q + == + + Wide + %_(p p.i.q q.i.q, p.i.t.q q.i.t.q) + + Irregular + none + + Reduction + See ++open + + [%cncl p=twig q=twig] + +%: ("cencol") is a synthetic rune that pulls %$ from the twig p +with the with its sample set to q. + + Tall + %: p + q + + Wide + %:(p q) + + Irregular + none + + Reduction + See ++open + + [%cndt p=twig q=twig] + +%. ("cendot") is a synthetic rune that slams the gate q with +[%cltr p]. The dual of %cnhp. + + Tall + %. p + q + + Wide + %.(p q) + + Irregular + none + + Reduction + %- q + p + + See ++open + + [%cnhp p=twig q=tusk] + +%- ("cenhep") is a synthetic rune that slams the gate p with +[%cltr q]. + + Tall + %- p + q + + Wide + %-(p q) + + Irregular + (p q) + + Reduction + See ++open + + [%cntr p=wing q=twig r=tram] + +%* is a synthetic rune that pulls the wing p from tray q with changes r. + + Tall + %* p q + p.i.r q.i.r + p.i.t.r q.i.t.r + == + + Wide + %*(p q p.i.r q.i.r, p.i.t.r q.i.t.r) + + Irregular + none + + Reduction + See ++open + + [%cnkt p=twig q=twig r=twig s=twig] + +%^ ("cenket") is a synthetic rune that slams gate p with [%cntr q r s]. + + Tall + %^ p + q + r + s + + Wide + %^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%cnls p=twig q=twig r=twig] + +%+ ("cenlus") is a synthetic rune that slams gate p with [%cntr q r]. + + Tall + %+ p + r + s + + Wide + %+(p q r) + + Irregular + none + + Reduction + See ++open + + [%cnsg p=wing q=twig r=twig] + +%~ ("censig") is a synthetic rune that pulls p from the tray q with its +sample set to r. + + Tall + %~ p + q + r + + Wide + %~(p q r) + + Irregular + ~(p q r) + + Reduction + See ++open + + [%cnts p=wing q=tram] + +%= ("centis") is a natural rune that evaluates p with the changes +specified in q. + + Tall + %= p + p.i.q q.i.q + p.i.t.q q.i.t.q + == + + Wide + %=(p p.i.q q.i.q, p.i.t.q q.i.t.q) + + Irregular + p(p.i.q q.i.q, p.i.t.q q.i.t.q) + + Reduction + See ++open + + [%cnzy p=term] + +"cenzey" is a synthetic internal rune that pulls limb p from the subject. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%cnzz p=wing] + +"cenzaz" is a synthetic internal rune that pulls wing p from the subject. + + Form + none, internal + + Reduction + See ++open + + [%dtkt p=twig] + +.^ ("dotket") is a natural rune that generates Nock operator 11, which in +virtual userspace Nock (++mock) loads a file from the global namespace. + + Tall + .^ p + + Wide + .^(p) + + Irregular + ^:type/path + + ^/path + + Reduction + none, natural + + [%dtls p=twig] + +.+ ("dotlus") is a natural rune that generates Nock operator 4, which +increments an atomic operand. + + Tall + .+ p + + Wide + .+(p) + + Irregular + +(p) + + Reduction + none, natural + + [%dtzy p=term q=@] + +"dotzey" is a natural internal rune that produces a non-cubed atomic +constant of odor p and value q. + + Tall/Wide/Irregular + none, internal + + Reduction + none, natural + + [%dtzz p=term q=*] + +"dotzaz" is a natural internal rune that produces a cubed noun constant of +value q and odor p, if q is an atom. + + Tall/Wide/Irregular + none, internal + + Reduction + none, natural + + [%dttr p=twig q=twig] + +.* ("dottar") is a natural rune that calculates the Nock of subject p, +formula q. + + Tall + .* p + q + + Wide + .*(p q) + + Irregular + none + + Reduction + none, natural + + [%dtts p=twig q=twig] + +.= ("dottis") is a natural rune that applies Nock 5 (equals) to determine +if the products of p and q are equivalent. + + Tall + .= p + q + + Wide + .=(p q) + + Irregular + =(p q) + + Reduction + none, natural + + [%dtwt p=twig] + +.? ("dotwut") is a natural hoon that applies Nock 3 to a noun: if the +noun is a cell, it returns the loobean & (true); if the noun is an atom, +it returns the loobean | (false). + + Tall + .? p + + Wide + .?(p) + + Irregular + none + + Reduction + none, natural + + [%hxgl p=tusk] + +#< ("haxgal") is a synthetic rune that slams the assumed gate noah on +[%zpgr %cntr p]. See the Biblical names. + + Tall/Wide + none + + Irregular + >i.p i.t.p i.t.t.p< + + Reduction + See ++open + + [%hxgr p=tusk] + +#> ("haxgar") is a synthetic rune that slams the assumed gate cain on +[%zpgr %cntr p]. See the Biblical names. + + Tall/Wide + none + + Irregular + + + Reduction + See ++open + + [%ktbr p=twig] + +^| ("ketbar") is a natural rune that converts a %gold core into an %iron +core. See geometric polymorphism. + + Tall + ^| p + + Wide + ^|(p) + + Irregular + none + + Reduction + none, natural + + [%ktdt p=twig q=twig] + +^. ("ketdot") is a synthetic rune that casts q to the type of (p q). + + Tall + ^. p + q + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%ktls p=twig q=twig] + +^+ ("ketlus") is a natural rune that casts the product of q to the +type of p, verifying that it contains the type of q. + + Tall + +^ p + q + + Wide + ^+(p q) + + Irregular + none + + Reduction + none, natural + + [%kthp p=tile q=twig] + +^- ("kethep") is a synthetic rune that casts q to ~(bunt al p), +i.e., the icon of p. + + Tall + ^- p + q + + Wide + ^-(p q) + + Irregular + `p`q + + Reduction + See ++open + + [%ktpm p=twig] + +^& ("ketpam") is a natural rune that converts a %gold core to %zinc core. +See geometric polymorphism. + + Tall + ^& p + + Wide + ^&(p) + + Irregular + none + + Reduction + none, natural + + [%ktsg p=twig] + +^~ ("ketsig") is a natural rune that tries to execute p statically at +compile time; if this fails, p remains dynamic. + + Tall + ^~ p + + Wide + ^~(a) + + Irregular + none + + Reduction + none, natural + + [%ktts p=toga q=twig] + +^= ("kettis") is a natural rune that wraps q in the toga p. The +toga is a powerful naming device that can assign an entire name +tree to a properly typed result. For instance, if foo produces +an unlabeled tuple [x y z], [a b=[c d]]=foo produces +[a=x b=[c=y d=z]]. + + Tall + ^= p + q + + Wide + ^=(p q) + + Irregular + none + + Reduction + none, natural + + [%ktwt p=twig] + +^? ("ketwut") is a natural hoon that converts a %gold core into a +%lead core. See geometric polymorphism. + + Tall + ^? p + + Wide + ^?(p) + + Irregular + none + + Reduction + none, natural + + [%sgbr p=twig q=twig] + +~| ("sigbar") is a synthetic rune that presents the product of p +in the stack trace if q crashes. Only performed as needed. +Generates %cain - see the Biblical names. + + Tall + ~| p + q + + Wide + ~|(p q) + + Irregular + none + + Reduction + See ++open, ++feck + + [%sgcb p=twig q=twig] + +~_ ("sigcab") is a synthetic rune that inserts p, a trap producing a tank, +into the trace of q. + + Tall + ~_ p + q + + Wide + ~_(p q) + + Irregular + none + + Reduction + See ++open + + [%sgcn p=chum q=twig r=tyre s=twig] + +~% ("sigcen") is a synthetic rune that identifies a core for specific +optimization. See jet propulsion. + + Tall + ~% p + q + == + p.i.r q.i.r + p.i.t.r q.i.t.r + == + s + + ~% p + q + ~ + s + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%sgfs p=chum q=twig] + +~/ ("sigfas") is a synthetic rune that identifies an arm for specific +optimization. See jet propulsion. + + Tall + ~/ p + q + + Wide + ~/(p q) + + Irregular + none + + Reduction + See ++open + + [%sggl p=$|(term [p=term q=twig]) q=twig] + +~< ("siggal") is a synthetic rune that applies arbitrary hint p to +the product of q. Does not wake the hint engine until the +computation is finished. + + Tall + ~< p + q + + Wide + ~<(p q) + + Irregular + none + + Reduction + See ++open + + [%sggr p=$|(term [p=term q=twig]) q=twig] + +~> ("siggar") is a natural rune that applies arbitrary hint p to q. + + Tall + ~> p + q + + Wide + ~>(p q) + + Irregular + none + + Reduction + See ++open + + [%sgbc p=term q=twig] + +~$ ("sigbuc") is a synthetic rune that labels computation q as p +for profiling (not currently enabled). + + Tall + ~$ p + q + + Wide + ~$(p q) + + Irregular + none + + Reduction + See ++open + + [%sgls p=@ q=twig] + +XX Solve ~+ ("siglus") is a synthetic rune that memoizes computation q + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%sgpm p=@ud q=twig r=twig] + +~& ("sigpam") is a synthetic rune that prints q on the console +before computing r. p is the log priority 0-3, defaulting to 0. + + Tall + 0, debug + ~& q + r + + 1, notice + ~& > q + r + + 2, warning + ~& >> q + r + + 3, alarm + ~& >>> q + r + + Wide + ~&(>>> q r) + + Irregular + none + + Reduction + See ++open + + [%sgts p=twig q=twig] + +~= ("sigtis") is a synthetic rune that hints to the interpreter +that q may produce a noun equal to the already existing p, +avoiding duplication. + + Tall + ~= p + q + + Wide + ~=(p q) + + Irregular + none + + Reduction + See ++open + + [%sgwt p=@ud q=twig r=twig s=twig] + +~? ("sigwut") is a synthetic rune that prints r to the console +before computing s, iff q produces yes. p is the log priority, +0-3, 0 by default + + Tall + 0, debug + ~? q + r + s + + 1, notice + ~? > q + r + s + + 2, warning + ~? >> q + r + s + + 3, alarm + ~? >>> q + r + s + + Wide + ~?(>>> q r s) + + Irregular + none + + Reduction + See ++open + + [%sgzp p=twig q=twig] + +~! ("sigzap") is a natural rune for debugging uses only, +semantically equivalent to its own twig q. Should compilation +fail within q, ~! will show the type of p on the stacktrace. + + Tall + ~! p + q + + Wide + ~!(p q) + + Irregular + none + + Reduction + none, natural + + [%smcl p=twig q=tusk] + +;: ("semcol") is a synthetic gate that applies p, a binary gate, +to the n-ary tuple q. + + Tall + ;: p + i.q + i.t.q + i.t.t.q + == + + Wide + ;:(p i.q i.t.q i.t.t.q) + + Irregular + :(p i.q i.t.q i.t.t.q) + + Reduction + See ++open + + [%smdt p=twig q=tusk] +XX determine function + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smdq p=(list beer)] +XX determine if internal/external + +;" ("semdoq") is a synthetic rune used to make strings, +interpolated or not. + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smsg p=twig q=tusk] + +XX to do + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%smsm p=twig q=twig] + +;; ("semsem") is a synthetic rune that types q as a fixpoint of p. +Semantically identical to ((hard p) q). + + Tall + ;; p + q + + Wide + ;;(p q) + + Irregular + none + + Reduction + See ++open + + [%tsbr p=tile q=twig] + +=| ("tisbar") is a synthetic rune that pushes ~(bunt al p) on the +subject and sends it to q. + + Tall + =| p + q + + Wide + =|(p q) + + Irregular + none + + Reduction + =+(_p q) + See ++open, ++bunt in ++al + + [%tscl p=tram q=twig] + +=: ("tiscol") is a synthetic rune that produces q with the subject +by p. Uses %cncb, and so cannot change the subject type. + + Tall + =: p.i.p q.i.p + p.i.t.p q.i.t.p + p.i.t.t.p q.i.t.t.p + == + q + + Wide + none + + Irregular + noen + + Reduction + See ++open + + [%tscn p=twig q=twig] +XX to do + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%tsdt p=wing q=twig r=twig] + +=. ("tisdot") is a synthetic rune that produces r with p in the +subject set to q. Uses %cncb, and so cannot change the subject + p. + + Tall + =. p + q + r + + =. p q + r + + Wide + =.(p q r) + + Irregular + none + + Reduction + See ++open + + [%tsfs p=twig q=twig] + XX not used + + [%tsgl p=twig q=twig] + +=< ("tisgal") is a synthetic rune that uses the product of q as +the subject of p. + + Tall + =< p + q + + Wide + =<(p q) + + Irregular + + Reduction + See ++open + + [%tshp p=twig q=twig] + +=- ("tishep") is a synthetic rune that pushes q on the subject +and sends it to p. Dual of =+ ("tislup") + + + Tall + =- p + q + + Wide + =- + + Irregular + none + + Reduction + See ++open + + [%tsgr p=twig q=twig] + +=> ("tisgar") is a natural rune that uses the product of p as the +subject of q. + + Tall + => p + q + + Wide + =>(p q) + + Irregular + none + + Reduction + none, natural + + [%tskt p=twig q=twig r=twig s=twig] + +=^ ("tisket") is a synthetic rune that handles a product which is +a cell of the new result, and a mutation to the subject. + + Tall + Kingside + =^ p + q + r + s + + Queenside + =^ p q + r + s + + Wide + =^(p q r s) + + Irregular + none + + Reduction + See ++open + + [%tsls p=twig q=twig] + +=+ ("tislus") is a synthetic rune that pushes p on the subject +and sends it to q. Semantically equavlent to Nock 8.Dual of =- ("tishep") + + Tall + =+ p + q + + Wide + =+(p q) + + Irregular + none + + Reduction + See ++open + + [%tspm p=tile q=twig] + + XX not used + + [%tspt p=tile q=twig] + + XX not used + + [%tstr p=term q=wing r=twig] + +=* ("tistar") is a natural rune that creates a %bull, or alias, +type. + + Tall + =* p q + r + + Wide + =*(p q r) + + Irregular + none + + Reduction + none, natural + + [%tssg p=tusk] + +=~ ("tissig") is a synthetic rune that composes a list of twigs. + + Tall + Kingside + =~ i.p + i.t.p + i.t.t.p + == + + Queenside + =~ i.p + i.t.p + i.t.t.p + == + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%wtbr p=tusk] + +?| ("wutbar") is a synthetic rune that computes the "or" of the +loobeans in p. + + Tall + ?| i.p + i.t.p + i.t.t.p + == + + Wide + ?|(i.p i.t.p i.t.t.p) + + Irregular + |(i.p i.t.p i.t.t.p) + + Reduction + See ++open + + [%wthp p=wing q=tine] + +?- ("wuthep") is a synthetic rune that selects a case in q for +the actual type of p. + + Tall + Kingside + ?- p + p.i.q q.i.q + p.i.t.q q.i.t.q + p.i.t.t.q q.i.t.t.q + == + + Queenside + ?- p + p.i.q + q.i.q + p.i.t.q + q.i.t.q + p.i.t.t.q + q.i.t.t.q + == + + Wide + ?-(p p.i.q q.i.q, p.i.t.q q.i.t.q, p.i.t.t.q q.i.t.t.q) + + Irregular + none + + Reduction + See ++open + + [%wthz p=tiki q=tine] + +"wuthaz" is a synthetic internal rune that selects a case in q +for the actual type of p. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtcl p=twig q=twig r=twig] + +?: ("wutcol") is a natural rune that produces q if p is yes (&, 0), +or r if p is no (|, 1). + + Tall + ?: p + q + r + + Wide + ?:(p q r) + + Irregular + none + + Reduction + none, natural + + [%wtdt p=twig q=twig r=twig] + +?. ("wutdot") is a synthetic rune that prduces r if p is yes +(&, 0), of q if p is no (|, 1). + + Tall + ?. p + q + r + + Wide + ?:(p q r) + + Irregular + none + + Reduction + none, natural + + [%wtkt p=wing q=twig r=twig] + +?^ ("wutkey") is a synthetic rune that evaluates r if p is +equivalent to the bunt for its tile, otherwise q is evaluted. + + Tall + ?^ p + q + r + + Wide + ?^(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtkz p=tiki q=twig r=twig] + +"wutkaz" is a synthetic, internal rune that evaluates r if p is +equivalent to the bunt for its tile, otherwise q is evaluated. +See tikis. + + Tall + ?^ p + q + r + + Wide + ?^(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtgl p=twig q=twig] + +?< ("wutgal") is a synthetic hoon that produces q, asserting that +p is no (|, 1). + + Tall + ?< p + q + + Wide + ?<(p q) + + Irregular + none + + Reduction + See ++open + + [%wtgr p=twig q=twig] + +?> ("wutgar") is a synthetic hoon that produces q, asserting that +p is yes (&, 0). + + Tall + ?> p + q + + Wide + ?>(p q) + + Irregular + none + + Reduction + See ++open + + [%wtls p=wing q=twig r=tine] + +?+ ("wutlus") is a synthetic rune that selects a case in q for +the actual type of p. + + Tall + Kingside + ?+ p + q + p.i.r q.i.r + p.i.t.r q.i.t.r + p.i.t.t.r q.i.t.t.r + == + + Queenside + ?+ p + q + p.i.r + q.i.r + p.i.t.r + q.i.t.r + p.i.t.t.r + q.i.t.t.r + == + + Wide + ?+(p p.i.r q.i.r, p.i.t.r q.i.t.r, p.i.t.t.r q.i.t.t.r) + + Irregular + none + + Reduction + See ++open + + [%wtlz p=tiki q=twig r=tine] + +"wutlaz" is a synthetic, internal rune that selects a case in q for +the actual type of p. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtpm p=tusk] + +?& ("wutpam") is a synthetic hoon that computes the "and" of the +loobeans in p. + + Tall + ?& i.p + i.t.p + i.t.t.p + == + + Wide + ?&(i.p i.t.p i.t.t.p) + + Irregular + none + + Reduction + See ++open + + [%wtpt p=wing q=twig r=twig] + +?@ ("wutpat") is a synthetic hoon that produces q if p is an +atom, r otherwise. + + Tall + Kingside + ?@ p + q + r + + Queenside + ?@ p + q + r + + Wide + ?@(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtpz p=tiki q=twig r=twig] + +"wutpaz" is a synthetic hoon that produces q if p is an atom, r +otherwise. + + Tall + ?@ p + q + r + + Wide + ?@(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtsg p=wing q=twig r=twig] + +?~ ("wutsig") is a synthetic rune that produces q if p is ~, r +otherwise. + + Tall + ?~ p + q + r + + Wide + ?~(p q r) + + Irregular + none + + Reduction + See ++open + + [%wtsz p=tiki q=twig r=twig] + +"wutsaz" is a synthetic internal rune that produces q if p is ~, +r otherwise. + + Tall/Wide/Irregular + none, internal + + Reduction + See ++open + + [%wtts p=tile q=wing] + +?= ("wuttis") is a natural rune that produces true if the leg at +wing q is in tile p. + + Tall + ?= p + q + + Wide + ?=(p q) + + Irregular + none + + Reduction + none, natural + + [%wtzp p=twig] + +?! ("wutzap") is a synthetic rune that produces the logical "not" +of p. + + Tall + ?! p + + Wide + ?!(p) + + Irregular + !p + + Reduction + See ++open + + [%zpcb p=spot q=twig] +XX tall/wide form +!_ ("zapcab") is a natural rune that puts debugging information +in the stack trace. + + Tall + + Wide + + Irregular + none + + Reduction + none, natural + + [%zpcm p=twig q=twig] + +!, ("zapcom") is a natural rune that inserts twig q as a +constant, typed with the type of twig p. + + Tall + !, p + q + + Wide + !,(p q) + + Irregular + none + + Reduction + none, natural + + [%zpcn ~] +XX determine function +!% ("zapcen") + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%zpfs p=twig] +XX tall/wide +!/ ("zapfas") is a natural rune that should never be compiled. +When compiled with error checking turned on, it reports its +subject as an error. + + Tall + + Wide + + Irregular + + Reduction + See ++open + + [%zpgr p=twig] + +!> ("zapgar") is a synthetic rune that produces a vase (a +[type noun] cell) with the value p. + + Tall + !> p + + Wide + !>(p) + + Irregular + none + + Reduction + See ++open + + [%zpsm p=twig q=twig] + +!; ("zapsem") is a natural rune that produces the product of twig +q as a [type noun] pair, with twig p defining the type of the type. + + Tall + !; p + q + + Wide + !;(p q) + + Irregular + none + + Reduction + none, natural + + [%zpts p=twig] + +!= ("zaptis") is a natural rune that produces the formula of twig +p as a noun. + + Tall + != p + + Wide + !=(p) + + Irregular + none + + Reduction + none, natural + + [%zpwt p=$|(p=@ [p=@ q=@]) q=twig] + +!? ("zapwut") is a synthetic rune that enforces a Hoon version +restriction. + + Tall + !? p + q + + Wide + none + + Irregular + none + + Reduction + See ++open + + [%zpzp ~] + +!! ("zapzap") is a natural rune that always causes a crash when +executed. + + Tall + none + + Wide + !! + + Irregular + none + + Reduction + none, natural + +--- + diff --git a/main/pub/src/doc/ref/hoon/morphology.md b/main/pub/src/doc/ref/hoon/morphology.md new file mode 100644 index 000000000..7b5fa3a23 --- /dev/null +++ b/main/pub/src/doc/ref/hoon/morphology.md @@ -0,0 +1,228 @@ +Morphology +========== + +Hoon is a statically typed language that compiles to Nock. + +Types +----- + +Types are nouns the compiler keeps around as it turns your Hoon into Nock. + +A type serve two purposes: + +1. It defines a set of nouns. Any finite noun is either in this set, or not in + it. + +2. it ascribes semantics to all nouns in this set. For example, a Hoon type + exports a semantic namespace. + + +These are defined in Hoon as one of the ten kinds of type found in `++type`. + +At its most general, the `noun` type contains all Hoon nouns. Everything in +Hoon is a noun. The `%void` type contains no values at all. The `%atom` type +contains only atoms. The `%cube` type is parameterized by a value, and it +contains only that single value. The other types are defined in the lexicon. + +Type inference in Hoon works well enough that there is no direct +syntax for defining or declaring a type. There is only a syntax for +constructing twigs. Types are always produced by inference. + + +When resolving a face, for example, the axis that +ends up in the nock formula depends on the where the face is in the subject. +We only know this because faces are in the subject type. Thus, in `=> [p=42 +q=1.337] p`, the `p` twig compiles to nock `[0 2]` while in `=> [q=42 p=1.337] +p`, the `p` twig compiles to nock `[0 3]`. This is true even though the actual +nock produced by `[p=42 q=1.337]` is the same as that produced by `[q=42 +p=1.337]`. Thus, the nock formula may depend on the subject type. It is for +this reason that we say that a type defines not only a set of values, but also +the semantics for operating on those values. + + +Tiles +----- + +What are the usual things we want to do with types? + +- Test if a noun is of a particular type. + +- Create a blank default example of a type + +- Coerce a noun into a type + +It is possible to generate twigs for each of the above use cases from two +pieces of information: (1) a tile describing a type and (2) a reference to +which case we want to generate. + +Tiles are not types. + +Every tile has a unique associated type, or "icon". + +A tile is not a type, but every tile corresponds to some type. + +Formalizing the operations on a tile, there are exactly four. + +Bunting a tile is simply creating a blank default example of the tile's icon. +This may seem to have limited usefulness, but this is actually the most common +use of tiles. This is due to the the way in which we create, for example, +gates. The sample of a gate is usually defined in terms of a tile, as in `|= +[p=@ q=@] (add p q)`. The `|=` rune takes a tile (in this case `[p=@ q=@]` +and bunts it to create a default sample of `[0 0]` with the type of a cell of +two atoms. Note that this is different from `|= [p=%0 q=%0] (add p q)`, +which still bunts to create a default sample of `[0 0]`, but whose type is a +cell of two constant `0`s. In the first case, when we call our gate, the type +checker will make sure that we are only ever replacing the sample with a cell +of two atoms, while in the second case the type checker will enforce that we +are only ever replacing the sample with a cell of two `0`s. + +Clamming a tile is creating a gate whose sample is a noun and whose product is +a member of the icon. This allows us to coerce any noun into any type. If the +noun is not a member of that type, then we produce some member of the type that +is either in some sense "similar" to the given noun or else we simply give a +default value, usually the bunt of this tile. + +Fishing a tile is testing whether a particular value is of that type. This +returns a loobean. This obviously has many uses. + +Whipping a tile is something you'll never have to do directly. Whipping is +never directly used in any Hoon source code. Whipping is used internally by +clamming. + +In summary, a tile is simply a convenient syntax for creating well-typed nouns. + +A tile is not a twig, but tiles always are reduced statically in one +of four ways to a twig. + + +Type Inference +-------------- + +Hoon is a higher-order typed functional language. Most languages in this class, +Haskell and ML being prominent examples, use something called the +Hindley-Milner unification algorithm. Hoon uses its own special sauce instead. + +Hoon's philosophy is that a language is a UI for programmers, and the basic +test of a UI is its predictability. It is impossible (for most programmers) +to learn a language properly unless they know what the compiler is doing, which +in practice means mentally stepping through the algorithms it uses (with the +exception of semantically neutral optimizations). Haskell is a hard language to +learn (for most programmers) because it's hard (for most programmers) to follow +what the Haskell compiler is thinking. + + +Broadly speaking, type inference in Hoon has three general limitations as +compared to Hindley-Milner inference. + +1. Hoon does not think backwards. For instance, it cannot infer a function's + argument type (or rather, a gate's sample type) from its body. + +2. Hoon can infer through tail recursion, but not head recursion. It can check + head recursion, however, given an annotation. + +3. The compiler catches most but not all divergent inference problems - i.e. + you can put the compiler into an infinite loop or exponential equivalent. + An interrupt will still show you your error location. + +Although an inference algorithm that reasons only forward must and does require +a few more annotations from the programmer, the small extra burden on her +fingers is more than offset by the lighter load on her hippocampus. +Furthermore, programs also exist to be read. Some of these annotations (which a +smarter algorithm might infer by steam) may annoy the actual author of the code +but be a lifesaver for her replacement. + +Our experience is that these limitations are minor annoyances at worst and +prudent restrictions at best. Your mileage may vary. + +Type inference is a frightening problem, especially if you've been exposed to +a wall of math. Your only real problem in learning Hoon is to learn not to +fear it. Once you work past this reasonable but entirely unfounded fear of +inference, your Hoon experience will be simple, refreshing and delightful. So +first, let's talk through a few reassuring facts: + +1. Type inference in Hoon never sees a tile. It operates exclusively on twigs. + All tiles and synthetic twigs are reduced to natural twigs for the inference + engine's benefit. + +2. The semantics of Hoon are in ++ut in hoon.hoon, and nowhere else. + +3. Within ++ut, all the semantics of Hoon are in the call graph of one arm: ++mint. + ++mint has a case for every natural hoon. So do ++play and ++mull, + but their semantics are redundant with ++mint. + +4. One leg in the sample of ++mint - gol - which looks for all the world like a + mechanism for backward inference, is not. It is semantically irrelevant and + only exists to get better localization on error reports. + +5. ++mint is the gate that maps [type twig] to [type nock]: + + [subject-type twig] => [product-type nock-formula] + + When we have a type that describes the subject for the formula we're trying to + generate, as we generate that formula we want to also generate a type for the + product of that formula on that subject. As long as subject-type is a + correct description of some subject, you can take any twig and compile it + against subject-type, producing a formula such that *(subject formula) is a + product correctly described by product-type. + + +Compilation +------------ + +`++make` is a top-level function that turns text into nock. + + ~hoclur-bicrel/try=> `*`(make '|= [@ @ud] +<') + [8 [1 0 0] [1 0 6] 0 1] + +Another way to do this is with `!=`. + + ~hoclur-bicrel/try=> !=(|=([@ @ud] +<)) + [8 [1 0 0] [1 0 6] 0 1] + +`++make` is more general, in that it can be called on programmatically +generated text, but `!=` is convenient for learning and debugging. + +The compilation process is as follows: + +First, a runic expression is parsed into an abstact syntax tree, called a +`twig`: + + text => twig + +Parsing code into a `twig` can be done with `++ream`: + + ~hoclur-bicrel/try=> (ream '|= [@ @ud] +<') + [ %brts + p=[p=[%axil p=[%atom p=~.]] q=[%axil p=[%atom p=~.ud]]] + q=[%cnts p=~[[%.y p=6]] q=~] + ] + +Refer to the Syntax section for more detail on parsing. + +The compiler proper, is `++mint` in `++ut`. + +++mint takes a twig and a subject type and produces a product type and a nock formula. + + [subject-type twig] => [product-type nock-formula] + +For example, we can call `++mint` on the twig we produced earlier with a +subject type of any noun: + + ~hoclur-bicrel/try=> + (~(mint ut %noun) %noun [%brts [[%axil [%atom ~.]] [%axil [%atom ~.ud]]] [%cnts ~[[%.y 6]] ~]]) + + [ p + [ %core + p=[%cell p=[%cell p=[%atom p=%$] q=[%atom p=%ud]] q=%noun] + q + [ p=%gold + q=[%cell p=[%cell p=[%atom p=%$] q=[%atom p=%ud]] q=%noun] + r=[p=[0 6] q={[p=%$ q=[%ash p=[%cnts p=~[[%.y p=6]] q=~]]]}] + ] + ] + q=[%8 p=[%1 p=[0 0]] q=[p=[%1 p=[0 6]] q=[%0 p=1]]] + ] + +Note that the head of the above is a type, which in this case is a gold core +with an ash gate. The second part, though, is (with a few labels, or faces added) the nock that was +produced by `++make`. diff --git a/main/pub/src/doc/ref/hoon/orthography.md b/main/pub/src/doc/ref/hoon/orthography.md new file mode 100644 index 000000000..3fdf6f0b0 --- /dev/null +++ b/main/pub/src/doc/ref/hoon/orthography.md @@ -0,0 +1,176 @@ +Orthography: Consensus Aesthetic +========== + +The Hoon compiler enforces the syntactical correctness of the language, it does +not, with some exceptions, enforce aesthetic standards. Many different styles +of Hoon are possible. However, given Hoon's runic syntax, it is remarkably easy +for the novice programmer to generate idiosyncratic illegible code. Many other +languages that make heavy use of ASCII have a similar problem. Furthermore, +collaborative programming is made vastly easier by using a standard style +convention. + +The Urbit source is written in a style of Hoon called the Consensus Aesthetic. +No patches to the Urbit source will be accepted unless they follow the ConsensusAesthetic. + +The general rules of the Consensus Aesthetic are the following: + +Character Restriction +--------------------- + +The horizontal tab character, \ht, ASCII 0x9, must never occur. This is +enforced by the compiler. + +Line and Comments +----------------- + +Lines must not exceed 80 columns in width and should not exceed 55 columns. + +Blank lines (lines consisting entirely of whitespace) should not occur. For +visual separation of code, use empty comments. + +Comments may appear on column 0, column 57 or inline at the same level of +indentation as the code. + +Indentation +----------- + +Aesthetically, the act of programming is the act of formatting a big wall of +text. This canvas has a curious but essential property - it is indefinitely +tall, but finitely wide. The programmer's task as a visual designer is to +persuade code to flow down, not across. + +The first law of Hoon indentation style is that all tall form indentation is in +two-space increments. Single spaces are for wide form only. + +The second law of Hoon indentation is that everything in the kernel is good +indentation style. Or at least if it's not, it needs to be changed. + +The third and most important law of Hoon indentation is that large twigs should +flow down and not across. The Aesthetic prescribes a backstep pattern, which +preserves indentation level in the common case: + + +``` +?: | + 47 +?: | + 52 +?: | + 7 +20 +``` + + +Notice that the first child is placed the furthest horizontal distance away +from its parent rune. Each of the subsequent children is outdented, such +that the last child (a similarly formatted twig) is vertically aligned with its parent. + +However, this convention does not always prevent horizontal drift. For example, +there are many cases when the last twig is not the heaviest: + +``` +?: & + ?: | + 52 + ?: | + 7 + 20 +47 +``` + +To handle cases like this, there exist several (synthetic runes)[lexicon/#rune_types] +that invert the argument order of common runes to ensure the last twig is the +heaviest. For example, where `?:` is _if-then_, `?.` is _unless_: + +``` +?. & + 47 +?: | + 52 +?: | + 7 +20 +``` + +###N-ary runes### +For runes that take an arbitrary number of children, the children are indented, +with the closing `==` aligned with the rune: + +``` +;~ plug + ace + ace +== +``` + +For runes operating on associative lists, there exist two indentation conventions: +Kingside, where the key-value pairs are (or at least start) on the same line: + +``` +%= res + key1 val + key2 val2 +== +``` + +And Queenside, where the keys lie indented on the line above their respective +values: + +``` +%= res + key + twig-producing-val + key2 + =+ a=2 + [a 3] +== +``` + +While both of these techniques are used to preserve the right margin, the +latter is used when the keys and/or values are especially heavy. + + +Naming Convention +----------------- + +Names must follow one of the following naming conventions: Austere, Lapidary, +or Freehand. + +In Austere Hoon, variables and arguments are named alphabetically with one +letter, a, b, c etc, in strict order of appearance in the text. This scheme is +only useful in the case of extremely regular and straightforward namespaces: +very short functions, for instance. + +Austere arms must be gates or trays. Gate arms are three letters and try to +carry some mnemonic significance - for instance, ++dec. Tray arms are two +letters and try to resemble pronouns - for instance, ++by. + +Austere structures must be short tuples, no wider than 5. The legs are named p, +q, r, s and/or t. + +Conventional recursive structures use other standard names. The head of a list +is always i, the tail is always t. In a binary tree of nodes, the node is n, +the children l and r. + +When in doubt, do not use Austere Hoon. In an ordinary context - not least +because Austere gates are easily mistaken for Lapidary variables - there should +be as few Austere arms as possible. And always remind yourself that Austere +Hoon makes it as hard as possible to refactor your code. + +Lapidary Hoon is the ordinary style of most of Hoon and Arvo. In lapidary mode, +variables, arguments, attributes, etc, are three-letter strings, usually +consonant-vowel-consonant, generally meaningless. If the same string is used +more than once in the same file, it should be used for the same concept in some +sense, as often happens spontaneously in cutting and pasting. It would be nice +to have an editor with a macro that generated random unique TLV strings +automatically. + +Lapidary arms are always four letters. They may or may not be English words, +which may or may not mean anything relevant. + +In Freehand Hoon, do whatever you want. Note that while uppercase is not +permitted in a symbol, - is, suggesting a generally Lisp-like state of gross +hyphenated disorder. F-mode is best used for top-layer software which nothing +else is based on; prototyping and casual coding; etc. Freehand Hoon is not an acceptable style for any code in the Urbit source proper, and is discouraged for production applications. + + diff --git a/main/pub/src/doc/ref/hoon/philosophy.md b/main/pub/src/doc/ref/hoon/philosophy.md new file mode 100644 index 000000000..40c9c1304 --- /dev/null +++ b/main/pub/src/doc/ref/hoon/philosophy.md @@ -0,0 +1,85 @@ +Philosophy +========== + +Hoon is a higher-order typed functional language that it compiles itself to +Nock in 3400 lines of Hoon. If this number is accurate (it is), Hoon is very +expressive, or very simple, or both. (It's both.) The bad news is that it +really has nothing at all in common, either syntactically or semantically, with +anything you've used before. + +By understanding Nock tutorial, you've actually come closer than you realize to +knowing Hoon. Hoon is actually not much more than a fancy wrapper around Nock. +People who know C can think of Hoon as the C to Urbit's Nock - just a +sprinkling of syntax, wrapped around machine code and memory. + +For instance, it's easy to imagine how instead of calculating tree axes by +hand, we could actually assign names to different parts of the tree - and those +names would stay the same as we pushed more data on the subject. + +The way we're going to do this is by associating something called a type with +the subject. You may have heard of types before. Technically, Hoon is a +statically typed language, which just means that the type isn't a part of your +program: it's just a piece of data the compiler keeps around as it turns your +Hoon into Nock. + +A lot of other languages use dynamic types, in which the type of a value is +carried along with the data as you use it. Even languages like Lisp, which are +nominally typeless, look rather typed from the Hoon perspective. For example, a +Lisp atom knows dynamically whether it's a symbol or an integer. A Hoon atom is +just a Nock atom, which is just a number. So without a static type, Hoon +doesn't even know how to print an atom properly. + +Most higher-order typed languages, Haskell and ML being prominent examples, use +something called the Hindley-Milner unification algorithm. Hoon uses its own +special sauce instead. + +Why? There are two obvious problems with Hindley-Milner as a functional type +system, the main one being the wall of heavy mathematics that greets you +instantly when you google it. We have heard some claims that Hindley-Milner is +actually quite simple. We urge all such claimants to hie themselves to its +Wikipedia page, which they'll surely be able to relieve of its present alarming +resemblance to some string-theory paper in Physics Review D. + +Nor is this in any way an an anti-academic stance. Quite the contrary. +Frankly, OS guys really quite seldom find themselves in the math-department +lounge, cadging stray grants by shamelessly misrepresenting the CAP theorem as +a result in mathematics. It doesn't seem too much to expect the mathematicians +to reciprocate this basic academic courtesy. + +Furthermore, besides the drawback that Hindley-Milner reeks of math and +programmers who love math are about as common as cats who love a bath - a +problem, but really only a marketing problem - Hindley-Milner has a genuine +product problem as well. It's too powerful. + +Specifically, Hindley-Milner reasons both forward with evaluation, and backward +from constraints. Pretty unavoidable in any sort of unification algorithm, +obviously. But since the compiler has to think both forward and backward, and +the programmer has to predict what the compiler will do, the programmer has to +think backward as well. + +Hoon's philosophy is that a language is a UI for programmers, and the basic +test of a UI is to be easy to use. It is impossible (for most programmers) to +learn a language properly unless they know what the compiler is doing, which in +practice means mentally stepping through the algorithms it uses (with the +exception of semantically neutral optimizations). Haskell is a hard language to +learn (for most programmers) because it's hard (for most programmers) to follow +what the Haskell compiler is thinking. + +It's true that some programmers have an effective mathematical intuition that +let them "see" algorithms without working through them step by step. But this +is a rare talent, we feel. And even those who have a talent don't always enjoy +exercising it. + +If a thorough understanding of any language demands high-grade mathematical +intuition in its programmers, the language as a UI is like a doorway that makes +you duck if you're over 6 feet tall. The only reason to build such a doorway in +your castle is if you and all your friends are short, and only your enemies are +tall. Is this really the case here? + +Although an inference algorithm that reasons only forward must and does require +a few more annotations from the programmer, the small extra burden on her +fingers is more than offset by the lighter load on her hippocampus. +Furthermore, programs also exist to be read. The modern code monkey is above +all things a replaceable part, and some of these annotations (which a smarter +algorithm might infer by steam) may annoy the actual author of the code but be +a lifesaver for her replacement. diff --git a/main/pub/src/doc/ref/hoon/phonology.md b/main/pub/src/doc/ref/hoon/phonology.md new file mode 100644 index 000000000..90630dc9d --- /dev/null +++ b/main/pub/src/doc/ref/hoon/phonology.md @@ -0,0 +1,226 @@ +Phonology +========= + +Glyphs +------ + +Hoon is a keyword-free language - any alphanumeric text in the program is part +of the program. Where other languages have reserved words, Hoon syntax uses +ASCII symbols, or glyphs. In normal English, many of these glyphs have +cumbersome multisyllabic names. As Hoon uses these glyphs heavily, it has its +own, more concise, naming scheme for them: + + ace space gal < per ) + bar | gar > sel [ + bas \ hax # sem ; + buc $ hep - ser ] + cab _ kel { sig ~ + cen % ker } soq ' + col : ket ^ tar * + com , lus + tec ` + doq " pam & tis = + dot . pat @ wut ? + fas / pel ( zap ! + + +A language is meant to be spoken. Even a programming language. Studies have +shown that even when we read silently, we activate the motor cortex that +controls our vocal cords. Even if we never speak these symbols, they're easier +to think if bound to simple sounds. + +Mnemonic aids for memorizing the above glyphs can be found in the comments of section 2eF of the Urbit Source, which is reprinted here: + +``` +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: section 2eF, parsing (ascii) :: +:: +++ ace (just ' ') :: spACE +++ bar (just '|') :: vertical BAR +++ bas (just '\\') :: Back Slash (escaped) +++ buc (just '$') :: dollars BUCks +++ cab (just '_') :: CABoose +++ cen (just '%') :: perCENt +++ col (just ':') :: COLon +++ com (just ',') :: COMma +++ doq (just '"') :: Double Quote +++ dot (just '.') :: dot dot dot ... +++ fas (just '/') :: Forward Slash +++ gal (just '<') :: Greater Left +++ gar (just '>') :: Greater Right +++ hax (just '#') :: Hash +++ kel (just '{') :: Curly Left +++ ker (just '}') :: Curly Right +++ ket (just '^') :: CareT +++ lus (just '+') :: pLUS +++ hep (just '-') :: HyPhen +++ pel (just '(') :: Paren Left +++ pam (just '&') :: AMPersand pampersand +++ per (just ')') :: Paren Right +++ pat (just '@') :: AT pat +++ sel (just '[') :: Square Left +++ sem (just ';') :: SEMicolon +++ ser (just ']') :: Square Right +++ sig (just '~') :: SIGnature squiggle +++ soq (just '\'') :: Single Quote +++ tar (just '*') :: sTAR +++ tec (just '`') :: backTiCk +++ tis (just '=') :: 'tis tis, it is +++ wut (just '?') :: wut, what? +++ zap (just '!') :: zap! bang! crash!! +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +``` + +Digraph Glyphs: Runes +-------------------- + +The fundamental building block of Hoon is the digraph glyph or rune. TThe choice of glyph is not random. The first defines a semantic category. That is, all runes whose first glyph is `|` or `bar` are conceptually related. See Morphology for details. + +To pronounce a rune, concatenate the glyph names, stressing the first syllable +and softening the second vowel into a "schwa." Hence, to say `~&`, say +"sigpam." To say `|=`, say "bartis." + +Punctuation Runes +---------------- + +The following runes are used as punctuation in Tall Form Hoon (See Syntax for details) and have mandatory special pronunciation: + + -- hephep phep + +- lushep slep + ++ luslus slus + == tistis stet + +Wing Runes +--------- + +The following runes are used to access specific axes or wings in a noun. See Morphology. They have optional alternate phonology. + + +< lusgal glus + +> lusgar gras + -< hepgal gelp + -> hepgar garp + +Tile Runes +--------- + +The following runes comprise the set of "Tile Runes" and are used to generate +complex types (See Morphology for details). They have an optional alternate +phonology, which describes the tile they generate: + + $% buccen kelp + $^ bucket herb + $: buccol tile + $= buctis bark + $& bucpam bush + $? bucwut fern + $| bucbar reed + +The following glyphs are not runes, but are commonly used with tile runes to specify basic types. (See Morphology for details). In context, they have an optional alternate phonology: + + @ "atom" + ^ "cell" + * "noun" + ? "bean" + ~ "null" + +Irregular Runes +-------------- + +The following glyphs have optional special pronunciation when they appear as +the irregular form as certain digraph runes. It is perfectly acceptable to +pronounce the characters, but some may find the alternate phonology useful, +especially in cases where multiple irregular forms occur in sequence. + +Irregular Regular Pronunciation + + ,p $,(p) "clam p" + _p $_(p) "bunt p" + p@q $@(p q) "whip p into q" + !p ?!(p) "NOT p" + &(p q) ?&(p q) "AND p q + |(p q) ?|(p q) "OR p q" + ?(p q) $?(p q) "fern p q" + `p`q ^-(p q) "cast p q" + p=q ^=(p q) "p is q" + ~[p q] :~(a b) "list p q" + `[p] [~ p] "unit p" + p^q [p q] "cell p q" + [p q] :*(p) "cell p q" + +(p) .+(p) "bump p" + =(p q) .=(p q) "equals p q" + p:q =<(p q) "p of q" + p(q r) %=(p q r) "toss p q r" + (p q) %-(p q) "slam p q" + ~(p q r) %~(p q r) "slug p q r" + +Nouns +----- + +Some nouns also have an alternate phonology: + + + & "yes" + %& "yes" + %.y "yes" + + | "no" + %| "no" + %.n "no" + + 42 "forty-two" + 0i42 "dec four two" + 0x2e "hex two e" + 0b10 "bin one zero" + 0v3t "base thirty two three t" + 0wA4 "base sixty-four big a four" + + 'foo' "cord foo" + "foo" "tape foo" + + +Example +------- + +Take the following snippet of Hoon: + + ++ dec :: decrement + ~/ %dec + |= a=@ + ~| %decrement-underflow + ?< =(0 a) + =+ b=0 + |- ^- @ + ?: =(a +(b)) + b + $(b +(b)) + +Omitting the spaces and comments (which only a real purist would include), the +above is pronounced: + + slus dec + sigfas cen-dec + bartis A tis pat + sigbar cen-decrement-underflow + wutgal tis zero A + tislus B tis zero + barhep kethep pat + wutcol tis A lus B + B + buc B lus B + +Or using the alternate phonology: + + slus dec + sigfas cen-dec + bartis A is atom + sigbar cen-decrement-underflow + wutgal equals zero A + tislus B is zero + barhep kethep atom + wutcol equals A lus B + B + buc B lus B + +Which is very similar. The alternate phonology exists as a result of common +speech patterns observed amongst Hoon programmers in the wild. In any language +actually spoken by actual humans, laziness soon rounds off any rough edges. + diff --git a/main/pub/src/doc/ref/hoon/syntax.md b/main/pub/src/doc/ref/hoon/syntax.md new file mode 100644 index 000000000..35084a907 --- /dev/null +++ b/main/pub/src/doc/ref/hoon/syntax.md @@ -0,0 +1,483 @@ +Syntax +====== + +Runes +----- + +Everything in hoon is parsed into an abstract syntax tree (AST), called a `twig`. +A `twig` is a (frond)[lexicon/#fronds] composed of a (cubic)[lexicon/#cubes] +rune and one or more children: + +``` +~zod/try=> :-(1 2) +[1 2] +~zod/try=> (ream ':-(1 2)') +[%clhp p=[%dtzy p=%ud q=1] q=[%dtzy p=%ud q=2]] +``` + +As the expression above begins with `:-`, it is parsed into the twig +`[%clhp p=twig q=twig]`, which accepts two twigs with which it produces a +tuple. In this case, both elements are atom literals and are parsed into the twig +`[%dtzy p=term q=@]`, which produces atomic constants. + +There are several valid twig syntaxes in hoon, which are covered below. + +###Tall Form + +For all multiline expressions, Tall form is used. To avoid the visual problems +that deep expression trees cause in other functional languages (namely excessive +parentheses and the tendencey for code to drift horizontally off the right side +of the screen), hoon employs neither multiline braces nor significant +indentation. Instead, when a twig, such as the `[%clhp p=twig q=twig]` from +above is parsed, the parser then knows that exactly two twigs are to follow. In +Tall Form, twigs are separated by at least two spaces (a newline is equivalent +to two spaces). + +These rules do not prevent the aforementioned problem horizontal drift: + +``` +?: | + 47 + ?: | + 52 + ?: | + 7 + 20 +``` + +**Note:** `?:` initiaties an _if-then_else_ twig. `|` is the loobean false. + +To avoid this problem, the official convention prescribes a backstep pattern, which +preserves indentation level in the common case: + + +``` +?: | + 47 +?: | + 52 +?: | + 7 +20 +``` + + +Notice that the first child is placed the furthest horizontal distance away +from its parent rune. Each of the subsequent children is outdented, such +that the last child (a similarly formatted twig) is vertically aligned with its parent. + +However, this convention does not always prevent horizontal drift. For example, +there are many cases when the last twig is not the heaviest: + +``` +?: & + ?: | + 52 + ?: | + 7 + 20 +47 +``` + +To handle cases like this, there exist several (synthetic runes)[lexicon/#rune_types] +that invert the argument order of common runes. For example, where `?:` is _if-then_, `?.` is _unless_: + +``` +?. & + 47 +?: | + 52 +?: | + 7 +20 +``` + +####Closing Unbounded Twigs#### + +Some runes accept a list of an arbitrary number of children, +which is closed by a `==` (pronounced "stet"). By convention, the children +appear in an indented block, and for most runes, the `==` is aligned vertically with +its parent. + +``` +:* + 1 + 2 + 3 +== +:: [1 2 3] +``` + +Some runes, such as `;~`, [%smsg p=twig q=tusk]`, have both `twig` and `tusk` +(list of twigs) children: + +``` +;~ plug + ace + ace +== +``` + +####Kingside and Queenside#### + +Runes such as %= accept associative lists. There exist two conventions: +Kingside, where the key-value pairs are (or at least start) on the same line: + +``` +%= res + key1 val + key2 val2 +== +``` + +And queenside, where the keys lie indented on the line above their respective +values: + +``` +%= res + key + twig-producing-val + key2 + =+ a=2 + [a 3] +== +``` + +The latter is useful when the keys and/or values are heavy. + +####Reference[#tall-reference] + +For specific rune syntaxes, see the [lexicon](). +The regular form parser, `++norm:vast`, can also be helpful: for example, %dtls +(increment) is parsed by + +``` +++ norm :: rune regular form + |= tol=? + =< %- stew + ^. stet ^. limo + :~ :- '|' + :: ......code skipped....... +``` + +``` + :- '.' + ;~ pfix dot + %- stew + ^. stet ^. limo + :~ ['+' (rune lus %dtls expa)] +``` + +``` + ++ expa |.(loaf) :: one twig +``` + +``` + ++ loaf ?:(tol tall wide) :: hoon, current width +``` + +###Wide + +Wide form is a more compact and visually structured twig syntax, where an +expression can be no longer than one line. Notably, children are enclosed by +parentheses, and twigs are separated by single spaces: + +``` +?:((gth 1 2) %abort-abort %correct) +``` + +While Tall Form expressions can contain wide form expressions, the converse is +invalid hoon: + +``` +?: .=(a b) + 0 +1 +:: succeeds +?:(.= a + b 0 1) +:: fails +``` + +There are two other notable differences from Tall Form: `==` is no longer used, +having been made redundant by closing parentheses; and, the syntax for +associative lists gains a `','` between pairs: + +``` +?-(a 0 %even, 1 %odd) +:: vs. +?- a + 0 %even + 1 %odd +== +``` + +####Reference + +For specific rune syntaxes, see the [lexicon](). +The regular form parser, `++norm:vast`, can also be [helpful.](#tall-reference). + +###Irregular + +For many common runes, there exist special wide forms. For example, +the rune `:*`, which was used as an example in the tall section[linkToExample](), +is more frequently employed in its irregular form, a list of twigs surrounded +by brackets: + +``` +~zod/try=> [1 2] +[1 2] +~zod/try=> (ream '[1 2]') +[%cltr p=~[[%dtzy p=%ud q=1] [%dtzy p=%ud q=2]]] +``` + +A comprehensive list of all of these irregular forms can be found in the +[lexicon](lexicon/irregular-section)i, and the irregular form parser +`++scat:vast`. + +###Tile + +Some runes accept [tiles](lexicon) instead of/in addition to twigs as children. + +These runes switch us into tile syntax: + + Tiles have a similar syntax to twigs when: + + Examples + + + And different + + 1.The irregular forms for `^=` and `:*`, infix `=` and surrounding `[]` + repsectively, now denote `$=` and `$:` + + 2.Primitive types `'@'`, `'^'`, and `'*'` represent their tiles. + + 3.Number literals represent their cubes, and are along with actual cubes + interpreted as their associated clams. + + +Tile syntax defaults to parsing a twig, and using the result as a + [clam](lexicon). + + + +``` +~zod/try=> *a=@ud +a=0 +``` + + +`a=@ud` is a `tile`, representing a face _a_ wrapped around an atom of [odor]() +_unsigned-decimal_. + +Tile syntax is similar to that of twigs, except that `'@'`, `'^'`, and `'*'` +represent the [clams](lexicon) for the `atom`, `cell`, and `noun` primitive types, +and numeric literals become cubed. When a twig is encountered, its product is +used as a clam directly: + +``` +|= a=(list char) +[' ' a] +``` + +See [lexicon tiles[, parser `++noil:vast` + +Wings +----- + +Items in the subject are accesed with wings + +``` +> =<(a.b.+.c c=[4 [b=[a=1 2] b=[a=6 7]]) +6 +``` + +Limbs and axes, separated by dots, inner to outer. + +Limbs are terms, axes (have a few syntaces)[lexicon axis syntax] + +See:** + +Nouns +----- + +Most common rune is the virtual %dtzy, atomic nock 1 + +``` +>(ream '42') +[%dtzy p=%ud q=42] +``` + +Its counterpart %dtzz does cubes + +``` +>(ream '%42') +[%dtzz p=%ud q=42] +``` + +See [lexicon atoms] + +Tapes + +###Interpolation + +``` +"This is an {(weld "inter" (trip %polate))}d string" + + +Dependencies (%ford) +-------------------- + +While !^ provides rudimentary %clay includes... + + +See: ford.hoon + +Templating (++sail) +------------------- + +Start with `;term` + +``` +;html + ;head:title:"Hello" + ;body + ;p + ; Text with some ;{b "bolded"} + ; and some -{(weld "inter" "polate"}d + == + == +== +``` + +See: + +Generates `manx`, xml nouns. +[lexicon template lang], parser `++sail:vast`. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.= ~[1 2 3 4 5 6] +:~ 1 + 2 + 3 + 4 + 5 + 6 +== + +:* 1 3 4 == +:- 1 :- 3 4 +1^3^4 +[1 3 4] + + + +':-' is constructing a tuple of two elements, constants... + +``` +~zod/try=>(mul 4 (add 2 3)) +20 +~zod/try=> (ream '(mul 4 (add 2 3))') +[ %cnhp + p=[%cnzz p=~[%mul]] + q + ~[ + [%dtzy p=%ud q=4] + [%cnhp p=[%cnzz p=~[%add]] q=~[[%dtzy p=%ud q=2] [%dtzy p=%ud q=3]]] + ] +] +``` + +A twig is a (frond)[lexicon frond] composed of a rune and one or +more children; here, we see `%cnhp %cnzz %dtzy`, which are defined +in `++twig` as: + +``` +++ twig $& [p=twig q=twig] :: + $% + [%cnhp p=twig q=tusk] :: slam p w/ sample q + [%cnzz p=wing] :: pulls p + == + +++ tusk (list twig) :: +``` + +Skipping the particulars, '%-' (slams gates)[lexicon gates], %cnzz is a virtual +rune that (pulls arms)[lexicon cores], and %dtzy is a virtual rune that +; the resulting twig representing fetching `add` and `mul`, +and applying them to 2, 3, and 4. + +``` +++ twig $% :: + [%$ p=axis] :: simple leg + :: :: + [%bccb p=tile] :: bunt a tile + :: etc. + == +``` diff --git a/main/pub/src/doc/ref/volumes/0.md b/main/pub/src/doc/ref/vol/0.md similarity index 100% rename from main/pub/src/doc/ref/volumes/0.md rename to main/pub/src/doc/ref/vol/0.md diff --git a/main/pub/src/doc/ref/volumes/1.md b/main/pub/src/doc/ref/vol/1.md similarity index 100% rename from main/pub/src/doc/ref/volumes/1.md rename to main/pub/src/doc/ref/vol/1.md diff --git a/main/pub/src/doc/ref/volumes/2/2a.md b/main/pub/src/doc/ref/vol/2a.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2a.md rename to main/pub/src/doc/ref/vol/2a.md diff --git a/main/pub/src/doc/ref/volumes/2/2b.md b/main/pub/src/doc/ref/vol/2b.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2b.md rename to main/pub/src/doc/ref/vol/2b.md diff --git a/main/pub/src/doc/ref/volumes/2/2c.md b/main/pub/src/doc/ref/vol/2c.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2c.md rename to main/pub/src/doc/ref/vol/2c.md diff --git a/main/pub/src/doc/ref/volumes/2/2d/2dA.md b/main/pub/src/doc/ref/vol/2dA.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2d/2dA.md rename to main/pub/src/doc/ref/vol/2dA.md diff --git a/main/pub/src/doc/ref/volumes/2/2d/2dB.md b/main/pub/src/doc/ref/vol/2dB.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2d/2dB.md rename to main/pub/src/doc/ref/vol/2dB.md diff --git a/main/pub/src/doc/ref/volumes/2/2d/2dC.md b/main/pub/src/doc/ref/vol/2dC.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2d/2dC.md rename to main/pub/src/doc/ref/vol/2dC.md diff --git a/main/pub/src/doc/ref/volumes/2/2d/2dD.md b/main/pub/src/doc/ref/vol/2dD.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2d/2dD.md rename to main/pub/src/doc/ref/vol/2dD.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eA.md b/main/pub/src/doc/ref/vol/2eA.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eA.md rename to main/pub/src/doc/ref/vol/2eA.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eb.md b/main/pub/src/doc/ref/vol/2eB.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eb.md rename to main/pub/src/doc/ref/vol/2eB.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eC.md b/main/pub/src/doc/ref/vol/2eC.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eC.md rename to main/pub/src/doc/ref/vol/2eC.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eE.md b/main/pub/src/doc/ref/vol/2eE.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eE.md rename to main/pub/src/doc/ref/vol/2eE.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eF.md b/main/pub/src/doc/ref/vol/2eF.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eF.md rename to main/pub/src/doc/ref/vol/2eF.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eG.md b/main/pub/src/doc/ref/vol/2eG.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eG.md rename to main/pub/src/doc/ref/vol/2eG.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eH.md b/main/pub/src/doc/ref/vol/2eH.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eH.md rename to main/pub/src/doc/ref/vol/2eH.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eI.md b/main/pub/src/doc/ref/vol/2eI.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eI.md rename to main/pub/src/doc/ref/vol/2eI.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eJ.md b/main/pub/src/doc/ref/vol/2eJ.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eJ.md rename to main/pub/src/doc/ref/vol/2eJ.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eK.md b/main/pub/src/doc/ref/vol/2eK.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eK.md rename to main/pub/src/doc/ref/vol/2eK.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eL.md b/main/pub/src/doc/ref/vol/2eL.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eL.md rename to main/pub/src/doc/ref/vol/2eL.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eM.md b/main/pub/src/doc/ref/vol/2eM.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eM.md rename to main/pub/src/doc/ref/vol/2eM.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eN.md b/main/pub/src/doc/ref/vol/2eN.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eN.md rename to main/pub/src/doc/ref/vol/2eN.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eO.md b/main/pub/src/doc/ref/vol/2eO.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eO.md rename to main/pub/src/doc/ref/vol/2eO.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eP.md b/main/pub/src/doc/ref/vol/2eP.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eP.md rename to main/pub/src/doc/ref/vol/2eP.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eW.md b/main/pub/src/doc/ref/vol/2eW.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eW.md rename to main/pub/src/doc/ref/vol/2eW.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eX.md b/main/pub/src/doc/ref/vol/2eX.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eX.md rename to main/pub/src/doc/ref/vol/2eX.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eY.md b/main/pub/src/doc/ref/vol/2eY.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eY.md rename to main/pub/src/doc/ref/vol/2eY.md diff --git a/main/pub/src/doc/ref/volumes/2/2e/section2eZ.md b/main/pub/src/doc/ref/vol/2eZ.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2e/section2eZ.md rename to main/pub/src/doc/ref/vol/2eZ.md diff --git a/main/pub/src/doc/ref/volumes/2/2f/2fA.md b/main/pub/src/doc/ref/vol/2fA.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2f/2fA.md rename to main/pub/src/doc/ref/vol/2fA.md diff --git a/main/pub/src/doc/ref/volumes/2/2f/2fB.md b/main/pub/src/doc/ref/vol/2fB.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2f/2fB.md rename to main/pub/src/doc/ref/vol/2fB.md diff --git a/main/pub/src/doc/ref/volumes/2/2f/2fC.md b/main/pub/src/doc/ref/vol/2fC.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2f/2fC.md rename to main/pub/src/doc/ref/vol/2fC.md diff --git a/main/pub/src/doc/ref/volumes/2/2f/2fD.md b/main/pub/src/doc/ref/vol/2fD.md similarity index 100% rename from main/pub/src/doc/ref/volumes/2/2f/2fD.md rename to main/pub/src/doc/ref/vol/2fD.md diff --git a/main/pub/src/doc/ref/volumes/3/3a.md b/main/pub/src/doc/ref/vol/3a.md similarity index 100% rename from main/pub/src/doc/ref/volumes/3/3a.md rename to main/pub/src/doc/ref/vol/3a.md diff --git a/main/pub/src/doc/ref/volumes/3/3b.md b/main/pub/src/doc/ref/vol/3b.md similarity index 100% rename from main/pub/src/doc/ref/volumes/3/3b.md rename to main/pub/src/doc/ref/vol/3b.md diff --git a/main/pub/src/doc/ref/volumes/4.md b/main/pub/src/doc/ref/vol/4.md similarity index 100% rename from main/pub/src/doc/ref/volumes/4.md rename to main/pub/src/doc/ref/vol/4.md diff --git a/main/pub/src/doc/ref/vol/4a.md b/main/pub/src/doc/ref/vol/4a.md new file mode 100644 index 000000000..1d8c31fce --- /dev/null +++ b/main/pub/src/doc/ref/vol/4a.md @@ -0,0 +1,1958 @@ +Ames +==== + +Ames is our networking protocol. + +First we give commentary on the code, the algorithms involved, and the +protocol. We trace through the code touched when a packet is sent, received, +acknowledged, and that acknowledgment applied. This is fairly comprehensive, +and contains many implementation details, but if you understand this, then you +understand Ames. + +If you've scrolled down this page, you may be intimidated by the amount of Hoon +code, especially if you are new to the language. Don't be afraid of it, you +don't have to read any of it if you don't want to -- every interesting action +the code takes is explained in plain English. In fact, if you are new to the +language, this may be a good learning opportunity. Even if you don't +understand every line of Hoon code, you'll hopefully be able to follow most +lines. By the time you've worked through this, you'll have seen many common +patterns and best practices. Hoon, much more than other languages, is best +learned by reading and understanding large quantities of existing code. In +this way, it is similar to learning a natural language. All of this code is in +`arvo/ames.hoon`. + +After the commentary, we have reference documentation for all the data +structures that are specific to Ames. If you see a data structure or a +variable used that you don't recognize, search for it in the code, and it's +very likely defined in one of these data structures. We recommend that another +tab is kept open for easy access to the data structure reference documentation. +The code for these is split between `arvo/ames.hoon` and `arvo/zuse.hoon`. + +The Lifecycle of a Packet (or, How a Packet Becomes Law) +-------------------------------------------------------- + +Here, we will trace a packet as it makes its way through ames. There are +actually two pathways through ames: the legacy path through `%want`, and the +modern way, entered through `%wont`, with full end-to-end acknowledgments. +Here we will only trace the modern way, though much of the path is the same for +both. + +When an app (or a vane) wishes to send a packet to another ship, it must send a +`%wont` card: + +``` + [%wont p=sock q=path r=*] :: e2e send message +``` + +This card takes three arguments. The `p` is a `sock`, that is, a pair of two +ships, the first of which is the sender and the second is the receiver. But +wait, you ask, why do I get to decide who is the sender? Can I fake like I'm +someone else? The reason is that there are potentially multiple ships on the +same pier, and the kernel can send a message from any of them. If you attempt +to send a message from a ship not on your pier, then ames will refuse to send +it. If you hack around in your own copy of ames to go ahead and send it +anyway, then the other ship will reject it because your key is bad. Only send +messages from yourself. + +The `q` is a path, representing the place on the other side that you want to +receive your message. It is approximately equivalent to a port number. +Messages on the same path are guaranteed to arrive in the same order as they +were sent. No such guarantees are made across paths. + +The `r` is the actual data that you are sending. As the type implies, this can +be an arbitrary noun, and it will be transferred to the receiver exactly as-is, +in a well-typed way. Of course, this is data that is sent over the wire, so be +careful not to send anything too massive unless you're willing to wait. + +But enough about the interface. Grepping in ames.hoon for `%wont`, we find +that it appears in exactly two places: at its definition in `++kiss`, and in +`++knob`, where it is handled. We see that we go directly into `++wise:am`. + +``` + ++ wise :: wise:am + |= [soq=sock hen=duct cha=path val=* ete=?] :: send a statement + ^- [p=(list boon) q=fort] + zork:zank:(wool:(ho:(um p.soq) q.soq) hen cha val ete) +``` + +The inputs to this gate are exactly the sort of thing you'd expect. In +particular, everything in the `%wont` gate is here plus the calling duct so +that we know where to send the acknowledgment and `ete` to determine if we're +going to do the modern end-to-end acknowledgments. + +The actual line of code looks intimidating, but it's really not all that bad. +Working from the inside out, the call to `++um` sets up our domestic server, +and the call to `++ho` sets up our knowledge about the neighbor we're sending +to. From the outside, `++zork` and `++zank` just apply the changes made to our +`++um` and `++am` cores, respectively. If you're familiar with the common +idiom of `++abet`, that's all this is. The code predates the widespread usage +of that name. + +The interesting part, then, is in `++wool:ho:um:am`. Let's look at the code. + +``` + ++ wool :: wool:ho:um:am + |= [hen=duct cha=path val=* ete=?] :: send a statement + ^+ +> + =+ ^= rol ^- rill + =+ rol=(~(get by ryl.bah) cha) + ?~(rol *rill u.rol) + =+ sex=sed.rol + :: ~& [%tx [our her] cha sex] + =. ryl.bah + %+ ~(put by ryl.bah) cha + rol(sed +(sed.rol), san (~(put by san.rol) sex hen)) + =+ cov=[p=p:sen:gus q=clon:diz] + %+ wind [cha sex] + ?: ete + [%bund q.cov cha sex val] + [%bond q.cov cha sex val] +``` + +This is slightly more complicated, but it's still not all that bad. Our +inputs, at least, are fairly obvious. + +If you glance at the code for a second, you'll see that `++wind:ho:um:am` seems +to be able to send a message, or `++meal`, given a `++soup`. This gate, then, +just sets up the things we need to for `++wind` to do its job. + +We first get `rol`, which is a `++rill`, that is, a particular outbound stream. +This stream is specific to the path on which we're sending. If the path hasn't +been used before, then we create it. We let `sex` be the number of messages +we've already sent on this path. + +Then, we update the outbound stream by incrementing the number of messages sent +and placing an entry in `san.rol` that associates the message number with the +`duct` that sent the message. This allows us to give the acknowledgment to the +one who sent the message. + +We let `cov` be the current life of our crypto and our neighbor's crypto. At +the moment, we only need our neighbor's life, which we put into the meal. + +Finally, we call `++wind:ho:um:am` with the `++soup` of the path and message +number and the `++meal` of the payload itself. For end-to-end acknowledged +messages, we use `%bund`. + +``` + [%bund p=life q=path r=@ud s=*] :: e2e message +``` + +Looking at how we create the `%bund`, we can easily see what each field is for. + +Following the trail a little further, we go to `++wind:ho:um:am`. + +``` + ++ wind :: wind:ho:um:am + |= [gom=soup ham=meal] + :: ~& [%wind her gom] + ^+ +> + =^ wyv diz (zuul:diz now ham) + =^ feh puz (whap:puz now gom wyv) + (busk xong:diz feh) +``` + +`++wind` does three things: it (1) encodes the message into a list of +possibly-encrypted packets, (2) puts the message into the packet pump, and (3) +sends any packets that are ready to be sent. Yes, our nice little linear run +of each gate calling exactly one other interesting gate is over. We'll go in +order here. + +`++zuul:lax:as:go` is the what converts a `++meal` into a list of actual, 1KB +packets. + +``` + ++ zuul :: zuul:lax:as:go + |= [now=@da ham=meal] :: encode message + ^- [p=(list rock) q=_+>] + =< weft + ++ wasp :: null security + ++ weft :: fragment message + ++ wisp :: generate message +``` + +For organizational purposes, `++zuul` constructs an internal core with three +arms. `++wasp` encodes the meal into an atom with no encryption. `++wisp` +encodes a meal with possible encryption (else it simply calls `++wasp`). +`++weft` takes the result of `++wisp` and splits it into actual packets. + +``` + ++ wasp :: null security + ^-([p=skin q=@] [%none (jam ham)]) +``` + +This simply jams the meal, wrapping it with the `skin` of `%none`, meaning no +encryption. + +Since `++wisp` is a little long, we'll go through it line-by-line. + +``` + ++ wisp :: generate message + ^- [[p=skin q=@] q=_..wisp] +``` + +`++wisp` produces a pair of a `skin` and an atom, which is the meal encoded as +a single atom and possibly encrypted. + +``` + ?: =(%carp -.ham) + [wasp ..wisp] +``` + +If the meal that we're encoding is a `%carp`, then we don't encrypt it. A +`%carp` meal is a partial meal, used when a message is more than 1KB. Since +the entire message is already encrypted, we don't need to encrypt each packet +individually again. + +``` + ?: !=(~ yed.caq.dur) + ?> ?=(^ yed.caq.dur) + :_ ..wisp + :- %fast + %^ cat 7 + p.u.yed.caq.dur + (en:r:cluy q.u.yed.caq.dur (jam ham)) +``` + +If we have a symmetric key set up with this neighbor, then we simply use it. +The skin `%fast` is used to indicate a symmetric key. + +``` + ?: &(=(~ lew.wod.dur) |(=(%back -.ham) =(%buck -.ham))) + [wasp ..wisp] +``` + +If we do not yet have our neighbor's will, then there is no way that we can +seal the message so that only they may read it. If what we're sending is an +acknowledgment, then we go ahead and just send it in the clear. + +``` + =^ tuy +>.$ + ?:(=(~ lew.wod.dur) [*code +>.$] (griz now)) +``` + +If we don't have our neighbor's will, then we "encrypt" with a key of 0. If we +do have their will, then we generate a new symmetric key that we will propose. + +``` + :_ ..wisp + =+ yig=sen + =+ bil=law.saf :: XX send whole will + =+ hom=(jam ham) +``` + +`yig` will be the life and engine for our current crypto. `bil` is our will. +`hom` is the meal encoded as a single atom. + +``` + ?: =(~ lew.wod.dur) + :- %open + %^ jam + [~ `life`p.yig] + bil + (sign:as:q.yig tuy hom) +``` + +If we do not have our neighbor's will, then we send our current life along with +our will and the message. The message itself is "signed" with a key of 0. + +``` + :- %full + =+ cay=cluy + %^ jam + [`life`p.cay `life`p.yig] + bil + (seal:as:q.yig pub:ex:r.cay tuy hom) + -- :: --zuul:lax:as:go +``` + +If we do have our neighbor's will, then we send our perception of their current +life, our current life, our will, and the message. The message is sealed with +their public key so that only they can read our message. + +Once we have the message encoded as an atom, `++weft` goes to work. + +``` + ++ weft :: fragment message + ^- [p=(list rock) q=_+>.$] + =^ gim ..weft wisp + :_ +>.$ + ^- (list rock) +``` + +We're going to produce a list of the packets to send. First, we use the +aforementioned `++wisp` to get the message as an atom. + +``` + =+ wit=(met 13 q.gim) + ?< =(0 wit) +``` + +`wit` is the number of 1KB (2^13 bit) blocks in the message. We assert that +there is at least one block. + +``` + ?: =(1 wit) + =+ yup=(spit [our her] p.gim q.gim) + [yup ~] +``` + +If there is exactly one block, then we just call `++spit` to turn the message +into a packet. We'll explain what `++spit` does momentarily. + +``` + =+ ruv=(rip 13 q.gim) + =+ gom=(shaf %thug q.gim) + =+ inx=0 +``` + +If there is more than one block, then we rip it into blocks in `ruv`. `gom` is +a hash of the message, used as an id. `inx` is the number of packets we've +already made. + +``` + |- ^- (list rock) + ?~ ruv ~ + =+ ^= vie + %+ spit + [our her] + wasp(ham [%carp (ksin p.gim) inx wit gom i.ruv]) + :- vie + $(ruv t.ruv, inx +(inx)) +``` + +Here we package each block into a packet with `++spit` and produce the list of +packets. + +``` + ++ spit :: cake to packet + |= kec=cake ^- @ + =+ wim=(met 3 p.p.kec) + =+ dum=(met 3 q.p.kec) + =+ yax=?:((lte wim 2) 0 ?:((lte wim 4) 1 ?:((lte wim 8) 2 3))) + =+ qax=?:((lte dum 2) 0 ?:((lte dum 4) 1 ?:((lte dum 8) 2 3))) + =+ wix=(bex +(yax)) + =+ vix=(bex +(qax)) + =+ bod=:(mix p.p.kec (lsh 3 wix q.p.kec) (lsh 3 (add wix vix) r.kec)) + =+ tay=(ksin q.kec) + %+ mix + %+ can 0 + :~ [3 1] + [20 (mug bod)] + [2 yax] + [2 qax] + [5 tay] + == + (lsh 5 1 bod) +``` + +This is how we turn a message into a real packet. This has the definition of +the packet format. + +`wim` is the length of the sending ship, and `dum` is the length of the +receiving ship. There are only five possibilities for each of those, +corresponding to carriers, cruisers, destroyers, yachts, and submarines. These +are encoded in `yax` and `qax` as 0, 0, 1, 2, and 3, respectively. Thus, `wix` +and `vix` are the number of bytes that must be reserved for the ship names in a +packet. + +Next, we construct `bod` by simply concatenating the sending ship, the +receiving ship, and the body of the message. Then, we get the encryption +mechanism from `++skin`, which may be a 0, 1, 2, or 3, and put it in `tay`. + +Next, we concatenate together, bit by bit, some final metadata. We use three +bits for our protocol number, which is incremented modulo eight when there is a +continuity breach or the protocol changes. We use the final twenty bits of a +hash of the body (which, we suppose, makes it a twenty bit hash) for +error-checking. We use two bits to tell how much room is used in the body for +the sending ship, and another two bits for the receiving ship. Finally, we use +five bits to store the encryption type. Note that since there are only two +bits worth of encryption types, there are three unused bits here. This adds up +to 32 bits of header data. Finally, we concatenate this onto the front of the +packet. Thus, we can summarize the packet header format as follows. + +``` + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +|Proto| Hash of Body |yax|qax| Crypto | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +``` + +After this, there are `yax` bits of the sender name, `qax` bits of the receiver +name, and up to 8192 bits of data. Thus, the maximum size of a packet is +achieved in a message between two submarines with 8192 bits of data. This will +require 32+128+128+8192 = 8480 bits, or 1060 bytes. + +This concludes our discussion of `++zuul:lax:as:go`. If you recall from +`++wind:ho:um:am`, the list of packets from `++zuul` is passed into `++whap:pu` +to update the packet pump and get any packets that can be sent immediately. + +``` + ++ whap :: whap:pu + |= [now=@da gom=soup wyv=(list rock)] :: send a message + ^- [(list rock) _+>] + =. pyz (~(put by pyz) gom (lent wyv)) + =. +> + |- ^+ +>.^$ + ?~ wyv +>.^$ + %= $ + wyv t.wyv + nus +(nus) + diq (~(put by diq) (shaf %flap i.wyv) nus) + puq (~(put to puq) [nus `soul`[gom 0 | ~2000.1.1 i.wyv]]) + == + (harv now) +``` + +First, we put into `pyz` the id for this message and the number of its packets +that have not yet been acknowledged, which is of course the total number of +packets since we haven't even sent the packets. + +For every packet, we change three things in the state (`++shed`) of our packet +pump: (1) we increment `nus`, the number of packets sent; (2) we put the +packet number into `diq` keyed by a hash of the packet; and (3) we put the +packet into the packet queue, with the basic metadata of its id `gom`, 0 +transmissions, not live yet, last sent in the year 2000, and the packet itself. + +Finally, we harvest the packet pump. + +``` + ++ harv :: harv:pu + |= now=@da :: harvest queue + ^- [(list rock) _+>] + ?: =(~ puq) [~ +>(rtn ~)] + ?. (gth caw nif) [~ +>] + =+ wid=(sub caw nif) + =| rub=(list rock) + =< abet =< apse + |% +``` + +`++harv` contains a core for most of its work. The meat is in `++apse`. +First, though, it sets itself up. If there aren't any packets in the queue, +then we simply do nothing except set `rtn`, our next timeout, to nil because we +don't have any packets that may need to be retransmitted. If we have more live +(that is, sent and unacknowledged) packets than our window size, then we don't +do anything. + +Otherwise, we let `wid` be the width of our remaining packet window, and we +initialize `rub` to nil. `rub` will be the list of packets that are ready to +be sent. We then call `++apse` and pass the result to `++abet`. `++apse` +decides which packets are ready to be sent. + +``` + ++ apse + ^+ . + ?~ puq . + ?: =(0 wid) . + => rigt =< left + ?> ?=(^ puq) + ?: =(0 wid) . + ?. =(| liv.q.n.puq) . + :: ~& [%harv nux.q.n.puq p.n.puq] + %_ . + wid (dec wid) + rub [pac.q.n.puq rub] + nif +(nif) + liv.q.n.puq & + nux.q.n.puq +(nux.q.n.puq) + lys.q.n.puq now + == +``` + +If there are no remaining packets to send, or if we've filled the packet +window, do nothing. We call `++rigt` and `++left` to process the left and +right branches of the packet queue. + +Now we assert that the queue is not empty, and we again check that we haven't +filled the packet window. We will operate on the head of the queue. If the +packet is live, then do nothing. Otherwise, we go ahead and send it. + +To send, we (1) decrement `wid`, our packet window width; (2) cons the packet +onto the `rub`, which will be returned as the list of packets to send; (3) +increment `nif`, the number of live packets; (4) set the packet to be live; +(5) increment the number of transmissions of the packet; and (6) set the last +sent time of the packet to now. + +``` + ++ left + ?> ?=(^ puq) + ^+(. =+(lef=apse(puq l.puq) lef(puq [n.puq puq.lef r.puq]))) + ++ rigt + ?> ?=(^ puq) + ^+(. =+(rig=apse(puq r.puq) rig(puq [n.puq l.puq puq.rig]))) +``` + +These do exactly what you would expect: they traverse the packet queue so that +`++apse` gets called recursively through it. + +Finally, `++abet` gets called, which resolves the changes. + +``` + ++ abet + ?~ rub [~ +>.$] + [(flop rub) +>.$(rtn [~ (add rto now)])] +``` + +This returns the packets that we wish to send, and it updates the timeout so +that we know when to try resending unacknowledged packets. + +This concludes our discussion of `++whap:pu`. To finish `++wind:ho:um:am`, we +just need to delve into `++busk:ho:um:am`. But wait, in the call to `++busk`, +the first argument is `xong:diz`. What is this? This, my dear reader, is one +more detour, this time into `++xong:lax:as:go`. + +``` + ++ xong :: xong:lax:as:go + ^- (list ship) :: route unto + =+ [fro=xen too=xeno] + =+ ^= oot ^- (list ship) + =| oot=(list ship) + |- ^+ oot + ?~ too ~ + ?: (lien fro |=(a=ship =(a i.too))) ~ + [i.too $(too t.too)] + :: ~& [%xong-to [our her] (weld oot ?>(?=(^ fro) t.fro))] + (weld oot ?>(?=(^ fro) t.fro)) +``` + +This gets the list of intermediate ships needed to get a packet from us to our +neighbor. First, we get `fro` and `too`, the "canons" of ourself and our +neighbor, respectively. + +What is this "canon", you ask? A canon is simply a ship plus its "ancestors", +as defined by `++sein`. For example, the canon of `~hoclur-bicrel` is: + +``` +~hoclur-bicrel/try=> (saxo ~hoclur-bicrel) +~[~hoclur-bicrel ~tasruc ~tug] +``` + +If we follow the algorithm in `++xong`, we see that we are simply creating a +list of ships that form a path from our neighbor to ourself. Essentially, we +look through the canon of our neighbor until we find something in our own +cannon -- a common ancestor. Or, if we are from different carriers, then there +is no common ancestor. We then weld this onto the tail of our own canon. In +the end, this is simply a list of possible ships to try to route via to get to +our neighbor, ordered by preferability (that is, closeness to our neighbor). +We will end up trying, in order, to find a lane to these. + +Now, we can finally get to `++busk:ho:um:am`. + +``` + ++ busk :: busk:ho:um:am + |= [waz=(list ship) pax=(list rock)] :: send packets + %_ +> + bin + |- ^+ bin + ?~ pax bin + $(pax t.pax, bin (weld (flop (wist:diz now waz ~ i.pax)) bin)) + == +``` + +Thankfully, `++busk` is fairly simple. We go through the list of packets and +convert them to `++boon`s with `++wist:lax:as:go`. These boons are placed into +`bin`, and they end up getting processed by `++clop` (this happens in +`++knob`). + +``` + ++ wist :: wist:lax:as:go + |= $: now=@da :: route via + waz=(list ,@p) + ryn=(unit lane) + pac=rock + == + ^- (list boon) + ?: =(our her) [[%ouzo *lane pac] ~] + ?~ waz ~ + =+ dyr=?:(=(her i.waz) dur (gur i.waz)) + ?. ?& !=(our i.waz) + ?=(^ lun.wod.dyr) + == + $(waz t.waz) + :_ ?: ?=(%ix -.u.lun.wod.dyr) + $(waz t.waz) + ~ + :+ %ouzo u.lun.wod.dyr + ?: &(=(i.waz her) =(~ ryn)) pac + =+ mal=(jam `meal`[%fore her ryn pac]) + %- spit + ^- cake + :* [our i.waz] + ?~ yed.caq.dyr [%none mal] + :- %fast + %^ cat 7 + p.u.yed.caq.dyr + (en:crua q.u.yed.caq.dyr mal) + == +``` + +This takes a sample of the current time, the list of ships that we just +generated, a lane if we already know it, and the packet itself. + +First, if we are sending a message to ourself, then we simply create a `%ouzo` +boon with a bunted lane. Otherwise, if there are no routing candidates, there +is nothing we can do, so we return nil. + +Next, we get the `dore` of the first routing candidate. If we're looking at +the neighbor to whom we're trying to send the message, then we simply use the +`dore` that we already have. Otherwise, we get a default `dore`. + +If we're the first routing candidate, or if we have don't have a lane to this +candidate, then we skip this candidate and move on to the next one. + +If we have only a provisional ip address, then we try to send on it, but we +also try to send on later routing candidates as well. Otherwise, we only send +on this one candidate. + +Finally, we create the actual `%ouzo` boon. The lane is the one from our +`dore`. If we're sending it directly to our intended recipient, and we haven't +been told to use a specific lane, then we just send the packet directly. +Otherwise, we wrap it in a little `%fore` meal, telling the intermediary to +whom we wish it to be sent. If we have already set up a symmetric key with the +intermediary, then we encrypt it with that. Otherwise, we send it in the +clear. + +Now, if you recall, we have traced all the way through from the beginning when, +in `++knob`, the `%wont` card was handled by a call to `++wise`. There is only +one more step before the packet is finally sent. Looking in `++knob`, we see +that the resultant list of boons is passed into `++clop`, which will execute +the correct actions and return a list of moves. In `++clop`, we see the +handling of each specific boon. The one we are interested in is `%ouzo`, since +that is the only one we have sent thus far. + +``` + %ouzo + :: ~& [%send now p.bon `@p`(mug (shaf %flap q.bon))] + :_ fox + [[gad.fox [%give %send p.bon q.bon]] ~] +``` + +Very simply, we give a `%send` gift along the special duct that goes straight into +the bowels of unix. This is the last stop before we drop into vere, and later +libuv. And then... the world. + +The packet, after its creation, embarks on a journey across physical time and +space into the great unknown. Hurtling through fiber-optic cables at hundreds +of thousands of kilometers per second, it finally arrives at our neighbor's +network adapter. The adapter tells unix, unix tells libuv, libuv tells vere, +and vere sends a `%hear` kiss to ames. And now we reenter the kernel. + +The `%hear` kiss goes straight to `++knob`, just as did the `%wont` kiss +earlier. + +``` + %hear + (~(gnaw am [now fox]) %good p.kyz q.kyz) +``` + +Here, though, we call `++gnaw:am` to process the packet. The arguments to +`++gnaw` are the same as those to the `%hear` kiss: the lane on which the +packet was received and the packet itself. The other argument is just `%good`, +which is a `++cape` saying that we expect the packet to succeed. If a formal +error occurs, then since we have a transactional event system, the `%hear` +event will never be considered to have actually happened, and unix will send a +`%hole` kiss so that we may send a negative acknowledgment. + +``` + ++ gnaw :: gnaw:am + |= [kay=cape ryn=lane pac=rock] :: process packet + ^- [p=(list boon) q=fort] + ?. =(2 (end 0 3 pac)) [~ fox] + =+ kec=(bite pac) + ?: (goop p.p.kec) [~ fox] + ?. (~(has by urb.ton.fox) q.p.kec) + [~ fox] + =< zork + =< zank + %- ~(chew la:(ho:(um q.p.kec) p.p.kec) kay ryn %none (shaf %flap pac)) + [q.kec r.kec] +``` + +First, we check the protocol number. If it is not correct, then we simply +ignore the packet entirely. Otherwise, we parse the packet with `++bite`, +which converts a packet atom into a `cake`, that is, a triple of the `sock` +(pair of sender and receiver), the `skin` (encryption type), and the data. + +``` + ++ bite :: packet to cake + |= pac=rock ^- cake + =+ [mag=(end 5 1 pac) bod=(rsh 5 1 pac)] + =+ :* vez=(end 0 3 mag) :: protocol version + chk=(cut 0 [3 20] mag) :: checksum + wix=(bex +((cut 0 [23 2] mag))) :: width of receiver + vix=(bex +((cut 0 [25 2] mag))) :: width of sender + tay=(cut 0 [27 5] mag) :: message type + == + ?> =(2 vez) + ?> =(chk (end 0 20 (mug bod))) + :+ [(end 3 wix bod) (cut 3 [wix vix] bod)] + (kins tay) + (rsh 3 (add wix vix) bod) +``` + +This is exactly the inverse of `++spit`. Note that here we check both the +protocol number and the hash, crashing on error. Remember that a crash will +result in a negative acknowledgment being sent. + +Continuing in `++gnaw`, we see that if the intended recipient is not on our +pier, then we drop the packet. + +If we've gotten this far, then we wish to process the packet. Recall that +`++ho` and `++um` set up the domestic server and foreign client cores, +respectively, and that `++zork` and `++zank` resolve any changes to these +cores. + +The new stuff here, then, is the `++la` core and the `++chew` arm. The `++la` +sets up a core for this particular packet, containing the current +success/failure `cape`, the lane it was sent on, the encryption type, and a +hash of the packet, used as an id. + +`++chew` is called with the encryption type and the message itself. It contains +a little helper core inside of it, which starts immediately with `++apse`. + +``` + ++ apse + ^+ +>.$ + =+ oub=bust:puz + =+ neg==(~ yed.caq.dur.diz) + =. +>.$ east + =+ eng==(~ yed.caq.dur.diz) + =+ bou=bust:puz + =. bin + ?. &(oub !bou) bin + :_(bin [%wine [our her] " is ok"]) + =. bin + ?. &(neg !eng) bin + :_(bin [%wine [our her] " is your neighbor"]) + +>.$ +``` + +First, we let `oub` be true if our neighbor hasn't been responding to us for +more than sixteen seconds. Let `neg` be true if we haven't yet proposed a +symmetric key, meaning that we haven't yet corresponded with this ship, so they +are not our neighbor. Next, we run `++east`, which we'll go into in just a +minute. + +We now do the same two checks and store the results in `eng` and `bou`. If our +neighbor has, like the prodigal son, returned after an extended absense, then +we send a `%wine` boon as the proverbial fatted calf, which is simply printed +out to the console. Likewise, if we are meeting one with whom we have never +had the pleasure of acquainting ourselves, we send a message to the console to +that effect. + +We skipped over `++east`, which contains the meat of the processing. It first +decrypts the message, then calls `++chow:la:ho:um:am` with the resultant meal. +We'll go through each of the four cases in turn, but first since each one calls +`++bilk:pu`, we'll take a brief detour. + +``` + ++ bilk :: bilk:pu + |= now=@da :: inbound packet + ^+ +> + =+ trt=(mul 2 rtt) + %= +>.$ + rue [~ now] + rto trt + rtn ?~(puq ~ [~ (add now trt)]) + == +``` + +This updates the timing information in our packet pump. `rue`, the last time +we have heard from this neighbor, is set to now. `rto`, the retransmit timeout +is set to twice the current ping time, and if there is anything in the packet +queue, then we reset the next timeout, since we've just heard a message. + +Back to `++east`. + +``` + %none + =. puz (bilk:puz now) + (chow ((hard meal) (cue msg))) +``` + +The simplest case is when the encryption type is `%none`. We first call +`++bilk` to update the packet pump, then we cue (unjam) the message into a +meal. We hard cast it into a meal -- if the cast fails, then we do want to +crash since someone is sending us malformed data. Finally, we send the result +to `++chow` for interpretation and handling. + +``` + %fast + =+ [mag=`hand`(end 7 1 msg) bod=(rsh 7 1 msg)] + =+ dey=(kuch:diz mag) + ?~ dey + ~& [%bad-key her mag] + +>.$ :: ignore unknown key + =. puz (bilk:puz now) + =^ key diz u.dey + (chow(aut sin) ((hard meal) (cue (dy:q:sen:gus key bod)))) +``` + +For symmetric encryption, we first get the `hand`, which is the hash of the +symmetric key. We pass it to `++kuch:lax:as:go`, which returns the key if we +either have used it before or we have proposed it. If we have proposed it, +then we change its status from proposed to real. If `++kuch` fails, then +we drop the packet and print out a `%bad-key` message. + +Otherwise, we call `++bilk` as before to update the packet pump and pass into +`++chow` the decrypted data. + +``` + %full + =+ mex=((hard ,[p=[p=life q=life] q=will r=@]) (cue msg)) + =. diz (deng:diz q.mex) + =+ wug=cluy:diz + ?> =(q.p.mex p.wug) + =+ gey=(sev:gus p.p.mex) + =+ mes=(need (tear:as:q.gey pub:ex:r.wug r.mex)) + =. diz (wasc:diz p.mes) + =. puz (bilk:puz now) + (west(msg q.mes)) +``` + +For sealed asymmetric encryption, we first take off the the layer of data that +gives us the life and will of our neighbor, and we apply try to extend their former +will with the new data. `++deng` will fail if this is impossible. + +Next, we get our most current understanding of our neighbor's crypto, and we +verify that it's the same life as what they're sending. Then, we get our own +crypto from `++sev` and decrypt the message with the public key from our +neighbor's crypto. We register the proposed symmetric key, update the packet +pump, and call `++west`, which simply casts the message to a meal and calls +`++chow`, reporting any error. + +``` + %open + =+ mex=((hard ,[p=[~ q=life] q=will r=@]) (cue msg)) + =. diz (deng:diz q.mex) + =+ wug=cluy:diz + ?> =(q.p.mex p.wug) + =+ mes=(need (sure:as:r.wug *code r.mex)) + =. puz (bilk:puz now) + (west(msg mes)) +``` + +Finally, for signed asymmetric encryption, we, as before, take off the layer of +data that gives us the life and will of our neighbor. This time, of course, we +do not get our own crypto -- only that of our neighbor. + +The rest you have seen. We call `++deng` to extend the will, we verify that +their crypto life is what we think it ought to be, we "decrypt" the data, we +update the packet pump, and we call `++west` to call `++chow`. + +``` + ++ chow :: chow:la:ho:um:am + |= fud=meal :: interpret meal + ^+ +> + =. diz ?:(=(%none aut) diz (wast:diz ryn)) + (dine fud) +``` + +Here, if the message was encrypted at all, then we call `++wast:lax:as:go`, +which simply updates the lane (route) to our neighbor (unless we're given a +provisional route). This ensures that we always have the most direct possible +path to them. + +We've been handling this meal for so long, we've almost forgotten what we want +to do with it. The telos is of any meal to be dined on. We will choose out +the cases here that are important to our current investigation. + +``` + %fore + =+ ^= lyn ^- lane + ?~ q.fud ryn + ?. ?=(%if -.u.q.fud) u.q.fud + [%ix +.u.q.fud] + :: u.q.fud + ?: =(our p.fud) + (emit %mead lyn r.fud) + =+ zid=(myx:gus p.fud) + (emir (wist:zid now xong:zid [~ lyn] r.fud)) +``` + +Forwarding is the simplest case, since we've seen all the arms before, except +perhaps `++emit` and `++emir`, which simply take a boon or list of boons +respectively and queue them up to be handled when the core resolves. If we're +told to forward a packet to ourselves, then we emit a `%mead` boon which simply +sends another `%hear` kiss to ourselves with the data. Otherwise, we try to +find a route to the recipient, as before. + +``` + %carp + =+ zol=(~(get by olz.weg) s.fud) + ?^ zol cock(kay u.zol) + =^ neb nys.weg + =+ neb=(~(get by nys.weg) s.fud) + ?^ neb [u.neb nys.weg] + =+ neb=`bait`[(kins p.fud) 0 r.fud ~] + [neb (~(put by nys.weg) s.fud neb)] + ?> (lth q.fud p.r.neb) + ?> =((kins p.fud) p.neb) + ?> =(r.fud p.r.neb) + =+ doy=`(unit ,@)`(~(get by q.r.neb) q.fud) + ?^ doy cock + => ^+ . %= . + q.r.neb (~(put by q.r.neb) q.fud t.fud) + q.neb +(q.neb) + == + :: ~& [%carp q.fud s.fud q.neb p.r.neb] + ?: =(q.neb p.r.neb) + =: nys.weg (~(del by nys.weg) s.fud) + olz.weg (~(put by olz.weg) s.fud kay) + == + (golf p.neb r.neb) + =. +>.$ cock + +>.$(nys.weg (~(put by nys.weg) s.fud neb)) +``` + +Here, we have received a partial message, and we're just assembling the +individual packets into a message. Most of this code is fairly algorithmic, so +we'll just hit the high points. In the beginning, we check if we've already +received this message, and if so, we resend the acknowledgment. Remember, +"always ack a dupe, never ack an ack". + +In `nys.weg` we keep track of an incoming set of partial packets, indexed by +the `flap` hash that comes with every packet. We check to see if we have +already received this partial message, and if so we acknowledge it. Otherwise, +we put it in `nys.weg` unless this is the last message, in which case we ack +the last partial message, move the complete message into `olz.weg`, and call +`++golf`, which assembles the message and calls `++chew`, to start the dance +again with the complete message. + +``` + %bund + :: ~& [%bund q.fud r.fud] + ?> =(p:sen:gus p.fud) + (deer q.fud r.fud ?-(kay %dead ~, %good [~ s.fud])) +``` + +What if we're just receiving a regular old, garden variety message? We call +`++deer` with the data from the message. If we already know that the message +processing will fail (that is, if we got a `%hole` card from unix rather than a +`%hear` card), then we don't even send the data at all. Remember, if a packet +fails to process, it's as if it never even arrived, except that we send a +negative acknowledgment. + +``` + ++ deer :: deer:la:ho:um:am + |= [cha=path num=@ud dut=(unit)] :: interpret message + ^+ +> + =+ rum=(fall (~(get by raz.bah) cha) *race) + %= +>.$ + +> + ?. (gte num did.rum) :: always ack a dup + (cook (~(get by bum.rum) num) cha ~ ryn dam) + ?: dod.rum + (coat cha rum(mis (~(put by mis.rum) num [kay ryn dam dut]))) + %= +>.+>.$ + raz.bah + %+ ~(put by raz.bah) cha + rum(mis (~(put by mis.rum) num [kay ryn dam dut])) + == + == +``` + +First, we get the race for this particular triple of sender, receiver, and +path, creating it if it doesn't exist. If we've already acked the message, +then we resend the ack. Note that `did.rum` is the number of packets we +acknowledged, positively or negatively while `bum.rum` is a map of message +numbers to negative acknowledgments. Thus, if a message number is less than +`did.rum`, then if it's in `bum.rum` then it was negatively acknowledged, +otherwise it's postively acknowledged. Thus, we are constant in space with the +number of successful messages and linear in the number of failed messages. +We'll document `++cook` later on, but suffice it to say that it sends an +acknowledgment. It is to end-to-end acknowledgments what `++cock` is to +packet-level acknowledgments. + +If we are still processing a message (that is, `dod.rum` is false), then we +simply put this message in the map of misordered packets to be processed when +their time comes. "Processing a message" in this case means that we've +received the message and notified the correct application, but we're still +waiting for the application-level acknowledgment. + +Otherwise, we're ready for a packet, so we process it. + +``` + ++ coat :: coat:ho:um:am + |= [cha=path rum=race] :: update input race + ^+ +> + =+ cun=(~(get by mis.rum) did.rum) + ?~ cun + +>.$(raz.bah (~(put by raz.bah) cha rum)) + ?. =(%good p.u.cun) +>.$ + ?> ?=(^ s.u.cun) + %= +>.$ + raz.bah (~(put by raz.bah) cha rum(dod |)) + bin + :_ bin + :^ %mulk + [our her] + `soap`[[p:sen:gus clon:diz] cha did.rum] + u.s.u.cun + == +``` + +First, we grab the message we want to process and store it in `cun`. If it's a +good packet, then we change `dod.rum` to false, meaning that we're in the +middle of processing a packet and should not start processing another one. We +also put a `%mulk` boon into the queue so that, when it all resolves, we send a +mesage to the intended recipient application. The boon contains the sender, +the receiver, the identity of the message, and the message itself. + +This bubbles up all the way back to `++knob`, where we were handling the +`%hear` card. Following the logic in `++knob`, we can see that the boons get +sent into `++clop` to be turned into actual arvo-level moves. We've been here +before, if you recall, when we handled the `%cake` boon to send a message. +Now, we're handling the `%mulk` boon, which is unfortunately slightly more +complicated. + +``` + %mulk + :: ~& [%mulk p.bon q.bon] + ?> ?=([@ @ *] q.q.bon) + ?> ?=(%q i.q.q.bon) + ?+ i.t.q.q.bon + ~& %mulk-bad + :_ fox + :~ :- (claw p.p.bon) + [%sick %wart p.bon i.t.q.q.bon t.t.q.q.bon r.bon] + == + %ge :: %gall request + ?> ?=([@ ~] t.t.q.q.bon) + =+ app=`term`(need ((sand %tas) i.t.t.q.q.bon)) + =+ ^= pax + :+ (scot %p p.p.bon) + (scot %p q.p.bon) + q.q.bon + :_ fox [hen %pass pax %g %rote p.bon app r.bon]~ + %gh :: %gall response + ?> ?=([@ ~] t.t.q.q.bon) + =+ app=`term`(need ((sand %tas) i.t.t.q.q.bon)) + =+ ^= pax + :+ (scot %p p.p.bon) + (scot %p q.p.bon) + q.q.bon + :_ fox [hen %pass pax %g %roth p.bon app r.bon]~ + == +``` + +We're dispatching messages based on the prefix of their path. Since only +`%gall` apps use end-to-end acknowledgments at the moment, every path must have +at least two elements, and the first one must be `%q`. Beyond that, we handle +the `/q/ge` and `/q/gh` cases for gall requests and responses, respectively. + +In both cases, we require the next term in the path to be the name of the +intended recipient `%gall` app. Thus, a message to `/q/ge/chat` for example, +will send a message to the chat app. + +We then send a message to the app itself. The message is either a `%rote` or a +`%roth` for a request and a response, respectively. The content is the `rook` +or `roon` that was sent (stored in `r.bon`), but we don't actually handle that +at all here. That's completely a `%gall`-level thing. We're just the +messenger. + +Notice the path we send this over. We encode the sender, the receiver, and the +path over which it was sent. This fully specifies the `race` so that when the +app gives us the acknowledgment we know where to send it. + +We now have another interlude. We have entrusted our precious data, so +carefully guarded and guided from the app on that far-away ship, to our local +app. It has the ability to do whatever it pleases with it. It may take a +significant amount of time to process. When the message has been handled by +this app, though, it must produce an acknowledgment. Our final task is to +deliver this acknowledgment to the sending app. + +We should describe here what exactly these oft-mentioned acknowledgments +actually consist of. There are two kinds of acknowledgments: positive and +negative. A positive acknowledgment contains no data other than its existence. +A negative acknowledgment may optionally include a reason for said negativity. +Formally, a negative acknowledgment is an `ares`, which is a unit pair of a +term and a list of tanks. If this is null, this is simply a failure with no +associated information. If the pair exists, the term is a short error code +that is usually both human and computer readable. For example, if you try to +send a message to a valid `%gall` app that doesn't have any `++poke` to handle +it, then `%gall` will give a negative acknowledgment with error term +`%poke-find-fail`. The list of tanks is a human-readable description of the +error. This often contains a stack trace. At any rate, all this information +is returned to the sending app on the other end of the wire. + +After this brief interlude, our story resumes in `++knap`, where we receive +responses. In particular, a `%mean` indicates a negative acknowledgment while +a `%nice` indicates a positive acknowledgment. + +``` + ?(%mean %nice) + ?> ?=([@ @ @ *] tea) + =+ soq=[(slav %p i.tea) (slav %p i.t.tea)] + =+ pax=t.t.tea + =+ ^= fuy + =< zork =< zank + %^ ~(rack am [now fox]) soq pax + ?-(+<.sih %mean `p.+.sih, %nice ~) + => %_(. fox q.fuy) + =| out=(list move) + |- ^- [p=(list move) q=_+>.^$] + ?~ p.fuy + [(flop out) +>.^$] + =^ toe fox (clop now hen i.p.fuy) + $(p.fuy t.p.fuy, out (weld (flop toe) out)) +``` + +Recall the format of the path we sent the message on, and you'll understand why +`soq` and `pax` are the sender/receiver pair and path on which the message was +sent. The rest of this is structured much like `++knob`, so we call +`++rack:am` and send the resulting boons to `++clop`. Business as usual. + +``` + ++ rack :: rack:am + |= [soq=sock cha=path cop=coop] :: e2e ack + =+ oh=(ho:(um p.soq) q.soq) + =. oh (cook:oh cop cha ~) + (cans:oh cha) +``` + +First, we set up `++um` and `++ho`, as we've done twice before, for our +domestic and foreign servers, respectively. The other two things are new, +though. Well, `++cook` is not actually new, but we delayed the explanation +saying only that it sends an acknowledgment. The time has come. + +``` + ++ cook :: cook:ho:um:am + |= [cop=coop cha=path ram=(unit ,[ryn=lane dam=flap])] + ^+ +> :: acknowledgment + =+ rum=(need (~(get by raz.bah) cha)) + =+ lat=(~(get by mis.rum) did.rum) + ?: &(?=(~ lat) ?=(~ ram)) ~&(%ack-late-or-redundant +>.$) + =+ ^- [ryn=lane dam=flap] + ?^ ram [ryn.u.ram dam.u.ram] + ?< ?=(~ lat) + [q r]:u.lat + =. raz.bah + ?^ ram raz.bah + %+ ~(put by raz.bah) cha + rum(dod &, bum ?~(cop bum.rum (~(put by bum.rum) did.rum u.cop))) + =^ roc diz (zuul:diz now [%buck cop dam ~s0]) + (busk(diz (wast:diz ryn)) xong:diz roc) +``` + +If we are acknowledging a message that we have already acked, the `ram` will +contain the new lane and flap to send the duplicate ack to. This happens if we +call `++cook` in `++deer`, but it doesn't happen from `++rack`. If there is no +message waiting to be acknowledged and we're not given an explicit lane and +flap (that is, we're not sending a duplicate ack), then the app must have sent +us multiple acknowledgments. We do the only sensible thing we can do and drop +all acknowledgments after the first, printing a message. This is, in fact, an +error, so it could be argued that we ought to crash. Whatever you do, don't +depend on this not crashing. + +First, we grab the race specified by the given path, and we get the most recent +in-order message, which must be the one which is being acknowledged. + +Then, we decide which lane/flap to respond on/to. Basically, in the usual case +we respond on the lane through which the initial message was sent, which is +stored along with the other packet information in `mis.rum`, since it has to be +remembered across calls to ames. However, if we receive a duplicate message, +then we must respond to the new message. It's quite possible the reason the +other acknowledgment didn't get returned was that the lane between the ships +was broken. + +At any rate, we update the race by saying that we've finished processing this +packet (unless we're sending a duplicate ack) and, if we're sending a negative +acknowledgment, putting the negative ack into `bum.rum` so that we can resend +it if necessary. + +We encode our new message, updating the packet pump, with `++zuul`, as before, +and we send it off with `++busk`, routed via `++wast` to one of the ships in +`++xong`. Of course, in practice, we don't even look at the ships in `++xong` +because we already have a lane directly to our neighbor (the one over which +they sent their message to us). + +We glossed over the actual message we're sending back. We're sending a `%buck` +meal, which is an acknowledgment. The `cop` specifies whether this is a +positive or a negative ack, `dam` specifies the message we're acknowledging, +and the `~s0` is a placeholder for the processing time required. This time is +neither calculated (though it is hopefully obvious how to do so) nor used at +present, but this information may be used in the future for improved congestion +control. Since the round-trip time for an end-to-end acknowledged packet +includes the processing time on the other end, most common congestion control +algorithms will stumble when some messages take much longer to process than +others. As noted, though, this is simply an opportunity for improvement -- our +congestion control algorithms are relatively naive at the moment. + +Recall that `++busk` calls `++wist` to put the actual `%ouzo` boon in the +queue, which gets handled by `++clop` to actually send the message. This is +the same pipeline as sending any other message, so we'll refer you to the +explanation above if you've forgotten it. + +The last thing we need to do on this ship is move on to the next packet in the +queue if there is one. If you recall, in `++rack` after the call to `++cook` +there was a call to `++cans:ho:um:am`. + +``` + ++ cans :: cans:ho:um:am + |= cha=path + =+ rum=(need (~(get by raz.bah) cha)) + =. rum + %= rum + did +(did.rum) + mis (~(del by mis.rum) did.rum) + == + (coat cha rum) +``` + +This is very simple. We increment the number of packets that we've +acknowledged on this race and we delete the packet that we just acknowledged +from the set of misordered packets. + +Then, we call `++coat` again to process the next packet if we've already +received it. And that's it for this. + +The acknowledgment now travels the same path that its forebearer, the original +message, once tread, but this time not into the great unknown. The weary +traveler is seeking out its familial roots, finding the app from whom sprung +forth the original message way back in paragraph three. When it arrives at the +network adapter of its ancestors, the adapter tells unix, unix tells libuv, +libuv tells vere, and vere sends a `%hear` kiss to ames. Once more into the +kernel. + +The `%hear` kiss is handled in `++knob` as before, leading to `++gnaw`, going +over to `++chew`, `++apse`, `++chow`, and eventualy to `++dine`. We've seen +most of the cases in `++dine`, but we haven't yet looked at the handling of this +`%buck` meal. + +``` + %buck + =. +> ?.(=(%full aut) +> cock) :: finish key exch + +>(..la (tock p.fud q.fud r.fud)) +``` + +We send a packet level acknowledgment if we're finishing a key exchange, else +we call `++tock` to process the acknowledgment. + +This will get a little involved, so if you don't much care about how exactly an +acknowledgment happens, just know that the result gets gifted as a `%woot` card +back to the app who sent it. For those brave souls who wish to see this thing +through to the end, it's once more into the breach. + +``` + ++ tock :: tock:ho:um:am + |= [cop=coop fap=flap cot=@dr] :: e2e ack by hash + ^+ +> + =^ yoh puz (bick:puz now fap) + =. +>.$ + ?~ p.yoh +>.$ + =^ hud +>.$ + (done p.u.p.yoh q.u.p.yoh) + ?~ hud +>.$ + %= +>.$ + bin + :_ bin + `boon`[%cake [our her] [[p:sen:gus clon:diz] u.p.yoh] cop u.hud] + == + (busk xong:diz q.yoh) +``` + +We're going to work through this one a little backwards since it's mostly +fairly simple except the call to `++bick:pu`. In fact, we'll just skip +`++bick` for the moment and finish the rest. + +If `++bick` succesfully acks the message, then we call `++done`. + +``` + ++ done :: done:ho:um:am + |= [cha=path num=@ud] :: complete outgoing + ^- [(unit duct) _+>] + =+ rol=(need (~(get by ryl.bah) cha)) + =+ rix=(~(get by san.rol) num) + ?~ rix [~ +>.$] + :- rix + %_ +>.$ + ryl.bah + (~(put by ryl.bah) cha rol(san (~(del by san.rol) num))) + == +``` + +This very simply gets the rill (the outgoing counterpart to a race, if you +recall), pulls out of the map of outstanding messages the duct over which the +original message was sent, and produces this duct while deleting that entry +from the map of outstanding messages. + +Going back to `++tock`, we now have the duct we need to return the result +over. We do the very sensible thing and put a `%cake` boon in the queue to be +processed later by `++clop`. + +In `q.yoh` we have a list of messages that may need to be sent, which we pass +to `++busk` to send, as usual. When an acknowledgment arrives, that may +trigger other messages immediately. This often happens when sending more +messages than the width of the logical window since for congestion control +reasons another message cannot be sent until some of the earlier ones have been +acknowledged. + +We'll look at the processing of the `%cake` boon in `++clop` before we get back +to talking about `++bick`. + +``` + %cake + :_ fox + :~ [s.bon %give %woot q.p.bon r.bon] + == +``` + +We very simply give, along the duct we found above, a `%woot` card with the +ship who sent us the ack and the ack itself. This allows the application to +decide what to do about the result. In case of a failure, we usually either +resend the message or display it to the user. Sometimes, we recognize the +error term and handle it internally. In any case, the decision of how to +handle the acknowledgment is entirely up to the application. Our job is done. + +Well, except that we skipped `++bick:pu`. Let's go back to that. + +``` + ++ bick :: bick:pu + |= [now=@da fap=flap] :: ack by hash + ^- [[p=(unit soup) q=(list rock)] _+>] + =+ sun=(~(get by diq) fap) + ?~ sun + [[~ ~] +>.$] + =. diq (~(del by diq) fap) + =^ gub +>.$ (bock now u.sun) + =^ yop +>.$ (harv now) + [[gub yop] +>.$] +``` + +If you recall, in `++whap:pu` we created the packet pump's representation of +the message, which included putting the message into `diq`, which maps from +packet hashes to packet sequence numbers. Thus, `u.sun` is the sequence number +of this particular message. + +We delete this message from `diq` since we have now received an ack for it. We +call `++bock` to perform the ack by sequence number. We call `++harv` to +harvest the packet queue, sending any messages that are now able to be sent. + +In `++bock`, there are three arms we haven't seen before: `++bine`, `+wept`, +and `++beet`. We'll describe each of these before we get to `++bock`. +`++bine` looks scariest. + +``` + ++ bine :: bine:pu + |= [now=@da num=@ud] :: apply ack + ^- [(unit soup) _+>] + ?~ puq !! + ?. =(num p.n.puq) + ?: (gth num p.n.puq) + =+ lef=$(puq l.puq) + [-.lef +.lef(puq [n.puq puq.lef r.puq])] + =+ rig=$(puq r.puq) + [-.rig +.rig(puq [n.puq l.puq puq.rig])] + =: rtt ?. &(liv.q.n.puq =(1 nux.q.n.puq)) rtt + =+ gap=(sub now lys.q.n.puq) + :: ~& [%bock-trip num (div gap (div ~s1 1.000))] + (div (add (mul 2 rtt) gap) 3) + nif (sub nif !liv.q.n.puq) + == + =+ lez=(dec (need (~(get by pyz) gom.q.n.puq))) + =^ gub pyz + ?: =(0 lez) + [[~ gom.q.n.puq] (~(del by pyz) gom.q.n.puq)] + [~ (~(put by pyz) gom.q.n.puq lez)] + :- gub + +>.$(puq ~(nap to puq)) +``` + +The first few lines are simply looking through the packet queue until we find +the correct packet to ack. This is basic queue manipulation that operates +directly on the treap structure of the queue. If you understand treap queues, +the logic is easy to follow. Otherwise, just trust us that by the time we get +to the `=:`, the packet with sequence number `num` is on the top of the packet +queue (that is, at `n.puq`). + +We first update the round-trip time. If the packet is either not alive or had +to be transmitted more than once, then we don't have any reliable way of +calculating the round-trip time since we're unsure of exactly which +transmission was acknowledged. Otherwise, the round-trip time is the +difference between now and when the packet was last sent. We set `rtt` by a +little weighted average where the previous smoothed RTT is weighted twice as +much as the RTT of the current packet. Thus, `(2*rtt+gap)/3`. This gives us a +nice smooth RTT that is somewhat resilient to outlier data while still being +responsive to our ever-changing world. + +If the packet wasn't already dead, then we decrement the number of live +packets, which may allow more packets to be sent. + +We decrement the number of unacknowledged packets in our `pyz` for this +particular message. If you recall, this was set in `++whap` to the number of +packets required to send a message. + +If that was the last packet in the messge that needed to be acked, then we +delete the messgae reference from `pyz` and produce the id of the message. +Otherwise, we simply update `pyz` with the new number of unacked messages. +In either case, we remove the packet from the packet queue. + +``` + ++ wept :: wept:pu + |= [fip=@ud lap=@ud] :: fip thru lap-1 + =< abet =< apse + |% + ++ abet +>.$ + ++ apse + ^+ . + ?~ puq . + ?: (lth p.n.puq fip) ?~(l.puq . left) + ?: (gte p.n.puq lap) ?~(r.puq . rigt) + => rigt =< left + ?> ?=(^ puq) + ?.(liv.q.n.puq . .(nif (dec nif), liv.q.n.puq |)) + :: + ++ left + ?> ?=(^ puq) + ^+(. =+(lef=apse(puq l.puq) lef(puq [n.puq puq.lef r.puq]))) + ++ rigt + ?> ?=(^ puq) + ^+(. =+(rig=apse(puq r.puq) rig(puq [n.puq l.puq puq.rig]))) + -- +``` + +The algorithm is a simple case of traversing the packet queue. Essentialy, we +mark as dead all packets in the queue between `fip` and `(dec lap)`. We also +update `nif`, the number of live packets. Lest you mourn too much the passing +of these packets, know that they shall soon rise again. Recall that in +`++bick` after the call to `++bock` we call `++harv`. This will resend the +packets that have just been labeled dead. + +``` + ++ beet :: beet:pu + ^+ . :: advance unacked + =- +(nep ?~(foh nus u.foh)) + ^= foh + |- ^- (unit ,@ud) + ?~ puq ~ + ?: (lte p.n.puq nep) $(puq l.puq) + =+ rig=$(puq r.puq) + ?^(rig rig [~ p.n.puq]) +``` + +Here we search for the next expected packet number. Basically, we search the +queue for the leftmost packet whose number is greater than the current `nep`. +If we don't find any such packet, we just use the total number of packets sent. + +We can now dive into `++bock`, our last arm. + +``` + ++ bock :: bock:pu + |= [now=@da num=@ud] :: ack by sequence + ^- [(unit soup) _+>] + =^ gym +> (bine now num) + :- gym + ?: (gth num nep) + =+ cam=(max 2 (div caw 2)) + :: ~& [%bock-hole num nep cam] + beet:(wept(nep num, cag cam, caw cam) nep num) + =. caw ?: (lth caw cag) +(caw) + (add caw !=(0 (mod (mug now) caw))) + ?: =(num nep) + :: ~& [%bock-fine num nif caw cag] + beet + :: ~& [%bock-fill num nif caw cag] + +>.$ +``` + +First, we call `++bine` to apply the ack to the packet pump information. We +produce `gym`, which, if it exists, is the id of the packet that was acked. If +we received an ack for a packet later than the one we expected, then we halve +the logical packet window and kill all the earlier packets so that they may be +resent. + +Otherwise, we possibly increase the congestion window. If the window is less than +the congestion threshold, then we increment the size of the window. Otherwise, +we only increment one out of every `caw` times. + +If we received an ack for the packet we expected, then we simply advance `nep` +with `++beet`. If we received an ack for a packet earlier than we expected, we +do nothing. + +It may be hard to believe, but we are, in fact, done. The message has been +sent, received, acknowledged, and the acknowledgment has been returned to the +original sender. We hope it's clear that, while the process has been somewhat +involved, the algorithms are not all that complicated. If you've read this +far, you know `%ames`. The only other code involves initialization, timeouts, +and the like. + +Below, we give detailed reference documentation for the data models involved. + +Data Models +----------- + +###`++fort`, formal state + +``` +++ fort :: formal state + $: %0 :: version + gad=duct :: client interface + hop=@da :: network boot date + ton=town :: security + zac=(map ship corn) :: flows by server + == :: +``` + +This is the state of our vane. Anything that must be remembered between +calls to ames must be stored in this state. + +`%0` is the version of the ames state model itself. If the data model `++fort` +changes, then this number needs to be incremented, and an adapter must be +written to upgrade the old state into the new state. Note that this is the +version number of the model itself, not the contents. When the data changes, +there is of course no need to change this. + +`gad` is a `duct` over which we send `%send` cards to unix. This card is +initialized when unix sends a `%barn` card as vere starts up. Vere treats this +duct specially -- don't send anything weird over it. + +`hop` is the network boot date. This is set when the `%kick` card is sent by +vere on start up. + +`ton` is a `++town`, where we store all of our security/encryption state. Note +that this is shared across all ships on a pier. + +`zac` is a map of ships to `++corn`. This stores all the per-ship state. The +keys to this map are the ships on the current pier. + +###`++town`, all security state + +``` +++ town :: all security state + $: lit=@ud :: imperial modulus + any=@ :: entropy + urb=(map ship sufi) :: all keys and routes + fak=? :: + == :: +``` + +This is the security state of our pier. + +`lit` is unused. + +`any` is 256 bits of entropy. This entropy is used and updated in exactly two +places: when we send a `%junk` card, and when we generate a new symmetric key +in `++griz:lax:as:go`. When it is updated, it is updated by a SHA-256 hash of +the current time and the old value of the entropy. + +`urb` is a map of ships to `++sufi`. This is where we store all the per-ship +state for the pier. The keys to this map are the ships on the current pier. + +`fak` is true if we are on a fake network. This disables certain security +checks so that anyone may run a fake `~zod`. This is used only for development. +To use, run vere with the `-F` option (and the `-I ~zod` option for a fake +`~zod`). + +###`++sufi`, domestic host + +``` +++ sufi :: domestic host + $: hoy=(list ship) :: hierarchy + val=wund :: private keys + law=will :: server will + seh=(map hand ,[p=ship q=@da]) :: key cache + hoc=(map ship dore) :: neighborhood + == :: +``` + +This is the security state of a domestic server. + +`hoy` is a list of the ships directly above us in the hierarchy of ships. For +example, for `~hoclur-bicrel`, this would be `~tasruc` and `~tug`. See +`++sein`. + +`val` is a list of our private keys. + +`law` is our certificate, which is a list of the XXX + +`seh` + +`hoc` is a map of ships to `++dore`. The stores all the security informatoin +about foreign ships. The keys to this map are the neighbors (ships we have +been in contact with) of this domestic server. + +###`++wund`, private keys + +``` +++ wund (list ,[p=life q=ring r=acru]) :: mace in action +``` + +This is a list of our own private keys, indexed by life. The key itself is +the `++ring`, and the `++acru` is the encryption engine. We generate the +`++acru` from the private key by calling `++weur`. Thus, we can at any time +regenerate our `++wund` from a `++mace`. The current crypto is at the head of +the list and can be accessed with +`++sen:as:go`. + +###`++ring`, private key + +``` +++ ring ,@ :: private key +``` + +This is a private key. The first byte is reserved to identify the type of +cryptography. Lower-case means public key, upper-case means public key, and +the letter identifies which `++acru` to use. + +###`++pass`, public key + +``` +++ pass ,@ :: public key +``` + +This is a public key. The first byte is reserved to identify the type of +cryptography. Lower-case means public key, upper-case means public key, and +the letter identifies which `++acru` to use. + +###`++mace`, private secrets + +``` +++ mace (list ,[p=life q=ring]) :: private secrets +``` + +This is a list of the our private keys, indexed by life. From this we can +generate a `++wund` for actual use. + +###`++skin`, encoding stem + +``` +++ skin ?(%none %open %fast %full) :: encoding stem +``` + +This defines the type of encryption used for each message. `%none` refers +to messages sent in the clear, `%open` refers to signed messages, `%full` +refers to sealed messages, and `%fast` refers to symmetrically encrypted +messages. See `++acru` for details. + +###`++acru`, asymmetric cryptosuite + +``` +++ acru :: asym cryptosuite + $_ ^? |% :: opaque object + ++ as ^? :: asym ops + |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a + ++ sign |=([a=@ b=@] _@) :: certify as us + ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us + ++ tear |= [a=pass b=@] :: accept from a + *(unit ,[p=@ q=@]) :: + -- :: + ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft + ++ dy |+([a=@ b=@] _@) :: symmetric de, hard + ++ en |+([a=@ b=@] _@) :: symmetric en + ++ ex ^? :: export + |% ++ fig _@uvH :: fingerprint + ++ pac _@uvG :: default passcode + ++ pub *pass :: public key + ++ sec *ring :: private key + -- + ++ nu ^? :: reconstructors + |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed] + ++ nol |=(a=@ ^?(..nu)) :: from naked ring + ++ com |=(a=@ ^?(..nu)) :: from naked pass + -- + -- +``` + +This is an opaque interface for a general asymmetric cryptosuite. Any form +of asymmetric cryptography can be dropped in to be used instead of the default. +Right now, there are two cryptosuites, `++crua`, which is your standard RSA, +and `++crub`, which is elliptic curve crypto but is mostly stubbed out at the +moment. + +####`++as:acru`, asymmetric operations + +``` + ++ as ^? :: asym ops + |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a + ++ sign |=([a=@ b=@] _@) :: certify as us + ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us + ++ tear |= [a=pass b=@] :: accept from a + *(unit ,[p=@ q=@]) :: + -- :: +``` + +This is the core that defines the standard asymmetric cryptography +operations. + +`++seal:as:acru` allows us to send a message encrypted with someone's public +key so that only they may read it. If Alice seals a message with Bob's public +key, then she can be sure that Bob is the only one who can read it. This is +associated with the `++skin` `%full`. + +`++sign:as:acru` allows us to sign a message with our private key so that +others can verify that we sent the message. If Alice signs a message with her +private key, then Bob can verify with her public key that it was indeed Alice +who sent it. This is associated with the `++skin` `%open`. + +`++sure:as:acru` is the dual to `++sign:as:acru`. It allows us to verify that +a message we have received is indeed from the claimed sender. If Alice sends a +message with her private key, then Bob can use this arm to verify that it was +indeed Alice who sent it. This is associated with the `++skin` `%open`. + +`++tear:as:acru` is the dual to `++seal:as:acru`. It allows us to read a +message that we can be sure is only read by us. If Alice seals a message with +Bob's public key, then Bob can use this arm to read it. This is associated +with the `++skin` `%full`. + +####`++de:acru`, `++dy:acru`, and `++en:acru`, symmetric encryption/decryption + +``` + ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft + ++ dy |+([a=@ b=@] _@) :: symmetric de, hard + ++ en |+([a=@ b=@] _@) :: symmetric en +``` + +Symmetric encryption is associated with the `++skin` `%fast`. + +`++de:acru` decrypts a message with a symmetric key, returning `~` on failure +and `[~ u=data]` on success. + +`++dy:acru` decrypts a message with a symmetric key, crashing on failure. This +should almost always be defined as, and should always be semantically +equivalent to, `(need (de a b))`. + +`++en:acru` encrypts a message with a symmetric key. + +####`++ex:acru`, exporting data + +``` + ++ ex ^? :: export + |% ++ fig _@uvH :: fingerprint + ++ pac _@uvG :: default passcode + ++ pub *pass :: public key + ++ sec *ring :: private key + -- +``` + +`++fig:ex:acru` is our fingerprint, usually a hash of our public key. This is +used, for example, in `++zeno`, where every carrier owner's fingerprint is +stored so that we can ensure that carriers are indeed owned by their owners + +`++pac:ex:acru` is our default passcode, which is unused at present. + +`++pub:ex:acru` is the `++pass` form of our public key. + +`++sec:ex:acru` is the `++ring` form of our private key. + +####`++nu:acru`, reconstructors + +``` + ++ nu ^? :: reconstructors + |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed] + ++ nol |=(a=@ ^?(..nu)) :: from naked ring + ++ com |=(a=@ ^?(..nu)) :: from naked pass + -- +``` + +These arms allow us to reconstruct a `++acru` from basic data. + +`++pit:nu:acru` constructs a `++acru` from the width of our intended key and +seed entropy. This is usually used in the initial construction of the +`++acru`. + +`++nol:nu:acru` constructs a `++acru` from a "naked ring", meaning a `++ring` +without the initial byte identifying the type of crypto. There is often a +helper arm that that wraps this; see `++weur` for `++crua` and `++wear` for +`++crub`. + +`++com:nu:acru` constructs a `++acru` from a "naked pass", meaning a `++ring` +without the initial byte identifying the type of crypto. There is often a +helper arm that that wraps this; see `++haul` for `++crua` and `++hail` for +`++crub`. + +###`++will`, certificate + +``` +++ will (list deed) :: certificate +``` + +This is a list of deeds associated with the current ship. There should be +an item in this list for every ship from this point up in the hierarchy times +the number of lives that each ship has had. For example, ~hoclur-bicrel may +have a will with three items: one for itself, one for ~tasruc (who issued +~hoclur-bicrel's deed) and one for ~tug (who issued ~tasruc's deed). + +###`++deed`, identity + +``` +++ deed ,[p=@ q=step r=?] :: sig, stage, fake? +``` + +`p` is the signature of a particular deed, which is a signed copy of `q`. + +`q` is the stage in the identity. + +`r` is true if we're working on a fake network, where we don't check that the +carrier fingerprints are correct. This allows us to create fake networks for +development without interfering with the real network. + +###`++step`, identity stage + +``` +++ step ,[p=bray q=gens r=pass] :: identity stage +``` + +This is a single stage in our identity. Thus, this is specific to a single +life in a single ship. Everything in here may change between lives. + +`p` + +`q` + +`r` is the public key for this stage in the identity. + +###`++bray` + +``` +++ bray ,[p=life q=(unit life) r=ship s=@da] :: our parent us now +``` + +XXX + +###`++gens`, general identity + +``` +++ gens ,[p=lang q=gcos] :: general identity +``` + +`p` is the IETF language code for the preferred language of this identity. +This is unused at the moment, but in the future text should be localized based +on this. + +`q` is the description of the ship. + +###`++gcos`, identity description + +``` +++ gcos :: id description + $% [%czar ~] :: 8-bit ship + [%duke p=what] :: 32-bit ship + [%earl p=@t] :: 64-bit ship + [%king p=@t] :: 16-bit ship + [%pawn p=(unit ,@t)] :: 128-bit ship + == :: +``` + +This is the description of the identity of a ship. Most types of identity have +a `@t` field, which is their human-readable name. The identity of a `%duke` is +more involved. + +A `%czar`, a carrier, is a ship with an 8-bit address. Thus, there are only +256 carriers. These are at the top of the namespace hierarchy, and the +fingerprint of each carrier is stored in `++zeno`. These are the "senators" of +Urbit. + +A `%king`, a cruiser, is a ship with a 16-bit address. Thus, there are 65,536 +cruisers. Each carrier may issue 256 cruisers. These are the infrastructure +of Urbit. + +A `%duke`, a destroyer, is a ship with a 32-bit address. Thus, there are +4,294,967,296 destroyers. Each cruiser may issue 65,536 cruisers. These are +the individuals of Urbit. + +A `%earl`, a yacht, is a ship with a 64-bit address. Thus, there are +18,446,744,073,709,551,616 yachts. Each destroyer may issue 4,294,967,296 +yachts. These are the devices of Urbit. + +A `%pawn`, a submarine, is a ship with a 128-bit address. Thus, there are a +lot of submarines. The chance of random name collision is negligible, so +submarines are not issued by any ship. They must simply assert their presence, +and they are all considered children of ~zod. This is the underworld of Urbit, +where anonymity reigns supreme. + +###`++what`, logical destroyer identity + +``` +++ what :: logical identity + $% [%anon ~] :: anonymous + [%lady p=whom] :: female person () + [%lord p=whom] :: male person [] + [%punk p=sect q=@t] :: opaque handle "" + == :: +``` + +This is the logical identity of a destroyer. + +A `%anon` is a completely anonymous destroyer. The difference between this and +a submarine is that a submarine is ephemeral while a `%anon` destroyer is not. +Thus, we may not know who ~hoclur-bicrel is, but we do know that it's always +the same person. + +A `%lady` is a female person. The name used here should be a real name. + +A `%lord` is a male person. The name used here should be a real name. + +A `%punk` is a person who is identified only by a handle. + +###`++whom`, real person + +``` +++ whom ,[p=@ud q=govt r=sect s=name] :: year/govt/id +``` + +Ths is the information associated with a real person. It is mostly information +that could be observed with the briefest of interactions. + +`p` is the birth year. + +`q` is the location of a user, usually of the form "country/zip". + +`r` is the sect of the user. + +`s` is the real name of the person. + + +###`++govt` + +``` +++ govt path :: country/postcode +``` + +This is the location of the user, usually of the form "country/zip". + +###`++sect` + +``` +++ sect ?(%black %blue %red %orange %white) :: banner +``` + +XXX + +###`++name` + +``` +++ name ,[p=@t q=(unit ,@t) r=(unit ,@t) s=@t] :: first mid/nick last +``` + +This is the given name, possible middle name/initial, possible nickname, and +surname of a user. + +packet format +------------- + +`++go`, PKI engine +------------------ + +###`++as`, per server + +####`++born`, register user + +#####`++lax`, per client + +`++pu`, packet pump +------------------- + +`++am`, protocol engine +----------------------- + +###`++um`, per server + +####`++ho`, per friend + +#####`++la`, per packet + +protocol vane +------------- + diff --git a/main/pub/src/doc/ref/volumes/4/4b.md b/main/pub/src/doc/ref/vol/4b.md similarity index 100% rename from main/pub/src/doc/ref/volumes/4/4b.md rename to main/pub/src/doc/ref/vol/4b.md diff --git a/main/pub/src/doc/ref/vol/4c.md b/main/pub/src/doc/ref/vol/4c.md new file mode 100644 index 000000000..d1db462f2 --- /dev/null +++ b/main/pub/src/doc/ref/vol/4c.md @@ -0,0 +1,1550 @@ +Clay +==== + +Clay is our filesystem. + +The first part of this will be reference documentation for the data types used +by our filesystem. In fact, as a general guide, we recommend reading and +attempting to understand the data structures used in any Hoon code before you +try to read the code itself. Although complete understanding of the data +structures is impossible without seeing them used in the code, an 80% +understanding greatly clarifies the code. As another general guide, when +reading Hoon, it rarely pays off to understand every line of code when it +appears. Try to get the gist of it, and then move on. The next time you come +back to it, it'll likely make a lot more sense. + +After a description of the data models, we'll give an overview of the interface +that vanes and applications can use to interact with the filesystem. + +Finally, we'll dive into the code and the algorithms themselves. You know, the +fun part. + +Data Models +----------- + +As you're reading through this section, remember you can always come back to +this when you run into these types later on. You're not going to remember +everything the first time through, but it is worth reading, or at least +skimming, this so that you get a rough idea of how our state is organized. + +The types that are certainly worth reading are `++raft`, `++room`, `++dome`, +`++ankh`, `++rung`, `++rang`, `++blob`, `++yaki`, and `++nori` (possibly in +that order). All in all, though, this section isn't too long, so many readers +may wish to quickly read through all of it. If you get bored, though, just +skip to the next section. You can always come back when you need to. + +###`++raft`, formal state + +``` +++ raft :: filesystem + $: fat=(map ship room) :: domestic + hoy=(map ship rung) :: foreign + ran=rang :: hashes + == :: +``` + +This is the state of our vane. Anything that must be remembered between calls +to clay is stored in this state. + +`fat` is the set of domestic servers. This stores all the information that is +specfic to a particular ship on this pier. The keys to this map are the ships +on the current pier. + +`hoy` is the set of foreign servers that we know anything about. This stores +all the information that is specific to a particular foreign ship. The keys to +this map are all the ships whose filesystems we have attempted to access +through clay. + +`ran` is the store of all commits and deltas, keyed by hash. The is where all +the "real" data we know is stored; the rest is "just bookkeeping". + +###`++room`, filesystem per domestic ship + +``` +++ room :: fs per ship + $: hun=duct :: terminal duct + hez=(unit duct) :: sync duch + dos=(map desk dojo) :: native desk + == :: +``` + +This is the representation of the filesystem of a ship on our pier. + +`hun` is the duct we use to send messages to dill to display notifications of +filesystem changes. Only `%note` gifts should be produced along this duct. +This is set by the `%init` kiss. + +`hez`, if present, is the duct we use to send sync messages to unix so that +they end up in the pier unix directory. Only `%ergo` gifts should be producd +along this duct. This is set by `%into` and `%invo` kisses. + +`dos` is a well-known operating system released in 1981. It is also the set of +desks on this ship, mapped to their data. + +###`++desk`, filesystem branch + +``` +++ desk ,@tas :: ship desk case spur +``` + +This is the name of a branch of the filesystem. The default desks are "arvo", +"main", and "try". More may be created by simply referencing them. Desks have +independent histories and states, and they may be merged into each other. + +###`++dojo`, domestic desk state + +``` +++ dojo ,[p=cult q=dome] :: domestic desk state +``` + +This is the all the data that is specific to a particular desk on a domestic +ship. `p` is the set of subscribers to this desk and `q` is the data in the +desk. + +###`++cult`, subscriptions + +``` +++ cult (map duct rave) :: subscriptions +``` + +This is the set of subscriptions to a particular desk. The keys are the ducts +from where the subscriptions requests came. The results will be produced along +these ducts. The values are a description of the requested information. + +###`++rave`, general subscription request + +``` +++ rave :: general request + $% [& p=mood] :: single request + [| p=moat] :: change range + == :: +``` + +This represents a subscription request for a desk. The request can be for +either a single item in the desk or else for a range of changes on the desk. + +###`++mood`, single subscription request + +``` +++ mood ,[p=care q=case r=path] :: request in desk +``` + +This represents a request for the state of the desk at a particular commit, +specfied by `q`. `p` specifies what kind of information is desired, and `r` +specifies the path we are requesting. + +###`++moat`, range subscription request + +``` +++ moat ,[p=case q=case] :: change range +``` + +This represents a request for all changes between `p` and `q`. Note that there +is currently no way to request to be notified only on changes to particular +paths in the filesystem. You must subscribe to the entire desk. + +###`++care`, clay submode + +``` +++ care ?(%u %v %w %x %y %z) :: clay submode +``` + +This specifies what type of information is requested in a subscription or a +scry. + +`%u` requests the `++rang` at the current moment. Because this information is +not stored for any moment other than the present, we crash if the `++case` is +not a `%da` for now. + +`%v` requests the `++dome` at the specified commit. + +`%w` requests the revsion number of the desk. + +`%x` requests the file at a specified path at the specified commit. If there +is no node at that path or if the node has no contents (that is, if `q:ankh` is +null), then this produces null. + +`%y` requests a `++arch` of the specfied commit at the specified path. + +`%z` requests the `++ankh` of the specified commit at the specfied path. + +###`++arch`, shallow filesystem node + +``` +++ arch ,[p=@uvI q=(unit ,@uvI) r=(map ,@ta ,~)] :: fundamental node +``` + +This is analogous to `++ankh` except that the we have neither our contents nor +the ankhs of our children. The other fields are exactly the same, so `p` is a +hash of the associated ankh, `u.q`, if it exists, is a hash of the contents of +this node, and the keys of `r` are the names of our children. `r` is a map to +null rather than a set so that the ordering of the map will be equivalent to +that of `r:ankh`, allowing efficient conversion. + +###`++case`, specifying a commit + +``` +++ case :: ship desk case spur + $% [%da p=@da] :: date + [%tas p=@tas] :: label + [%ud p=@ud] :: number + == :: +``` + +A commit can be referred to in three ways: `%da` refers to the commit that was +at the head on date `p`, `%tas` refers to the commit labeled `p`, and `%ud` +refers to the commit numbered `p`. Note that since these all can be reduced +down to a `%ud`, only numbered commits may be referenced with a `++case`. + +###`++dome`, desk data + +``` +++ dome :: project state + $: ang=agon :: pedigree + ank=ankh :: state + let=@ud :: top id + hit=(map ,@ud tako) :: changes by id + lab=(map ,@tas ,@ud) :: labels + == :: +``` + +This is the data that is actually stored in a desk. + +`ang` is unused and should be removed. + +`ank` is the current state of the desk. Thus, it is the state of the +filesystem at revison `let`. The head of a desk is always a numbered commit. + +`let` is the number of the most recently numbered commit. This is also the +total number of numbered commits. + +`hit` is a map of numerical ids to hashes of commits. These hashes are mapped +into their associated commits in `hut:rang`. In general, the keys of this map +are exactly the numbers from 1 to `let`, with no gaps. Of course, when there +are no numbered commits, `let` is 0, so `hit` is null. Additionally, each of +the commits is an ancestor of every commit numbered greater than this one. +Thus, each is a descendant of every commit numbered less than this one. Since +it is true that the date in each commit (`t:yaki`) is no earlier than that of +each of its parents, the numbered commits are totally ordered in the same way +by both pedigree and date. Of course, not every commit is numbered. If that +sounds too complicated to you, don't worry about it. It basically behaves +exactly as you would expect. + +`lab` is a map of textual labels to numbered commits. Note that labels can +only be applied to numbered commits. Labels must be unique across a desk. + +###`++ankh`, filesystem node + +``` +++ ankh :: fs node (new) + $: p=cash :: recursive hash + q=(unit ,[p=cash q=*]) :: file + r=(map ,@ta ankh) :: folders + == :: +``` + +This is a single node in the filesystem. This may be file or a directory or +both. In earth filesystems, a node is a file xor a directory. On mars, we're +inclusive, so a node is a file ior a directory. + +`p` is a recursive hash that depends on the contents of the this file or +directory and on any children. + +`q` is the contents of this file, if any. `p.q` is a hash of the contents +while `q.q` is the data itself. + +`r` is the set of children of this node. In the case of a pure file, this is +empty. The keys are the names of the children and the values are, recursively, +the nodes themselves. + +###`++cash`, ankh hash + +``` +++ cash ,@uvH :: ankh hash +``` + +This is a 128-bit hash of an ankh. These are mostly stored within ankhs +themselves, and they are used to check for changes in possibly-deep +hierarchies. + +###`++rung`, filesystem per neighbor ship + +``` +++ rung $: rus=(map desk rede) :: neighbor desks + == :: +``` + +This is the filesystem of a neighbor ship. The keys to this map are all the +desks we know about on their ship. + +###`++rede`, desk state + +``` +++ rede :: universal project + $: lim=@da :: complete to + qyx=cult :: subscribers + ref=(unit rind) :: outgoing requests + dom=dome :: revision state + == :: +``` + +This is our knowledge of the state of a desk, either foreign or domestic. + +`lim` is the date of the last full update. We only respond to requests for +stuff before this time. + +`qyx` is the list of subscribers to this desk. For domestic desks, this is +simply `p:dojo`, all subscribers to the desk, while in foreign desks this is +all the subscribers from our ship to the foreign desk. + +`ref` is the request manager for the desk. For domestic desks, this is null +since we handle requests ourselves. + +`dom` is the actual data in the desk. + +###`++rind`, request manager + +``` +++ rind :: request manager + $: nix=@ud :: request index + bom=(map ,@ud ,[p=duct q=rave]) :: outstanding + fod=(map duct ,@ud) :: current requests + haw=(map mood (unit)) :: simple cache + == :: +``` + +This is the request manager for a foreign desk. + +`nix` is one more than the index of the most recent request. Thus, it is the +next available request number. + +`bom` is the set of outstanding requests. The keys of this map are some subset +of the numbers between 0 and one less than `nix`. The members of the map are +exactly those requests that have not yet been fully satisfied. + +`fod` is the same set as `bom`, but from a different perspective. In +particular, the values of `fod` are the same as the values of `bom`, and the +`p` out of the values of `bom` are the same as the keys of `fod`. Thus, we can +map ducts to their associated request number and `++rave`, and we can map +numbers to their associated duct and `++rave`. + +`haw` is a map from simple requests to their values. This acts as a cache for +requests that have already been made. Thus, the second request for a +particular `++mood` is nearly instantaneous. + +###`++rang`, data store + +``` +++ rang $: hut=(map tako yaki) :: + lat=(map lobe blob) :: + == :: +``` + +This is a set of data keyed by hash. Thus, this is where the "real" data is +stored, but it is only meaningful if we know the hash of what we're looking +for. + +`hut` is a map from hashes to commits. We often get the hashes from +`hit:dome`, which keys them by logical id. Not every commit has an id. + +`lat` is a map from hashes to the actual data. We often get the hashes from a +`++yaki`, a commit, which references this map to get the data. There is no +`++blob` in any `++yaki`. They are only accessible through this map. + +###`++tako`, commit reference + +``` +++ tako ,@ :: yaki ref +``` + +This is a hash of a `++yaki`, a commit. These are most notably used as the +keys in `hut:rang`, where they are associated with the actual `++yaki`, and as +the values in `hit:dome`, where sequential ids are associated with these. + +###`++yaki`, commit + +``` +++ yaki ,[p=(list tako) q=(map path lobe) r=tako t=@da] :: commit +``` + +This is a single commit. + +`p` is a list of the hashes of the parents of this commit. In most cases, this +will be a single commit, but in a merge there may be more parents. In theory, +there may be an arbitrary number of parents, but in practice merges have +exactly two parents. This may change in the future. For commit 1, there is no +parent. + +`q` is a map of the paths on a desk to the data at that location. If you +understand what a `++lobe` and a `++blob` is, then the type signature here +tells the whole story. + +`r` is the hash associated with this commit. + +`t` is the date at which this commit was made. + +###`++lobe`, data reference + +``` +++ lobe ,@ :: blob ref +``` + +This is a hash of a `++blob`. These are most notably used in `lat:rang`, where +they are associated with the actual `++blob`, and as the values in `q:yaki`, +where paths are associated with their data in a commit. + +###`++blob`, data + +``` +++ blob $% [%delta p=lobe q=lobe r=udon] :: delta on q + [%direct p=lobe q=* r=umph] :: + [%indirect p=lobe q=* r=udon s=lobe] :: + == :: +``` + +This is a node of data. In every case, `p` is the hash of the blob. + +`%delta` is the case where we define the data by a delta on other data. In +practice, the other data is always the previous commit, but nothing depends on +this. `q` is the hash of the parent blob, and `r` is the delta. + +`%direct` is the case where we simply have the data directly. `q` is the data +itself, and `r` is any preprocessing instructions. These almost always come +from the creation of a file. + +`%indirect` is both of the preceding cases at once. `q` is the direct data, +`r` is the delta, and `s` is the parent blob. It should always be the case +that applying `r` to `s` gives the same data as `q` directly (with the +prepreprocessor instructions in `p.r`). This exists purely for performance +reasons. This is unused, at the moment, but in general these should be created +when there are a long line of changes so that we do not have to traverse the +delta chain back to the creation of the file. + +###`++udon`, abstract delta + +``` +++ udon :: abstract delta + $: p=umph :: preprocessor + $= q :: patch + $% [%a p=* q=*] :: trivial replace + [%b p=udal] :: atomic indel + [%c p=(urge)] :: list indel + [%d p=upas q=upas] :: tree edit + == :: + == :: +``` + +This is an abstract change to a file. This is a superset of what would +normally be called diffs. Diffs usually refer to changes in lines of text +while we have the ability to do more interesting deltas on arbitrary data +structures. + +`p` is any preprocessor instructions. + +`%a` refers to the trival delta of a complete replace of old data with new +data. + +`%b` refers to changes in an opaque atom on the block level. This has very +limited usefulness, and is not used at the moment. + +`%c` refers to changes in a list of data. This is often lines of text, which +is your classic diff. We, however, will work on any list of data. + +`%d` refers to changes in a tree of data. This is general enough to describe +changes to any hoon noun, but often more special-purpose delta should be +created for different content types. This is not used at the moment, and may +in fact be unimplemented. + +###`++urge`, list change + +``` +++ urge |*(a=_,* (list (unce a))) :: list change +``` + +This is a parametrized type for list changes. For example, `(urge ,@t)` is a +list change for lines of text. + +###`++unce`, change part of a list. + +``` +++ unce |* a=_,* :: change part + $% [%& p=@ud] :: skip[copy] + [%| p=(list a) q=(list a)] :: p -> q[chunk] + == :: +``` + +This is a single change in a list of elements of type `a`. For example, `(unce ,@t)` is +a single change in a lines of text. + +`%&` means the next `p` lines are unchanged. + +`%|` means the lines `p` have changed to `q`. + +###`++umph`, preprocessing information + +``` +++ umph :: change filter + $| $? %a :: no filter + %b :: jamfile + %c :: LF text + == :: + $% [%d p=@ud] :: blocklist + == :: +``` + +This space intentionally left undocumented. This stuff will change once we get +a well-typed clay. + +###`++upas`, tree change + +``` +++ upas :: tree change (%d) + $& [p=upas q=upas] :: cell + $% [%0 p=axis] :: copy old + [%1 p=*] :: insert new + [%2 p=axis q=udon] :: mutate! + == :: +``` + +This space intentionally left undocumented. This stuff is not known to work, +and will likely change when we get a well-typed clay. Also, this is not a +complicated type; it is not difficult to work out the meaning. + +###`++nori`, repository action + +``` +++ nori :: repository action + $% [& q=soba] :: delta + [| p=@tas] :: label + == :: +``` + +This describes a change that we are asking clay to make to the desk. There are +two kinds of changes that may be made: we can modify files or we can apply a +label to a commit. + +In the `|` case, we will simply label the current commit with the given label. +In the `&` case, we will apply the given changes. + +###`++soba`, delta + +``` +++ soba ,[p=cart q=(list ,[p=path q=miso])] :: delta +``` + +This describes a set of changes to make to a desk. The `cart` is simply a pair +of the old hash and the new hash of the desk. The list is a list of changes +keyed by the file they're changing. Thus, the paths are paths to files to be +changed while `miso` is a description of the change itself. + +###`++miso`, ankh delta + +``` +++ miso :: ankh delta + $% [%del p=*] :: delete + [%ins p=*] :: insert + [%mut p=udon] :: mutate + == :: +``` + +There are three kinds of changes that may be made to a node in a desk. We can +insert a file, in which case `p` is the contents of the new file. We can +delete a file, in which case `p` is the contents of the old file. Finally, we +can mutate that file, in which case the `udon` describes the changes we are +applying to the file. + +###`++mizu`, merged state + +``` +++ mizu ,[p=@u q=(map ,@ud tako) r=rang] :: new state +``` + +This is the input to the `%merg` kiss, which allows us to perform a merge. The +`p` is the number of the new head commit. The `q` is a map from numbers to +commit hashes. This is all the new numbered commits that are to be inserted. +The keys to this should always be the numbers from `let.dom` plus one to `p`, +inclusive. The `r` is the maps of all the new commits and data. Since these +are merged into the current state, no old commits or data need be here. + +###`++riff`, request/desist + +``` +++ riff ,[p=desk q=(unit rave)] :: request/desist +``` + +This represents a request for data about a particular desk. If `q` contains a +`rave`, then this opens a subscription to the desk for that data. If `q` is +null, then this tells clay to cancel the subscription along this duct. + +###`++riot`, response + +``` +++ riot (unit rant) :: response/complete +``` + +A riot is a response to a subscription. If null, the subscription has been +completed, and no more responses will be sent. Otherwise, the `rant` is the +produced data. + +###`++rant`, response data + +``` +++ rant :: namespace binding + $: p=[p=care q=case r=@tas] :: clade release book + q=path :: spur + r=* :: data + == :: +``` + +This is the data at a particular node in the filesystem. `p.p` specifies the +type of data that was requested (and is produced). `q.p` gives the specific +version reported (since a range of versions may be requested in a +subscription). `r.p` is the desk. `q` is the path to the filesystem node. +`r` is the data itself (in the format specified by `p.p`). + +###`++nako`, subscription response data + +``` +++ nako $: gar=(map ,@ud tako) :: new ids + let=@ud :: next id + lar=(set yaki) :: new commits + bar=(set blob) :: new content + == :: +``` + +This is the data that is produced by a request for a range of revisions of a +desk. + +`gar` is a map of the revisions in the range to the hash of the commit +at that revision. These hashes can be used with `hut:rang` to find the commit +itself. + +`let` is either the last revision number in the range or the most recent +revision number, whichever is smaller. + +`lar` is the set of new commits, and `bar` is the set of new content. + +Interface +--------- + +As with all vanes, there are exactly two ways to interact with clay. Clay +exports a namespace accessible through `.^`, which is described above under +`++care`. The primary way of interacting with clay, though, is by sending +kisses and receiving gifts. + +``` +++ gift :: out result <-$ + $% [%ergo p=@p q=@tas r=@ud] :: version update + [%note p=@tD q=tank] :: debug message + [%writ p=riot] :: response + == :: +++ kiss :: in request ->$ + $% [%info p=@p q=@tas r=nori] :: internal edit + [%ingo p=@p q=@tas r=nori] :: internal noun edit + [%init p=@p] :: report install + [%into p=@p q=@tas r=nori] :: external edit + [%invo p=@p q=@tas r=nori] :: external noun edit + [%merg p=@p q=@tas r=mizu] :: internal change + [%wake ~] :: timer activate + [%wart p=sock q=@tas r=path s=*] :: network request + [%warp p=sock q=riff] :: file request + == :: +``` + +There are only a small number of possible kisses, so it behooves us to describe +each in detail. + +``` + $% [%info p=@p q=@tas r=nori] :: internal edit +``` + +``` + [%into p=@p q=@tas r=nori] :: external edit +``` + +These two kisses are nearly identical. At a high level, they apply changes to +the filesystem. Whenever we add, remove, or edit a file, one of these cards is +sent. The `p` is the ship whose filesystem we're trying to change, the `q` is +the desk we're changing, and the `r` is the request change. For the format of +the requested change, see the documentation for `++nori` above. + +When a file is changed in the unix filesystem, vere will send a `%into` kiss. +This tells clay that the duct over which the kiss was sent is the duct that +unix is listening on for changes. From within Arvo, though, we should never +send a `%into` kiss. The `%info` kiss is exactly identical except it does not +reset the duct. + + +``` + [%ingo p=@p q=@tas r=nori] :: internal noun edit +``` + +``` + [%invo p=@p q=@tas r=nori] :: external noun edit +``` + +These kisses are currently identical to `%info` and `%into`, though this will +not always be the case. The intent is for these kisses to allow typed changes +to clay so that we may store typed data. This is currently unimplemented. + +``` + [%init p=@p] :: report install +``` + +Init is called when a ship is started on our pier. This simply creates a +default `room` to go into our `raft`. Essentially, this initializes the +filesystem for a ship. + +``` + [%merg p=@p q=@tas r=mizu] :: internal change +``` + +This is called to perform a merge. This is most visibly called by :update to +update the filesystem of the current ship to that of its sein. The `p` and `q` +are as in `%info`, and the `r` is the description of the merge. See `++mizu` +above. + +``` + [%wake ~] :: timer activate +``` + +This card is sent by unix at the time specified by `++doze`. This time is +usually the closest time specified in a subscription request. When `%wake` is +called, we update our subscribers if there have been any changes. + +``` + [%wart p=sock q=@tas r=path s=*] :: network request +``` + +This is a request that has come across the network for a particular file. When +another ship asks for a file from us, that request comes to us in the form of a +`%wart` kiss. This is handled by trivially turning it into a `%warp`. + +``` + [%warp p=sock q=riff] :: file request +``` + +This is a request for information about a particular desk. This is, in its +most general form, a subscription, though in many cases it is the trivial case +of a subscription -- a read. See `++riff` for the format of the request. + +Lifecycle of a Local Read +------------------------- + +There are two real types of interaction with a filesystem: you can read, and +you can write. We'll describe each process, detailing both the flow of control +followed by the kernel and the algorithms involved. The simpler case is that +of the read, so we'll begin with that. + +When a vane or an application wishes to read a file from the filesystem, it +sends a `%warp` kiss, as described above. Of course, you may request a file on +another ship and, being a global filesystem, clay will happily produce it for +you. That code pathway will be described in another section; here, we will +restrict ourselves to examining the case of a read from a ship on our own pier. + +The kiss can request either a single version of a file node or a range of +versions of a desk. Here, we'll deal only with a request for a single version. + +As in all vanes, a kiss enters clay via a call to `++call`. Scanning through +the arm, we quickly see where `%warp` is handled. + +``` + ?: =(p.p.q.hic q.p.q.hic) + =+ une=(un p.p.q.hic now ruf) + =+ wex=(di:une p.q.q.hic) + =+ ^= wao + ?~ q.q.q.hic + (ease:wex hen) + (eave:wex hen u.q.q.q.hic) + =+ ^= woo + abet:wao + [-.woo abet:(pish:une p.q.q.hic +.woo ran.wao)] +``` + +We're following the familar patern of producing a list of moves and an updated +state. In this case, the state is `++raft`. + +We first check to see if the sending and receiving ships are the same. If +they're not, then this is a request for data on another ship. We describe that +process later. Here, we discuss only the case of a local read. + +At a high level, the call to `++un` sets up the core for the domestic ship that +contains the files we're looking for. The call to `++di` sets up the core for +the particular desk we're referring to. + +After this, we perform the actual request. If there is no rave in the riff, +then that means we are cancelling a request, so we call `++ease:de`. +Otherwise, we start a subscription with `++eave:de`. We call `++abet:de` to +resolve our various types of output into actual moves. We produce the moves we +found above and the `++un` core resolved with `++pish:un` (putting the modified +desk in the room) and `++abet:un` (putting the modified room in the raft). + +Much of this is fairly straightforward, so we'll only describe `++ease`, +`++eave`, and `++abet:de`. Feel free to look up the code to the other steps -- +it should be easy to follow. + +Although it's called last, it's usually worth examining `++abet` first, since +it defines in what ways we can cause side effects. Let's do that, and also a +few of the lines at the beginning of `++de`. + +``` + =| yel=(list ,[p=duct q=gift]) + =| byn=(list ,[p=duct q=riot]) + =| vag=(list ,[p=duct q=gift]) + =| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]]) + |% + ++ abet + ^- [(list move) rede] + :_ red + ;: weld + %+ turn (flop yel) + |=([a=duct b=gift] [hun %give b]) + :: + %+ turn (flop byn) + |=([a=duct b=riot] [a %give [%writ b]]) + :: + %+ turn (flop vag) + |=([a=duct b=gift] [a %give b]) + :: + %+ turn (flop say) + |= [a=duct b=path c=ship d=[p=@ud q=riff]] + :- a + [%pass b %a %want [who c] [%q %re p.q.d (scot %ud p.d) ~] q.d] + == +``` + +This is very simple code. We see there are exactly four different kinds of +side effects we can generate. + +In `yel` we put gifts that we wish to be sent along the `hun:room` duct to +dill. See the documentation for `++room` above. This is how we display +messages to the terminal. + +In `byn` we put riots that we wish returned to subscribers. Recall that a riot +is a response to a subscription. These are returned to our subscribers in the +form of a `%writ` gift. + +In `vag` we put gifts along with the ducts on which to send them. This allows +us to produce arbitrary gifts, but in practice this is only used to produce +`%ergo` gifts. + +In `say` we put messages we wish to pass to ames. These messages are used to +request information from clay on other piers. We must provide not only the +duct and the request (the riff), but also the return path, the other ship to +talk to, and the sequence number of the request. + +Now that we know what kinds of side effects we may have, we can jump into the +handling of requests. + +``` + ++ ease :: release request + |= hen=duct + ^+ +> + =. qyx (~(del by qyx) hen) + ?~ ref +> + |- ^+ +>+.$ + =+ nux=(~(get by fod.u.ref) hen) + ?~ nux +>+.$ + %= +>+.$ + say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say] + fod.u.ref (~(del by fod.u.ref) hen) + bom.u.ref (~(del by bom.u.ref) u.nux) + == +``` + +This is called when we're cancelling a subscription. First, we remove the duct +from our map of subscribers. For domestic desks, `ref` is null, so we're done. +Although we said we're not going to talk about foreign requests yet, it's easy +to see that for foreign desks, we cancel any outstanding requests for this duct +and send a message over ames to the other ship telling them to cancel the +subscription. + +The more interesting case is, of course, when we're not cancelling a +subscription but starting one. + +``` + ++ eave :: subscribe + |= [hen=duct rav=rave] + ^+ +> + ?- -.rav + & + ?: &(=(p.p.rav %u) !=(p.q.p.rav now)) + ~& [%clay-fail p.q.p.rav %now now] + !! + =+ ver=(aver p.rav) + ?~ ver + (duce hen rav) + ?~ u.ver + (blub hen) + (blab hen p.rav u.u.ver) +``` + +There are two types of subscriptions -- either we're requesting a single file +or we're requesting a range of versions of a desk. We'll dicuss the simpler +case first. + +First, we check that we're not requesting the `rang` from any time other than +the present. Since we don't store that information for any other time, we +can't produce it in a referentially transparent manner for any time other than +the present. + +Then, we try to read the requested `mood` `p.rav`. If we can't access the +request data right now, we call `++duce` to put the request in our queue to be +satisfied when the information becomes available. The code for `++duce` is +nearly the exact inverse of `++ease`, which in the case of a domestic desk is +very simple -- we simply put the duct and rave into `qyx`. This case occurs +when we make a request for a case whose (1) date is after the current date, (2) +number is after the current number, or (3) label is not yet used. + +If `++aver` returned `[~ ~]`, then we cancel the subscription. This occurs +when we make (1) a `%x` request for a file that does not exist, (2) a `%w` +request with a case that is not a number, or (3) a `%w` request with a nonempty +path. The `++blub` is exactly what you would expect it to be. + +``` + ++ blub :: ship stop + |= hen=duct + %_(+> byn [[hen ~] byn]) +``` + +We notify the duct that we're cancelling their subscription since it isn't +satisfiable. + +Otherwise, we have received the desired information, so we send it on to the +subscriber with `++blab`. + +``` + ++ blab :: ship result + |= [hen=duct mun=mood dat=*] + ^+ +> + +>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn]) +``` + +The most interesting arm called in `++eave` is, of course, `++aver`, where we +actually try to read the data. + +``` + ++ aver :: read + |= mun=mood + ^- (unit (unit ,*)) + ?: &(=(p.mun %u) !=(p.q.mun now)) :: prevent bad things + ~& [%clay-fail p.q.mun %now now] + !! + =+ ezy=?~(ref ~ (~(get by haw.u.ref) mun)) + ?^ ezy ezy + =+ nao=(~(aeon ze lim dom ran) q.mun) + :: ~& [%aver-mun nao [%from syd lim q.mun]] + ?~(nao ~ [~ (~(avid ze lim dom ran) u.nao mun)]) +``` + +We check immediately that we're not requesting the `rang` for any time other +than the present. + +If this is a foreign desk, then we check our cache for the specific request. +If either this is a domestic desk or we don't have the request in our cache, +then we have to actually go read the data from our dome. + +We need to do two things. First, we try to find the number of the commit +specified by the given case, and then we try to get the data there. + +Here, we jump into `arvo/zuse.hoon`, which is where much of the algorithmic +code is stored, as opposed to the clay interface, which is stored in +`arvo/clay.hoon`. We examine `++aeon:ze`. + +``` + ++ aeon :: aeon:ze + |= lok=case :: act count through + ^- (unit ,@ud) + ?- -.lok + %da + ?: (gth p.lok lim) ~ + |- ^- (unit ,@ud) + ?: =(0 let) [~ 0] :: avoid underflow + ?: %+ gte p.lok + =< t + %- ~(got by hut) + %- ~(got by hit) + let + [~ let] + $(let (dec let)) + :: + %tas (~(get by lab) p.lok) + %ud ?:((gth p.lok let) ~ [~ p.lok]) + == +``` + +We handle each type of `case` differently. The latter two types are easy. + +If we're requesting a revision by label, then we simply look up the requested +label in `lab` from the given dome. If it exists, that is our number; else we +produce null, indicating the requested revision does not yet exist. + +If we're requesting a revision by number, we check if we've yet reached that +number. If so, we produce the number; else we produce null. + +If we're requesting a revision by date, we check first if the date is in the +future, returning null if so. Else we start from the most recent revision and +scan backwards until we find the first revision committed before that date, and +we produce that. If we requested a date before any revisions were committed, +we produce `0`. + +Assuming we got a valid version number, `++aver` calls `++avid:ze`, which reads +the requested data at the given revision. + +``` + ++ avid :: avid:ze + |= [oan=@ud mun=mood] :: seek and read + ^- (unit) + ?: &(?=(%w p.mun) !?=(%ud -.q.mun)) :: NB only for speed + ?^(r.mun ~ [~ oan]) + (auto:(argo oan) mun) +``` + +If we're requesting the revision number with a case other than by number, then +we go ahead and just produce the number we were given. Otherwise, we call +`++argo` to rewind our state to the given revision, and then we call `++auto` +to get the requested information. + +``` + ++ argo :: argo:ze + |= oan=@ud :: rewind to aeon + ^+ +> + ?: =(let oan) +> + ?: (gth oan let) !! :: don't have this version + +>(ank (azel q:(~(got by hut) (~(got by hit) oan))), let oan) +``` + +If we're already at the requested version, we do nothing. If we're requesting +a version later than our head, we are unable to comply. + +Otherwise, we get the hash of the commit at the number, and from that we get +the commit itself (the yaki), which has the map of path to lobe that represents +a version of the filesystem. We call `++azel` to checkout the commit, and we +replace `ank` in our context with the result. + +``` + ++ azel :: azel:ze + |= hat=(map path lobe) :: checkout commit + ^- ankh + %- cosh + %+ roll (~(tap by hat) ~) + |= [[pat=path bar=lobe] ank=ankh] + ^- ankh + %- cosh + ?~ pat + =+ zar=(zaul bar) + ank(q [~ (sham zar) zar]) + =+ nak=(~(get by r.ank) i.pat) + %= ank + r %+ ~(put by r.ank) i.pat + $(pat t.pat, ank (fall nak _ankh)) + == +``` + +Twice we call `++cosh`, which hashes a commit, updating `p` in an `ankh`. +Let's jump into that algorithm before we describe `++azel`. + +``` +++ cosh :: locally rehash + |= ank=ankh + ank(p dash:(zu ank)) +``` + +We simply replace `p` in the hash with the `cash` we get from a call to +`++dash:zu`. + +``` +++ zu !: :: filesystem + |= ank=ankh :: filesystem state + =| myz=(list ,[p=path q=miso]) :: changes in reverse + =| ram=path :: reverse path into + |% + ++ dash :: local rehash + ^- cash + %+ mix ?~(q.ank 0 p.u.q.ank) + =+ axe=1 + |- ^- cash + ?~ r.ank _@ + ;: mix + (shaf %dash (mix axe (shaf %dush (mix p.n.r.ank p.q.n.r.ank)))) + $(r.ank l.r.ank, axe (peg axe 2)) + $(r.ank r.r.ank, axe (peg axe 3)) + == +``` + +`++zu` is a core we set up with a particular filesystem node to traverse a +checkout of the filesystem and access the actual data inside it. One of the +things we can do with it is to create a recursive hash of the node. + +In `++dash`, if this node is a file, then we xor the remainder of the hash with +the hash of the contents of the file. The remainder of the hash is `0` if we +have no children, else we descend into our children. Basically, we do a half +SHA-256 of the xor of the axis of this child and the half SHA-256 of the xor of +the name of the child and the hash of the child. This is done for each child +and all the results are xored together. + +Now we return to our discussion of `++azel`. + +We fold over every path in this version of the filesystem and create a great +ankh out of them. First, we call `++zaul` to get the raw data referred to be +each lobe. + +``` + ++ zaul :: grab blob + |= p=lobe :: ^- * + %- zaru + (zaal p) +``` + +This converts a lobe into the raw data it refers to by first getting the blob +with `++zaal` and converting that into data with `++zaru`. + +``` + ++ zaal :: grab blob + |= p=lobe :: (raw) + ^- blob + (~(got by lat) p) +``` + +This just grabs the blob that the lobe refers to. + +``` + ++ zaru :: grab blob + |= p=blob + ?- -.p + %delta (lump r.p (zaul q.p)) + %direct q.p + %indirect q.p + == +``` + +If we have either a direct or an indirect blob, then the data is stored right +in the blob. Otherwise, we have to reconstruct it from the diffs. We do this +by calling `++lump` on the diff in the blob with the data obtained by +recursively calling the parent of this blob. + +``` +++ lump :: apply patch + |= [don=udon src=*] + ^- * + ?+ p.don ~|(%unsupported !!) + %a + ?+ -.q.don ~|(%unsupported !!) + %a q.q.don + %c (lurk ((hard (list)) src) p.q.don) + %d (lure src p.q.don) + == + :: + %c + =+ dst=(lore ((hard ,@) src)) + %- roly + ?+ -.q.don ~|(%unsupported !!) + %a ((hard (list ,@t)) q.q.don) + %c (lurk dst p.q.don) + == + == +``` + +This is defined in `arvo/hoon.hoon` for historical reasons which are likely no +longer applicable. Since the `++umph` structure will likely change we convert +clay to be a typed filesystem, we'll only give a high-level description of this +process. If we have a `%a` udon, then we're performing a trivial replace, so +we produce simply `q.q.don`. If we have a `%c` udon, then we're performing a +list merge (as in, for example, lines of text). The merge is performed by +`++lurk`. + +``` +++ lurk :: apply list patch + |* [hel=(list) rug=(urge)] + ^+ hel + =+ war=`_hel`~ + |- ^+ hel + ?~ rug (flop war) + ?- -.i.rug + & + %= $ + rug t.rug + hel (slag p.i.rug hel) + war (weld (flop (scag p.i.rug hel)) war) + == + :: + | + %= $ + rug t.rug + hel =+ gur=(flop p.i.rug) + |- ^+ hel + ?~ gur hel + ?>(&(?=(^ hel) =(i.gur i.hel)) $(hel t.hel, gur t.gur)) + war (weld q.i.rug war) + == + == +``` + +We accumulate our final result in `war`. If there's nothing more in our list +of merge instructions (unces), we just reverse `war` and produce it. +Otherwise, we process another unce. If the unce is of type `&`, then we have +`p.i.rug` lines of no changes, so we just copy them over from `hel` to `war`. +If the unice is of type `|`, then we verify that the source lines (in `hel`) +are what we expect them to be (`p.i.rug`), crashing on failure. If they're +good, then we append the new lines in `q.i.rug` onto `war`. + +And that's really it. List merges are pretty easy. Anyway, if you recall, we +were discussing `++azel`. + +``` + ++ azel :: azel:ze + |= hat=(map path lobe) :: checkout commit + ^- ankh + %- cosh + %+ roll (~(tap by hat) ~) + |= [[pat=path bar=lobe] ank=ankh] + ^- ankh + %- cosh + ?~ pat + =+ zar=(zaul bar) + ank(q [~ (sham zar) zar]) + =+ nak=(~(get by r.ank) i.pat) + %= ank + r %+ ~(put by r.ank) i.pat + $(pat t.pat, ank (fall nak _ankh)) + == +``` + +If the path is null, then we calculate `zar`, the raw data at the path `pat` in +this version. We produce the given ankh with the correct data. + +Otherwise, we try to get the child we're looking at from our parent `ankh`. If +it's already been created, this succeeds; otherwise, we simply create a default +blank ankh. We place ourselves in our parent after recursively computing our +children. + +This algorithm really isn't that complicated, but it may not be immediately +obvious why it works. An example should clear everything up. + +Suppose `hat` is a map of the following information. + + /greeting --> "customary upon meeting" + /greeting/english --> "hello" + /greeting/spanish --> "hola" + /greeting/russian/short --> "привет" + /greeting/russian/long --> "Здравствуйте" + /farewell/russian --> "до свидания" + +Furthermore, let's say that we process them in this order: + + /greeting/english + /greeting/russian/short + /greeting/russian/long + /greeting + /greeting/spanish + /farewell/russian + +Then, the first path we process is `/greeting/english` . Since our path is not +null, we try to get `nak`, but because our ankh is blank at this point it +doesn't find anything. Thus, update our blank top-level ankh with a child +`%greeting`. and recurse with the blank `nak` to create the ankh of the new +child. + +In the recursion, we our path is `/english` and our ankh is again blank. We +try to get the `english` child of our ankh, but this of course fails. Thus, +we update our blank `/greeting` ankh with a child `english` produced by recursing. + +Now our path is null, so we call `++zaul` to get the actual data, and we place +it in the brand-new ankh. + +Next, we process `/greeting/russian/short`. Since our path is not null, we try +to get the child named `%greeting`, which does exist since we created it +earlier. We put modify this child by recursing on it. Our path is now +`/russian/short`, so we look for a `%russian` child in our `/greeting` ankh. +This doesn't exist, so we add it by recursing. Our path is now `/short`, so we +look for a `%short` child in our `/greeting/russian` ankh. This doesn't exist, +so we add it by recursing. Now our path is null, so we set the contents of +this node to `"привет"`, and we're done processing this path. + +Next, we process `/greeting/russian/long`. This proceeds similarly to the +previous except that now the ankh for `/greeting/russian` already exists, so we +simply reuse it rather than creating a new one. Of course, we still must +create a new `/greeting/russian/long` ankh. + +Next, we process `/greeting`. This ankh already exists, so after we've +recursed once, our path is null, and our ankh is not blank -- it already has +two children (and two grandchildren). We don't touch those, though, since a +node may be both a file and a directory. We just add the contents of the file +-- "customary upon meeting" -- to the existing ankh. + +Next, we process `/greeting/spanish`. Of course, the `/greeting` ankh already +exists, but it doesn't have a `%spanish` child, so we create that, taking care +not to disturb the contents of the `/greeting` file. We put "hola" into the +ankh and call it good. + +Finally, we process `/farewell/russian`. Here, the `/farewell` ankh doesn't +exist, so we create it. Clearly the newly-created ankh doesn't have any +children, so we have to add a `%russian` child, and in this child we put our +last content -- "до свидания". + +We hope it's fairly obvious that the order we process the paths doesn't affect +the final ankh tree. The tree will be constructed in a very different order +depending on what order the paths come in, but the resulting tree is +independent of order. + +At any rate, we were talking about something important, weren't we? If you +recall, that concludes our discussion of `++argo`, which was called from +`++avid`. In summary, `++argo` returns a context in which our current state is +(very nearly) as it was when the specified version of the desk was the head. +This allows `++avid` to call `++auto` to read the requested information. + +``` + ++ auto :: auto:ze + |= mun=mood :: read at point + ^- (unit) + ?: ?=(%v p.mun) + [~ `dome`+<+<.auto] + ?: &(?=(%w p.mun) !?=(%ud -.q.mun)) + ?^(r.mun ~ [~ let]) + ?: ?=(%w p.mun) + =+ ^= yak + %- ~(got by hut) + %- ~(got by hit) + let + ?^(r.mun ~ [~ [t.yak (azul yak)]]) + ::?> ?=(^ hit) ?^(r.mun ~ [~ i.hit]) :: what do?? need [@da nori] + (amor(ank ank:(deny:(zu ank) r.mun)) p.mun) +``` + +If we're requesting the dome, then we just return that immediately. + +If we're requesting the revision number of the desk and we're not requesting it +by number, then we just return the current number of this desk. Note of course +that this was really already handled in `++avid`. + +If we're requesting a `%w` with a specific revision number, then we do +something or other with the commit there. It's kind of weird, and it doesn't +seem to work, so we'll ignore this case. + +Otherwise, we descend into the ankh tree with `++deny:zu` to the given path, +and then we handle specific request in `++amor`. + +``` + ++ deny :: descend recursively + |= way=path + ^+ +> + ?~(way +> $(way t.way, +> (dent i.way))) +``` + +This is simple recursion down into the ankh tree. `++dent` descends one level, +so this will eventually get us down to the path we want. + +``` + ++ dent :: descend + |= lol=@ta + ^+ +> + =+ you=(~(get by r.ank) lol) + +>.$(ram [lol ram], ank ?~(you [*cash ~ ~] u.you)) +``` + +`ram` is the path that we're at, so to descend one level we push the name of +this level onto that path. We update the ankh with the correct one at that +path if it exists; else we create a blank one. + +Once we've decscended to the correct level, we need to actually deal with the +request. + +``` + ++ amor :: amor:ze + |= ren=?(%u %v %x %y %z) :: endpoint query + ^- (unit ,*) + ?- ren + %u [~ `rang`+<+>.amor] + %v [~ `dome`+<+<.amor] + %x ?~(q.ank ~ [~ q.u.q.ank]) + %y [~ ache] + %z [~ ank] + == +``` + +Now that everything's set up, it's really easy. If they're requesting the rang +, dome, or ankh, we give it to them. If the contents of a file, we give it to +them if it is in fact a file. If the `arch`, then we calculate it with `++ache`. + +``` + ++ ache :: ache:ze + ^- arch :: arch report + :+ p.ank + ?~(q.ank ~ [~ p.u.q.ank]) + |- ^- (map ,@ta ,~) + ?~ r.ank ~ + [[p.n.r.ank ~] $(r.ank l.r.ank) $(r.ank r.r.ank)] +``` + +This very simply strips out all the "real" data and returns just our own hash, +the hash of the file contents (if we're a file), and a map of the names of our +immediate children. + +Lifecycle of a Local Subscription +--------------------------------- + +A subscription to a range of revisions of a desk initially follows the same +path that a single read does. In `++aver`, we checked the head of the given +rave. If the head was `&`, then it was a single request, so we handled it +above. If `|`, then we handle it with the following code. + +``` + | + =+ nab=(~(aeon ze lim dom ran) p.p.rav) + ?~ nab + ?> =(~ (~(aeon ze lim dom ran) q.p.rav)) + (duce hen rav) + =+ huy=(~(aeon ze lim dom ran) q.p.rav) + ?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab)))) + (blub hen) + =+ top=?~(huy let.dom u.huy) + =+ fud=(~(gack ze lim dom ran) u.nab let.dom) + =. +>.$ (bleb hen u.nab fud) + ?^ huy + (blub hen) + =+ ^= ptr ^- case + [%ud +(let.dom)] + (duce hen `rave`[%| ptr q.p.rav]) + == +``` + +Recall that `++aeon:ze` produces the revision number that a case corresponds +to, if it corresponds to any. If it doesn't yet correspond to a revision, then +it produces null. + +Thus, we first check to see if we've even gotten to the beginning of the range +of revisions requested. If not, then we assert that we haven't yet gotten to +the end of the range either, because that would be really strange. If not, +then we immediately call `++duce`, which, if you recall, for a local request, +simply puts this duct and rave into our cult `qyx`, so that we know who to +respond to when the revision does appear. + +If we've already gotten to the first revision, then we can produce some content +immediately. If we've also gotten to the final revision, and that revision is +earlier than the start revision, then it's a bad request and we call `++blub`, +which tells the subscriber that his subscription will not be satisfied. + +Otherwise, we call `++gack`, which creates the `++nako` we need to produce. We +call `++bleb` to actually produce the information. If we already have the last +requested revision, then we also tell the subscriber with `++blub` that the +subscription will receive no further updates. + +If there will be more revisions, that we'll need to report, then we call +`++duce`, adding the duct to our subscribers. We modify the rave to start at +the next revision since we've already handled all the revisions up to the +present. + +We glossed over the calls to `++gack` and `++bleb`, so we'll get back to those +right now. `++bleb` is simple, so we'll start with that. + +``` + ++ bleb :: ship sequence + |= [hen=duct ins=@ud hip=nako] + ^+ +> + (blab hen [%w [%ud ins] ~] hip) +``` + +We're given a duct, the beginning revision number, and the nako that contains +the updates since that revision. We use `++blab` to produce this result to +the subscriber. The case is `%w` with a revision number of the beginning of the +subscription, and the data is the nako itself. + +Finally, we will describe `++gack:ze`. + +``` + ++ gack :: gack a through b + |= [a=@ud b=@ud] + ^- [(map ,@ud tako) @ud (set yaki) (set blob)] + :_ :- b + %- hack + %+ pack + (~(get by hit) a) :: if a not found, a=0 + %- need (~(get by hit) b) + ^- (map ,@ud tako) + %- mo %+ skim (~(tap by hit) ~) + |= [p=@ud *] + &((gth p a) (lte p b)) +``` + + + +``` + ++ hack :: trivial + |= [a=(set tako) b=(set lobe)] + ^- [(set yaki) (set blob)] + :- %- sa %+ turn (~(tap by a) ~) + |= tak=tako + (need (~(get by hut) tak)) + %- sa %+ turn (~(tap by b) ~) + |= lob=lobe + (need (~(get by lat) lob)) +``` + +The type signature says everything you need to know about this. We take a set +of hashes of commits and data and convert them into the actual commits and data +in the most straightforward way possible. + +``` + ++ pack + |= [a=(unit tako) b=tako] :: pack a through b + ^- [(set tako) (set lobe)] + =+ ^= sar + ?~ a ~ + (zule r:(need (~(get by hut) u.a))) + =+ yak=`yaki`(need (~(get by hut) b)) + %+ garf (garg ~ sar) :: get lobes + |- ^- (set tako) :: walk onto sar + ?: (~(has in sar) r.yak) + ~ + =+ ber=`(set tako)`(~(put in `(set tako)`~) `tako`r.yak) + %- ~(uni in ber) + ^- (set tako) + %+ roll p.yak + |= [yek=tako bar=(set tako)] + ^- (set tako) + ?: (~(has in bar) yek) :: save some time + bar + %- ~(uni in bar) + ^$(yak (need (~(get by hut) yek))) +``` + +``` + ++ zule :: reachable + |= p=tako :: XX slow + ^- (set tako) + =+ y=(~(got by hut) p) + =+ t=(~(put in _(set tako)) p) + %+ roll p.y + |= [q=tako s=_t] + ?: (~(has in s) q) :: already done + s :: hence skip + (~(uni in s) ^$(p q)) :: otherwise traverse +``` + +``` + ++ garg :: object hash set + |= [b=(set lobe) a=(set tako)] :: that aren't in b + ^- (set lobe) + %+ roll (~(tap in a) ~) + |= [tak=tako bar=(set lobe)] + ^- (set lobe) + =+ yak=(need (~(get by hut) tak)) + %+ roll (~(tap by q.yak) ~) + |= [[path lob=lobe] far=_bar] + ^- (set lobe) + ?~ (~(has in b) lob) :: don't need + far + =+ gar=(need (~(get by lat) lob)) + ?- -.gar + %direct (~(put in far) lob) + %delta (~(put in $(lob q.gar)) lob) + %indirect (~(put in $(lob s.gar)) lob) + == +``` + +``` + ++ garf :: garg & repack + |= [b=(set lobe) a=(set tako)] + ^- [(set tako) (set lobe)] + [a (garg b a)] +``` diff --git a/main/pub/src/doc/ref/volumes/4/4d.md b/main/pub/src/doc/ref/vol/4d.md similarity index 100% rename from main/pub/src/doc/ref/volumes/4/4d.md rename to main/pub/src/doc/ref/vol/4d.md diff --git a/main/pub/src/doc/ref/volumes/4/4e.md b/main/pub/src/doc/ref/vol/4e.md similarity index 100% rename from main/pub/src/doc/ref/volumes/4/4e.md rename to main/pub/src/doc/ref/vol/4e.md diff --git a/main/pub/src/doc/ref/volumes/4/4f.md b/main/pub/src/doc/ref/vol/4f.md similarity index 100% rename from main/pub/src/doc/ref/volumes/4/4f.md rename to main/pub/src/doc/ref/vol/4f.md diff --git a/main/pub/src/doc/ref/volumes/4/4g.md b/main/pub/src/doc/ref/vol/4g.md similarity index 100% rename from main/pub/src/doc/ref/volumes/4/4g.md rename to main/pub/src/doc/ref/vol/4g.md diff --git a/main/pub/src/doc/ref/volumes/index.md b/main/pub/src/doc/ref/vol/index.md similarity index 88% rename from main/pub/src/doc/ref/volumes/index.md rename to main/pub/src/doc/ref/vol/index.md index 82da6afd9..e4f30be6c 100644 --- a/main/pub/src/doc/ref/volumes/index.md +++ b/main/pub/src/doc/ref/vol/index.md @@ -18,8 +18,6 @@ - chapter 2c, simple noun surgery - ### Chapters 2a through 2eZ refactoring and second-pass. - ### Dulin and Henry. - section 2cA, bit surgery - section 2cB, bit logic @@ -40,8 +38,6 @@ - chapter 2e, miscellaneous libs - ### Anton - virtualization - - section 2eA, packing - section 2eB, parsing (tracing) - section 2eC, parsing (custom rules) @@ -63,7 +59,6 @@ - section 2eY, SHA-2564 (move me) - section 2eZ, OLD rendering (kill me) - ### Chapter 2f is Philip. - chapter 2f, Hoon proper @@ -78,20 +73,18 @@ - chapter 3b, Arvo libraries, zuse - ### Anton - All of Chapter 3b except 3bE and 3bG. - - section 3bA, lite number theory - section 3bB, cryptosuites - section 3bC, UTC - section 3bD, JSON and XML - section 3bE, tree sync - - section 3bF, names etc - - section 3bG, Arvo models + - section 3bF!, filesystem interface + - section 3bG!, URL handling + - section 3bH!, names etc + - section 3bI!, Arvo models - Volume 4, Arvo vanes - ### Chapter 4a, %ames, is Philip. Possibly %ford nad %gall as well. - - chapter 4a, ames, networking - section 4aA, structures @@ -114,8 +107,6 @@ - section 4cB, filesystem logic - section 4cC, filesystem vane - ### Anton Chapter 4d - - chapter 4d, dill: terminal handling - chapter 4e, eyre: http servant diff --git a/main/pub/src/doc/ref/volumes/nock.md b/main/pub/src/doc/ref/vol/nock.md similarity index 100% rename from main/pub/src/doc/ref/volumes/nock.md rename to main/pub/src/doc/ref/vol/nock.md diff --git a/main/pub/src/doc/ref/volumes/4/4a.md b/main/pub/src/doc/ref/volumes/4/4a.md deleted file mode 100644 index 8dc25825a..000000000 --- a/main/pub/src/doc/ref/volumes/4/4a.md +++ /dev/null @@ -1,481 +0,0 @@ -Ames -==== - -Ames is our networking protocol. - -data models ------------ - -###`++fort`, formal state - -``` -++ fort :: formal state - $: %0 :: version - gad=duct :: client interface - hop=@da :: network boot date - ton=town :: security - zac=(map ship corn) :: flows by server - == :: -``` - -This is the state of our vane. Anything that must be remembered between -calls to ames must be stored in this state. - -`%0` is the version of the ames state model itself. If the data model `++fort` -changes, then this number needs to be incremented, and an adapter must be -written to upgrade the old state into the new state. Note that this is the -version number of the model itself, not the contents. When the data changes, -there is of course no need to change this. - -`gad` is a `duct` over which we send `%send` cards to unix. This card is -initialized when unix sends a `%barn` card as vere starts up. Vere treats this -duct specially -- don't send anything weird over it. - -`hop` is the network boot date. This is set when the `%kick` card is sent by -vere on start up. - -`ton` is a `++town`, where we store all of our security/encryption state. Note -that this is shared across all ships on a pier. - -`zac` is a map of ships to `++corn`. This stores all the per-ship state. The -keys to this map are the ships on the current pier. - -###`++town`, all security state - -``` -++ town :: all security state - $: lit=@ud :: imperial modulus - any=@ :: entropy - urb=(map ship sufi) :: all keys and routes - fak=? :: - == :: -``` - -This is the security state of our pier. - -`lit` is unused. - -`any` is 256 bits of entropy. This entropy is used and updated in exactly two -places: when we send a `%junk` card, and when we generate a new symmetric key -in `++griz:lax:as:go`. When it is updated, it is updated by a SHA-256 hash of -the current time and the old value of the entropy. - -`urb` is a map of ships to `++sufi`. This is where we store all the per-ship -state for the pier. The keys to this map are the ships on the current pier. - -`fak` is true if we are on a fake network. This disables certain security -checks so that anyone may run a fake `~zod`. This is used only for development. -To use, run vere with the `-F` option (and the `-I ~zod` option for a fake -`~zod`). - -###`++sufi`, domestic host - -``` -++ sufi :: domestic host - $: hoy=(list ship) :: hierarchy - val=wund :: private keys - law=will :: server will - seh=(map hand ,[p=ship q=@da]) :: key cache - hoc=(map ship dore) :: neighborhood - == :: -``` - -This is the security state of a domestic server. - -`hoy` is a list of the ships directly above us in the hierarchy of ships. For -example, for `~hoclur-bicrel`, this would be `~tasruc` and `~tug`. See -`++sein`. - -`val` is a list of our private keys. - -`law` is our certificate, which is a list of the XXX - -`seh` - -`hoc` is a map of ships to `++dore`. The stores all the security informatoin -about foreign ships. The keys to this map are the neighbors (ships we have -been in contact with) of this domestic server. - -###`++wund`, private keys - -``` -++ wund (list ,[p=life q=ring r=acru]) :: mace in action -``` - -This is a list of our own private keys, indexed by life. The key itself is -the `++ring`, and the `++acru` is the encryption engine. We generate the -`++acru` from the private key by calling `++weur`. Thus, we can at any time -regenerate our `++wund` from a `++mace`. The current crypto is at the head of -the list and can be accessed with -`++sen:as:go`. - -###`++ring`, private key - -``` -++ ring ,@ :: private key -``` - -This is a private key. The first byte is reserved to identify the type of -cryptography. Lower-case means public key, upper-case means public key, and -the letter identifies which `++acru` to use. - -###`++pass`, public key - -``` -++ pass ,@ :: public key -``` - -This is a public key. The first byte is reserved to identify the type of -cryptography. Lower-case means public key, upper-case means public key, and -the letter identifies which `++acru` to use. - -###`++mace`, private secrets - -``` -++ mace (list ,[p=life q=ring]) :: private secrets -``` - -This is a list of the our private keys, indexed by life. From this we can -generate a `++wund` for actual use. - -###`++skin`, encoding stem - -``` -++ skin ?(%none %open %fast %full) :: encoding stem -``` - -This defines the type of encryption used for each message. `%none` refers -to messages sent in the clear, `%open` refers to signed messages, `%full` -refers to sealed messages, and `%fast` refers to symmetrically encrypted -messages. See `++acru` for details. - -###`++acru`, asymmetric cryptosuite - -``` -++ acru :: asym cryptosuite - $_ ^? |% :: opaque object - ++ as ^? :: asym ops - |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a - ++ sign |=([a=@ b=@] _@) :: certify as us - ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us - ++ tear |= [a=pass b=@] :: accept from a - *(unit ,[p=@ q=@]) :: - -- :: - ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft - ++ dy |+([a=@ b=@] _@) :: symmetric de, hard - ++ en |+([a=@ b=@] _@) :: symmetric en - ++ ex ^? :: export - |% ++ fig _@uvH :: fingerprint - ++ pac _@uvG :: default passcode - ++ pub *pass :: public key - ++ sec *ring :: private key - -- - ++ nu ^? :: reconstructors - |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed] - ++ nol |=(a=@ ^?(..nu)) :: from naked ring - ++ com |=(a=@ ^?(..nu)) :: from naked pass - -- - -- -``` - -This is an opaque interface for a general asymmetric cryptosuite. Any form -of asymmetric cryptography can be dropped in to be used instead of the default. -Right now, there are two cryptosuites, `++crua`, which is your standard RSA, -and `++crub`, which is elliptic curve crypto but is mostly stubbed out at the -moment. - -####`++as:acru`, asymmetric operations - -``` - ++ as ^? :: asym ops - |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a - ++ sign |=([a=@ b=@] _@) :: certify as us - ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us - ++ tear |= [a=pass b=@] :: accept from a - *(unit ,[p=@ q=@]) :: - -- :: -``` - -This is the core that defines the standard asymmetric cryptography -operations. - -`++seal:as:acru` allows us to send a message encrypted with someone's public -key so that only they may read it. If Alice seals a message with Bob's public -key, then she can be sure that Bob is the only one who can read it. This is -associated with the `++skin` `%full`. - -`++sign:as:acru` allows us to sign a message with our private key so that -others can verify that we sent the message. If Alice signs a message with her -private key, then Bob can verify with her public key that it was indeed Alice -who sent it. This is associated with the `++skin` `%open`. - -`++sure:as:acru` is the dual to `++sign:as:acru`. It allows us to verify that -a message we have received is indeed from the claimed sender. If Alice sends a -message with her private key, then Bob can use this arm to verify that it was -indeed Alice who sent it. This is associated with the `++skin` `%open`. - -`++tear:as:acru` is the dual to `++seal:as:acru`. It allows us to read a -message that we can be sure is only read by us. If Alice seals a message with -Bob's public key, then Bob can use this arm to read it. This is associated -with the `++skin` `%full`. - -####`++de:acru`, `++dy:acru`, and `++en:acru`, symmetric encryption/decryption - -``` - ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft - ++ dy |+([a=@ b=@] _@) :: symmetric de, hard - ++ en |+([a=@ b=@] _@) :: symmetric en -``` - -Symmetric encryption is associated with the `++skin` `%fast`. - -`++de:acru` decrypts a message with a symmetric key, returning `~` on failure -and `[~ u=data]` on success. - -`++dy:acru` decrypts a message with a symmetric key, crashing on failure. This -should almost always be defined as, and should always be semantically -equivalent to, `(need (de a b))`. - -`++en:acru` encrypts a message with a symmetric key. - -####`++ex:acru`, exporting data - -``` - ++ ex ^? :: export - |% ++ fig _@uvH :: fingerprint - ++ pac _@uvG :: default passcode - ++ pub *pass :: public key - ++ sec *ring :: private key - -- -``` - -`++fig:ex:acru` is our fingerprint, usually a hash of our public key. This is -used, for example, in `++zeno`, where every carrier owner's fingerprint is -stored so that we can ensure that carriers are indeed owned by their owners - -`++pac:ex:acru` is our default passcode, which is unused at present. - -`++pub:ex:acru` is the `++pass` form of our public key. - -`++sec:ex:acru` is the `++ring` form of our private key. - -####`++nu:acru`, reconstructors - -``` - ++ nu ^? :: reconstructors - |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed] - ++ nol |=(a=@ ^?(..nu)) :: from naked ring - ++ com |=(a=@ ^?(..nu)) :: from naked pass - -- -``` - -These arms allow us to reconstruct a `++acru` from basic data. - -`++pit:nu:acru` constructs a `++acru` from the width of our intended key and -seed entropy. This is usually used in the initial construction of the -`++acru`. - -`++nol:nu:acru` constructs a `++acru` from a "naked ring", meaning a `++ring` -without the initial byte identifying the type of crypto. There is often a -helper arm that that wraps this; see `++weur` for `++crua` and `++wear` for -`++crub`. - -`++com:nu:acru` constructs a `++acru` from a "naked pass", meaning a `++ring` -without the initial byte identifying the type of crypto. There is often a -helper arm that that wraps this; see `++haul` for `++crua` and `++hail` for -`++crub`. - -###`++will`, certificate - -``` -++ will (list deed) :: certificate -``` - -This is a list of deeds associated with the current ship. There should be -an item in this list for every ship from this point up in the hierarchy times -the number of lives that each ship has had. For example, ~hoclur-bicrel may -have a will with three items: one for itself, one for ~tasruc (who issued -~hoclur-bicrel's deed) and one for ~tug (who issued ~tasruc's deed). - -###`++deed`, identity - -``` -++ deed ,[p=@ q=step r=?] :: sig, stage, fake? -``` - -`p` is the signature of a particular deed, which is a signed copy of `q`. - -`q` is the stage in the identity. - -`r` is true if we're working on a fake network, where we don't check that the -carrier fingerprints are correct. This allows us to create fake networks for -development without interfering with the real network. - -###`++step`, identity stage - -``` -++ step ,[p=bray q=gens r=pass] :: identity stage -``` - -This is a single stage in our identity. Thus, this is specific to a single -life in a single ship. Everything in here may change between lives. - -`p` - -`q` - -`r` is the public key for this stage in the identity. - -###`++bray` - -``` -++ bray ,[p=life q=(unit life) r=ship s=@da] :: our parent us now -``` - -XXX - -###`++gens`, general identity - -``` -++ gens ,[p=lang q=gcos] :: general identity -``` - -`p` is the IETF language code for the preferred language of this identity. -This is unused at the moment, but in the future text should be localized based -on this. - -`q` is the description of the ship. - -###`++gcos`, identity description - -``` -++ gcos :: id description - $% [%czar ~] :: 8-bit ship - [%duke p=what] :: 32-bit ship - [%earl p=@t] :: 64-bit ship - [%king p=@t] :: 16-bit ship - [%pawn p=(unit ,@t)] :: 128-bit ship - == :: -``` - -This is the description of the identity of a ship. Most types of identity have -a `@t` field, which is their human-readable name. The identity of a `%duke` is -more involved. - -A `%czar`, a carrier, is a ship with an 8-bit address. Thus, there are only -256 carriers. These are at the top of the namespace hierarchy, and the -fingerprint of each carrier is stored in `++zeno`. These are the "senators" of -Urbit. - -A `%king`, a cruiser, is a ship with a 16-bit address. Thus, there are 65,536 -cruisers. Each carrier may issue 256 cruisers. These are the infrastructure -of Urbit. - -A `%duke`, a destroyer, is a ship with a 32-bit address. Thus, there are -4,294,967,296 destroyers. Each cruiser may issue 65,536 cruisers. These are -the individuals of Urbit. - -A `%earl`, a yacht, is a ship with a 64-bit address. Thus, there are -18,446,744,073,709,551,616 yachts. Each destroyer may issue 4,294,967,296 -yachts. These are the devices of Urbit. - -A `%pawn`, a submarine, is a ship with a 128-bit address. Thus, there are a -lot of submarines. The chance of random name collision is negligible, so -submarines are not issued by any ship. They must simply assert their presence, -and they are all considered children of ~zod. This is the underworld of Urbit, -where anonymity reigns supreme. - -###`++what`, logical destroyer identity - -``` -++ what :: logical identity - $% [%anon ~] :: anonymous - [%lady p=whom] :: female person () - [%lord p=whom] :: male person [] - [%punk p=sect q=@t] :: opaque handle "" - == :: -``` - -This is the logical identity of a destroyer. - -A `%anon` is a completely anonymous destroyer. The difference between this and -a submarine is that a submarine is ephemeral while a `%anon` destroyer is not. -Thus, we may not know who ~hoclur-bicrel is, but we do know that it's always -the same person. - -A `%lady` is a female person. The name used here should be a real name. - -A `%lord` is a male person. The name used here should be a real name. - -A `%punk` is a person who is identified only by a handle. - -###`++whom`, real person - -``` -++ whom ,[p=@ud q=govt r=sect s=name] :: year/govt/id -``` - -Ths is the information associated with a real person. It is mostly information -that could be observed with the briefest of interactions. - -`p` is the birth year. - -`q` is the location of a user, usually of the form "country/zip". - -`r` is the sect of the user. - -`s` is the real name of the person. - - -###`++govt` - -``` -++ govt path :: country/postcode -``` - -This is the location of the user, usually of the form "country/zip". - -###`++sect` - -``` -++ sect ?(%black %blue %red %orange %white) :: banner -``` - -XXX - -###`++name` - -``` -++ name ,[p=@t q=(unit ,@t) r=(unit ,@t) s=@t] :: first mid/nick last -``` - -This is the given name, possible middle name/initial, possible nickname, and -surname of a user. - -packet format -------------- - -`++go`, PKI engine ------------------- - -###`++as`, per server - -####`++born`, register user - -#####`++lax`, per client - -`++pu`, packet pump -------------------- - -`++am`, protocol engine ------------------------ - -###`++um`, per server - -####`++ho`, per friend - -#####`++la`, per packet - -protocol vane -------------- - diff --git a/main/pub/src/doc/ref/volumes/4/4c.md b/main/pub/src/doc/ref/volumes/4/4c.md deleted file mode 100644 index e74531575..000000000 --- a/main/pub/src/doc/ref/volumes/4/4c.md +++ /dev/null @@ -1,484 +0,0 @@ -Clay -==== - -Clay is our filesystem. - -data models ------------ - -###`++raft`, formal state - -``` -++ raft :: filesystem - $: fat=(map ship room) :: domestic - hoy=(map ship rung) :: foreign - ran=rang :: hashes - == :: -``` - -This is the state of our vane. Anything that must be remembered between calls -to clay must be stored in this state. - -`fat` is the set of domestic servers. This stores all the information that is -specfic to a particular ship on this pier. The keys to this map are the ships -on the current pier. - -`hoy` is the set of foreign servers that we know anything about. This stores -all the information that is specific to a particular foreign ship. The keys to -this map are all the ships whose filesystems we have attempted to access -through clay. - -`ran` is the store of all commits and deltas, keyed by hash. The is where all -the "real" data we know is stored; the rest is "just bookkeeping". - -###`++room`, filesystem per domestic ship - -``` -++ room :: fs per ship - $: hun=duct :: terminal duct - hez=(unit duct) :: sync duch - dos=(map desk dojo) :: native desk - == :: -``` - -This is the representation of the filesystem of a ship on our pier. - -`hun` is the duct that we use to send messages to dill to display notifications -of filesystem changes. Only `%note` gifts should be produced along this duct. -This is set by the `%init` kiss. - -`hez`, if present, is the duct we use to send sync messages to unix so that -they end up in the pier unix directory. Only `%ergo` gifts should be producd -along this duct. This is set by `%into` and `%invo` gifts. - -`dos` is a well-known operating system released in 1981. It is also the set of -desks on this ship, mapped to their data. - -###`++desk`, filesystem branch - -``` -++ desk ,@tas :: ship desk case spur -``` - -This is the name of a branch of the filesystem. The default desks are "arvo", -"main", and "try". More may be created by simply referencing them. Desks have -independent histories and states, and they may be merged into each other. - -###`++dojo`, domestic desk state - -``` -++ dojo ,[p=cult q=dome] :: domestic desk state -``` - -This is the all the data that is specific to a particular desk on a domestic -ship. `p` is the set of subscribers to this desk and `q` is the data in the -desk. - -###`++cult`, subscriptions - -``` -++ cult (map duct rave) :: subscriptions -``` - -This is the set of subscriptions to a particular desk. The keys are the ducts -from where the subscriptions requests came. The results will be produced along -these ducts. The values are a description of the requested information. - -###`++rave`, general subscription request - -``` -++ rave :: general request - $% [& p=mood] :: single request - [| p=moat] :: change range - == :: -``` - -This represents a subscription request for a desk. The request can be for -either a single item in the desk or else for a range of changes on the desk. - -###`++mood`, single subscription request - -``` -++ mood ,[p=care q=case r=path] :: request in desk -``` - -This represents a request for the state of the desk at a particular commit, -specfied by `q`. `p` specifies what kind of information is desired, and `r` -specifies the path we are requesting. - -###`++moat`, range subscription request - -``` -++ moat ,[p=case q=case] :: change range -``` - -This represents a request for all changes between `p` and `q`. Note that there -is currently no way to request to be notified only on changes to particular -paths in the filesystem. You must subscribe to the entire desk. - -###`++care`, clay submode - -``` -++ care ?(%u %v %w %x %y %z) :: clay submode -``` - -This specifies what type of information is requested in a subscription or a -scry. - -`%u` requests the `++rang` at the current moment. Because this information is -not stored for any moment other than the present, we crash if the `++case` is -not a `%da` for now. - -`%v` requests the `++dome` at the specified commit. - -`%w` requests the current revsion number of the desk. - -`%x` requests the file at a specified path at the specified commit. If there -is no node at that path or if the node has no contents (that is, if `q:ankh` is -null), then this produces null. - -`%y` requests a `++arch` of the specfied commit at the specified path. - -`%z` requests the `++ankh` of the specified commit at the specfied path. - -###`++arch`, shallow filesystem node - -``` -++ arch ,[p=@uvI q=(unit ,@uvI) r=(map ,@ta ,~)] :: fundamental node -``` - -This is analogous to `++ankh` except that the we have neither our contents nor -the ankhs of our children. The other fields are exactly the same, so `p` is a -hash of the associated ankh, `u.q`, if it exists, is a hash of the contents of -this node, and the keys of `r` are the names of our children. `r` is a map to -null rather than a set so that the ordering of the map will be equivalent to -that of `r:ankh`, allowing efficient conversion. - -###`++case`, specifying a commit - -``` -++ case :: ship desk case spur - $% [%da p=@da] :: date - [%tas p=@tas] :: label - [%ud p=@ud] :: number - == :: -``` - -A commit can be referred to in three ways: `%da` refers to the commit that was -at the head on date `p`, `%tas` refers to the commit labeled `p`, and `%ud` -refers to the commit numbered `p`. Note that since these all can be reduced -down to a `%ud`, only numbered commits may be referenced with a `++case`. - -###`++dome`, desk data - -``` -++ dome :: project state - $: ang=agon :: pedigree - ank=ankh :: state - let=@ud :: top id - hit=(map ,@ud tako) :: changes by id - lab=(map ,@tas ,@ud) :: labels - == :: -``` - -This is the data that is actually stored in a desk. - -`ang` is unused and should be removed. - -`ank` is the current state of the desk. Thus, it is the state of the -filesystem at revison `let`. The head of a desk is always a numbered commit. - -`let` is the number of the most recently numbered commit. This is also the -total number of numbered commits. - -`hit` is a map of numerical ids to hashes of commits. These hashes are mapped -into their associated commits in `hut:rang`. In general, the keys of this map -are exactly the numbers from 1 to `let`, with no gaps. Of course, when there -are no numbered commits, `let` is 0, so `hit` is null. Additionally, each of -the commits is an ancestor of every commit numbered greater than this one. -Thus, each is a descendant of every commit numbered less than this one. Since -it is true that the date in each commit (`t:yaki`) is no earlier than that of -each of its parents, the numbered commits are totally ordered in the same way -by both pedigree and date. Of course, not every commit is numbered. If that -sounds too complicated to you, don't worry about it. It basically behaves -exactly as you would expect. - -`lab` is a map of textual labels to numbered commits. Note that labels can -only be applied to numbered commits. Labels must be unique across a desk. - -###`++ankh`, filesystem node - -``` -++ ankh :: fs node (new) - $: p=cash :: recursive hash - q=(unit ,[p=cash q=*]) :: file - r=(map ,@ta ankh) :: folders - == :: -``` - -This is a single node in the filesystem. This may be file or a directory or -both. In earth filesystems, a node is a file xor a directory. On mars, we're -inclusive, so a node is a file ior a directory. - -`p` is a recursive hash that depends on the contents of the this file or -directory and on any children. - -`q` is the contents of this file, if any. `p.q` is a hash of the contents -while `q.q` is the data itself. - -`r` is the set of children of this node. In the case of a pure file, this is -empty. The keys are the names of the children and the values are, recursively, -the nodes themselves. - -###`++cash`, ankh hash - -``` -++ cash ,@uvH :: ankh hash -``` - -This is a 128-bit hash of an ankh. These are mostly stored within ankhs -themselves, and they are used to check for changes in possibly-deep -hierarchies. - -###`++rung`, filesystem per neighbor ship - -``` -++ rung $: rus=(map desk rede) :: neighbor desks - == :: -``` - -This is the filesystem of a neighbor ship. The keys to this map are all the -desks we know about on their ship. - -###`++rede`, desk state - -``` -++ rede :: universal project - $: lim=@da :: complete to - qyx=cult :: subscribers - ref=(unit rind) :: outgoing requests - dom=dome :: revision state - == :: -``` - -This is our knowledge of the state of a desk, either foreign or domestic. - -`lim` is the date of the last full update. We only respond to requests for -stuff before this time. - -`qyx` is the list of subscribers to this desk. For domestic desks, this is -simply `p:dojo`, all subscribers to the desk, while in foreign desks this is -all the subscribers from our ship to the foreign desk. - -`ref` is the request manager for the desk. - -`dom` is the actual data in the desk. - -###`++rind`, request manager - -``` -++ rind :: request manager - $: nix=@ud :: request index - bom=(map ,@ud ,[p=duct q=rave]) :: outstanding - fod=(map duct ,@ud) :: current requests - haw=(map mood (unit)) :: simple cache - == :: -``` - -This is the request manager for a desk. - -`nix` is one more than the index of the most recent request. Thus, it is the -next available request number. - -`bom` is the set of outstanding requests. The keys of this map are some subset -of the numbers between 0 and one less than `nix`. The members of the map are -exactly those requests that have not yet been fully satisfied. - -`fod` is the same set as `bom`, but from a different perspective. In -particular, the values of `fod` are the same as the values of `bom`, and the -`p` out of the values of `bom` are the same as the keys of `fod`. Thus, we can -map ducts to their associated request number and `++rave`, and we can map -numbers to their associated duct and `++rave`. - -`haw` is a map from simple requests to their values. This acts as a cache for -requests that have already been made. Thus, the second request for a -particular `++mood` is nearly instantaneous. - -###`++rang`, data store - -``` -++ rang $: hut=(map tako yaki) :: - lat=(map lobe blob) :: - == :: -``` - -This is a set of data keyed by hash. Thus, this is where the "real" data is -stored, but it is only meaningful if we know the hash of what we're looking -for. - -`hut` is a map from hashes to commits. We often get the hashes from -`hit:dome`, which keys them by logical id. Not every commit has an id. - -`lat` is a map from hashes to the actual data. We often get the hashes from a -`++yaki`, a commit, which references this map to get the data. There is no -`++blob` in any `++yaki`. They are only accessible through this map. - -###`++tako`, commit reference - -``` -++ tako ,@ :: yaki ref -``` - -This is a hash of a `++yaki`, a commit. These are most notably used as the -keys in `hut:rang`, where they are associated with the actual `++yaki`, and as -the values in `hit:dome`, where sequential ids are associated with these. - -###`++yaki`, commit - -``` -++ yaki ,[p=(list tako) q=(map path lobe) r=tako t=@da] :: commit -``` - -This is a single commit. - -`p` is a list of the hashes of the parents of this commit. In most cases, this -will be a single commit, but in a merge there may be more parents. In theory, -there may be an arbitrary number of parents, but in practice merges have -exactly two parents. This may change in the future. For commit 1, there is no -parent. - -`q` is a map of the paths on a desk to the data at that location. If you -understand what a `++lobe` and a `++blob` is, then the type signature here -tells the whole story. - -`r` is the hash associated with this commit. - -`t` is the date at which this commit was made. - -###`++lobe`, data reference - -``` -++ lobe ,@ :: blob ref -``` - -This is a hash of a `++blob`. These are most notably used in `lat:rang`, where -they are associated with the actual `++blob`, and as the values in `q:yaki`, -where paths are associated with their data in a commit. - -###`++blob`, data - -``` -++ blob $% [%delta p=lobe q=lobe r=udon] :: delta on q - [%direct p=lobe q=* r=umph] :: - [%indirect p=lobe q=* r=udon s=lobe] :: - == :: -``` - -This is a node of data. In every case, `p` is the hash of the blob. - -`%delta` is the case where we define the data by a delta on other data. In -practice, the other data is always the previous commit, but nothing depends on -this. `q` is the hash of the parent blob, and `r` is the delta. - -`%direct` is the case where we simply have the data directly. `q` is the data -itself, and `r` is any preprocessing instructions. These almost always come -from the creation of a file. - -`%indirect` is both of the preceding cases at once. `q` is the direct data, -`r` is the delta, and `s` is the parent blob. It should always be the case -that applying `r` to `s` gives the same data as `q` directly (with the -prepreprocessor instructions in `p.r`). This exists purely for performance -reasons. This is unused, at the moment, but in general these should be created -when there are a long line of changes so that we do not have to traverse the -delta chain back to the creation of the file. - -###`++udon`, abstract delta - -``` -++ udon :: abstract delta - $: p=umph :: preprocessor - $= q :: patch - $% [%a p=* q=*] :: trivial replace - [%b p=udal] :: atomic indel - [%c p=(urge)] :: list indel - [%d p=upas q=upas] :: tree edit - == :: - == :: -``` - -This is an abstract change to a file. This is a superset of what would -normally be called diffs. Diffs usually refer to changes in lines of text -while we have the ability to do more interesting deltas on arbitrary data -structures. - -`p` is any preprocessor instructions. - -`%a` refers to the trival delta of a complete replace of old data with new -data. - -`%b` refers to changes in an opaque atom on the block level. This has very -limited usefulness, and is not used at the moment. - -`%c` refers to changes in a list of data. This is often lines of text, which -is your classic diff. We, however, will work on any list of data. - -`%d` refers to changes in a tree of data. This is general enough to describe -changes to any hoon noun, but often more special-purpose delta should be -created for different content types. This is not used at the moment, and may -in fact be unimplemented. - -###`++urge`, list change - -``` -++ urge |*(a=_,* (list (unce a))) :: list change -``` - -This is a parametrized type for list changes. For example, `(urge ,@t)` is a -list change for lines of text. - -###`++unce`, change part of a list. - -``` -++ unce |* a=_,* :: change part - $% [%& p=@ud] :: skip[copy] - [%| p=(list a) q=(list a)] :: p -> q[chunk] - == :: -``` - -This is a single change in a list of elements of type `a`. For example, `(unce ,@t)` is -a single change in a lines of text. - -`%&` means the next `p` lines are unchanged. - -`%|` means the lines `p` have changed to `q`. - -###`++umph`, preprocessing information - -``` -++ umph :: change filter - $| $? %a :: no filter - %b :: jamfile - %c :: LF text - == :: - $% [%d p=@ud] :: blocklist - == :: -``` - -This space intentionally left undocumented. This stuff will change once we get -a well-typed clay. - - -###`++upas`, tree change - -``` -++ upas :: tree change (%d) - $& [p=upas q=upas] :: cell - $% [%0 p=axis] :: copy old - [%1 p=*] :: insert new - [%2 p=axis q=udon] :: mutate! - == :: -``` - -This space intentionally left undocumented. This stuff is not known to work, -and will likely change when we get a well-typed clay. Also, this is not a -complicated type; it is not difficult to work out the meaning. diff --git a/main/pub/src/doc/sail-moveme.md b/main/pub/src/doc/sail-moveme.md new file mode 100644 index 000000000..af58fbd91 --- /dev/null +++ b/main/pub/src/doc/sail-moveme.md @@ -0,0 +1,472 @@ +Structures +========== + +The fundamental hoon structure used to generate XML is a manx. A manx is +composed of a `marx` and a `marl`, representing an XML node: + + +``` +++ manx ,[g=marx c=marl] :: XML node +++ marx ,[n=mane a=mart] :: XML tag +++ mane $|(@tas [@tas @tas]) :: XML name/space +``` + +Names, manes +------------ + +The most basic `manx` consists of an XML node name, called a `mane`, an empty +`marl`, and an empty `mart`: + +``` +~zod/try=> ;div +[[%div ~] ~] +~zod/try=> ;namespaced_div; +[[[%namespaced %div] ~] ~] +``` + +This represents an XML node, an opening and a closing tag with no attributes +nor children: + +``` +~zod/try=> (xmlt | ;div; "") +"

" +~zod/try=> (xmlt | ;namespaced_div; ~) +"" +``` + +**Note**: `++xmlt` takes three arguments: a loobean determening whether text should be +xml-escaped, the `manx` to be rendered, and a tape onto which to append the +results. ` +``` + +Tall form +========== + +Most development is done in tall form: + +``` +;html + ;head + ;title + ; Hi + == + == + ;body + ;p + ; Hello world + == + == +== +``` + +This produces the `manx`: + +``` +g=[n=%html a=~] + c + ~[ + [ g=[n=%head a=~] + c=~[[g=[n=%title a=~] c=~[[g=[n=%$ a=~[[n=%$ v="Hi +"]]] c=~]]]] + ] + [ g=[n=%body a=~] + c=~[[g=[n=%p a=~] c=~[[g=[n=%$ a=~[[n=%$ v="Hello world +"]]] c=~]]]] + ] + ] +] +``` + +When the `manx` is rendered, it produces: + +``` +Hi +

Hello world +

+``` + +As previously mentioned, a tag must always be closed. In tall form, this is accomplished by a `'=='`, which should align directly beneath it; any node in between the two is a subnnode. + +As demonstrated in the example above, the tall form for character data +is opened by `'; '` (note the space). Unlike wide form, the text that follows +the `'; '` is not wrapped in quotes, but is instead terminated with a new +line. The syntax for interpolation remains the same. + +The final way in which a tag may be closed is with `': '`, which is equivalent +to a `manx` with a single child declared by `'; '`. As with `'; '`, the text + declared by the `': '` is terminated by a new line: + +``` +;p: par contents +::

par contents

+``` + +Another syntax that is unique to tall form is`';='`, which describes a `marl` +with no tag: + +``` +!: +=- [- (xmll | - ~)] +;= + ;p: node + ;node(with "attribute"); +== +``` + +This produces the `marl`: + +``` +[[[%p ~] [[%~. [%~. "node"] ~] ~] ~] [[%node [%with "attribute"] ~] ~] ~] +``` + + +Notice how this renders two XML nodes without an outer tag: + +``` + "

node

" +``` + +Tall interpolation +------------------ + +A ';' followed by an interpolation glyph(`-, +, *, or %`) and two or more spaces, +accepts a twig and interpolates it into the surrounding structure: + +``` +;div#demo + ;- "foo" + ;+ ;p:"bar" + ;* :- ;p:"baz" + ?: & + ~ + ~[;hi;] + ;% |= a=marl + (weld a a) + ; dup +== +``` + +This produces the `manx`: + +``` +[ g=[n=%div a=~[[n=%id v="demo"]]] + c + ~[ + [g=[n=%$ a=~[[n=%$ v="foo"]]] c=~] + [g=[n=%p a=~] c=~[[g=[n=%$ a=~[[n=%$ v="bar"]]] c=~]]] + [g=[n=%p a=~] c=~[[g=[n=%$ a=~[[n=%$ v="baz"]]] c=~]]] + [g=[n=%$ a=~[[n=%$ v="dup +"]]] c=~] + [g=[n=%$ a=~[[n=%$ v="dup +"]]] c=~] + ] + ] +``` + +When the `manx` is rendered, it produces: + +``` +
foo

bar

baz

dup +dup +
+``` + +Attributes +---------- + +The tall form syntax for attributes is `'='` followed by a `mane` (the key), two +or more spaces, and a tall twig that produces a tape: + +``` +;div + =id "foo" + =class "bar" + ;p: baz` +== +``` + +This produces the `manx`: + +``` +[ g=[n=%div a=~[[n=%id v="foo"] [n=%class v="bar"]]] + c=~[[g=[n=%p a=~] c=~[[g=[n=%$ a=~[[n=%$ v="baz"]]] c=~]]]] +] +``` + +When rendered, this `manx` produces: + +``` +

baz

+``` + +The tall-form syntax can be combined with the wide-form attribute syntax (and all of its short forms): + +``` +;html + ;div#foo(tag "bar") + =attr "exceedingly value in here" + ; tall form + ;p: contents + == +== +``` + +This produces the `manx`: + +``` +[ [%html ~] + [ [%div [%id "foo"] [%tag "bar"] [%attr "hella long value in here"] ~] + [[%~. [%~. "tall form +"] ~] ~] + [[%p ~] [[%~. [%~. "contents"] ~] ~] ~] + ~ + ] + ~ +] +``` + +When rendered, this `manx` produces: + +``` +"
tall form +

contents

" +``` + + + diff --git a/main/pub/src/doc/say/arvo/app.md b/main/pub/src/doc/say/arvo/3.md similarity index 100% rename from main/pub/src/doc/say/arvo/app.md rename to main/pub/src/doc/say/arvo/3.md diff --git a/main/pub/src/doc/say/arvo/pub2.md b/main/pub/src/doc/say/arvo/4.md similarity index 100% rename from main/pub/src/doc/say/arvo/pub2.md rename to main/pub/src/doc/say/arvo/4.md diff --git a/main/pub/src/doc/say/arvo/pub3.md b/main/pub/src/doc/say/arvo/5.md similarity index 99% rename from main/pub/src/doc/say/arvo/pub3.md rename to main/pub/src/doc/say/arvo/5.md index bf8fb25be..b577e8ed5 100644 --- a/main/pub/src/doc/say/arvo/pub3.md +++ b/main/pub/src/doc/say/arvo/5.md @@ -238,7 +238,7 @@ we put: :::: /hoon/three/mad/fab/pub :: /= hello /: /===/pub/fab/mad/res/hello /hymn/ - : + :: :::: ~tasfyn-partyv :: :: diff --git a/main/pub/src/doc/say/nock/2.md b/main/pub/src/doc/say/nock/2.md index 48d6a4e39..b39658aa9 100644 --- a/main/pub/src/doc/say/nock/2.md +++ b/main/pub/src/doc/say/nock/2.md @@ -319,7 +319,7 @@ example, it'll be obvious what it is. <<33r:: *[a 7 b c] *[*[a b] c]>> *[*[a c] 2 [0 1] 0 b]] - + <<27 :: *[a 2 b c] *[*[a b] *[a c]]>> *[*[*[a c] [0 1]] *[*[a c] 0 b]] diff --git a/try/bin/poxo.hoon b/try/bin/poxo.hoon index be8f0eecd..61a25c1a2 100644 --- a/try/bin/poxo.hoon +++ b/try/bin/poxo.hoon @@ -1,4 +1,4 @@ |= ^ |= [a=manx ~] -=- ~[$/!>(-)]~ -(xmlt | a "") +=- ~[te/[-]~]~ +(crip (xmlt | a ""))