7### `++axle`, formal state
9 ++ axle :: all %ford state
10 $: %1 :: version for update
11 pol=(map ship baby) ::
14This is the formal state of our vane. Anything that must be remembered
15between calls to ford must be stored here. The number `%1` is a version
16number for our state that allows us to upgrade the structure of our
17state in the future if we wish.
19`pol` is the a map from every ship on our pier to their individual ford
20state. There is no shared ford state -- every ship is entirely separate.
22### `++baby`, state by ship
24 ++ baby :: state by ship
25 $: tad=[p=@ud q=(map ,@ud task)] :: tasks by number
26 dym=(map duct ,@ud) :: duct to task number
27 jav=(map ,* calx) :: cache
30This is the state specific to each ship.
32`tad` and `dym` keep track of the tasks we're currently working on.
33`dym` is a map from ducts to task numbers, and `q.tad` is a map from
34task number to the task itself. `p.tad` is the next available task
35number. Thus, the keys of `q.tad` are a subset of the numbers less than
36`p.tad`, and ford has attempted exactly `p.tad` tasks so far.
38`jav` is the cache of previously-solved problems. The keys are a pair of
39a term (either `%hood`, `%slap`, or `%slam`) and a noun that represents
40the exact problem solved. In the case of a `%hood`, then, the key is of
41the form `[%hood beam cage]`. For `%slap`, there is `[%slap vase twig]`.
42For `%slam`, there is `[%slam vase vase]`. The values are the result of
43solving the problem. Note that this cache is wiped in `++stay` when ford
46### `++task`, problem in progress
48 ++ task :: problem in progress
51 kig=[p=@ud q=(map ,@ud beam)] :: blocks
54This is all the state we keep regarding a particular task. `nah` is the
55duct which asked us to solve the problem, and `kas` is the most recent
56statement of the problem.
58`kig` keeps track of which resources we are blocked on. Our blocks are
59stored by index in `q.kig`, and the next available index is `p.kig`.
63 ++ silk :: construction layer
64 $& [p=silk q=silk] :: cons
65 $% [%bake p=mark q=beam r=path] :: local synthesis
66 [%boil p=mark q=beam r=path] :: general synthesis
67 [%call p=silk q=silk] :: slam
68 [%cast p=mark q=silk] :: translate
69 [%diff p=silk q=silk] :: diff
70 [%done p=(set beam) q=cage] :: literal
71 [%dude p=tank q=silk] :: error wrap
72 [%dune p=(set beam) q=(unit cage)] :: unit literal
73 [%mute p=silk q=(list (pair wing silk))] :: mutant
74 [%pact p=silk q=silk] :: patch
75 [%plan p=beam q=spur r=hood] :: structured assembly
76 [%reef ~] :: kernel reef
77 [%ride p=twig q=silk] :: silk thru twig
78 [%vale p=mark q=ship r=*] :: validate [our his]
81This is the every type of problem we can solve. Every `%exec` kiss that
82requests us to solve a problem must choose one of these problems to
85Because this is both an internal structure used in ford and the public
86interface to ford, we choose to document this structure in our
87discussion of the public interface to ford below.
89### `++calx`, cache line
91 ++ calx :: concrete cache line
92 $% [%hood p=calm q=(pair beam cage) r=hood] :: compile
93 [%slap p=calm q=[p=vase q=twig] r=vase] :: compute
94 [%slam p=calm q=[p=vase q=vase] r=vase] :: compute
97There are three kinds of cache entries. Every entry includes some
98metadata in `p` and is the combination of an input and its output.
100The input to a `%hood` is the location of the resource and a cage
101representing the data at that location. The output is the hood found by
102compiling the given cage at the given location.
104The input to a `%slap` is the vase of the subject and the twig of the
105formula against which we are slapping the subject. The output is the
106vase produced by slapping them.
108The input to a `%slam` is the vase of the subject and the vase of the
109gate which we are slapping. The output is the vase produced by slamming
112### `++calm`, cache line metadata
114 ++ calm :: cache metadata
115 $: laz=@da :: last accessed
116 dep=(set beam) :: dependencies
119Every line in the cache needs to have two pieces of metadata. We must
120know the last time this line in the cache was accessed, and we must know
121what are the dependencies of this line.
123### `++hood`, assembly components
125 ++ hood :: assembly plan
126 $: zus=@ud :: zuse kelvin
127 sur=(list hoot) :: structures
128 lib=(list hoof) :: libraries
129 fan=(list horn) :: resources
130 src=(list hoop) :: program
133When assembling a hook file, we split it into several sections.
135`zus` is the kelvin version of the required zuse. In general, we assume
136that any newer (lower-numbered) zuse will retain backward compatibility,
137so any newer zuse is also permissible. This number is set with a `/?` at
138the beginning of the file.
140`sur` is the set of structures included. These are included with the
141`/-` rune. When a structure is included, we look in `/=main=/sur` for
142the given structure and we load the gate there. When compiling, all the
143included structures are collected into a single core placed in the
144subject of the body with a `=>`.
146`lib` is the set of librarires included. These are included with the
147`/+` rune. When a library is included, we look in `/=main=/lib` for the
148given library and we load the library there. As with structures, all the
149included libraries are collected into a single core placed in the
150subject of the body with a `=>`.
152`fan` is the set of resources included. These are loaded in many
153different ways and may load resources from any location. These are
154placed in the subject of the body with a `=~`.
156`src` is the set of twigs or references to twigs in the body of the
157program. Generally, each of these will represent a core, but this is not
158required. When compiling, these are strung together in a `=~`.
162 ++ hoot (pair bean hoof) :: structure gate/core
164A structures may be either a direct gate or a core. These are
165syntactically distinguished by adding a `*` to the beginning of the
166structure name for a core. The structure itself is a `hoof`.
170 ++ hoof (pair term (unit (pair case ship))) :: resource reference
172A hoof, which is either a structure or a library, has a name, and it may
173also specify which version of the resource to use and which ship to
178 ++ horn :: resource tree
179 $% [%ape p=twig] :: /~ twig by hand
180 [%arg p=twig] :: /$ argument
181 [%day p=horn] :: /| list by @dr
182 [%dub p=term q=horn] :: /= apply face
183 [%fan p=(list horn)] :: /. list
184 [%for p=path q=horn] :: /, descend
185 [%hub p=horn] :: /@ list by @ud
186 [%man p=(map span horn)] :: /* hetero map
187 [%nap p=horn] :: /% homo map
188 [%now p=horn] :: /& list by @da
189 [%saw p=twig q=horn] :: /; operate on
190 [%see p=beam q=horn] :: /: relative to
191 [%sic p=tile q=horn] :: /^ cast
192 [%toy p=mark] :: /mark/ static
195This is how we represent the static resources hook files can load. The
196discussion of their use from a user's perspective is documented
197elsewhere (link), so we will here only give a description of the data
200A `%ape` horn is simply a twig that gets evaluated and placed in the
203A `%arg` is a gate that gets evaluated with a sample of our location and
206A `%day` is a horn that applies to each of a list of `@dr`-named files
209A `%dub` is a term and horn, where the result of a horn is given the
212A `%fan` is a list of horns, all at the current directory level.
214A `%for` is a path and a horn, where the horn is evaluated relative to
215the given path, where the given path is relative to the current
218A `%hub` is a horn that applies to each of a list of `@ud`-named files
221A `%man` is a map of spans to horns where the result is a set of each
222horn applied to the current directory given the associated face.
224A `%nap` is a homogenous map where each entry in a directory is handled
225with the same horn and is given a face according to its name.
227A `%now` is a horn that applies to each of a list of `@da`-named files
230A `%saw` is a twig and a horn, where the twig operates on the result of
233A `%see` is a beam and a horn, where the horn is evaluated at a location
236A `%sic` is a tile and a horn, where the horn is evaluated and cast to
237the type associated with the tile.
239A `%toy` is simply a mark to be baked.
243 ++ hoop :: source in hood
244 $% [%& p=twig] :: direct twig
245 [%| p=beam] :: resource location
248This is an entry in the body of the hook file. The hoop can either be
249defined directly in the given file or it can be a reference to another
250file. The second is specified with a `//` rune.
252### `++bolt`, monadic edge
254 ++ bolt :: gonadic edge
255 |* a=$+(* *) :: product clam
258 $% [%0 p=(set beam) q=a] :: depends/product
259 [%1 p=(set ,[p=beam q=(list tank)])] :: blocks
260 [%2 p=(list tank)] :: error
264Throughout our computation, we let our result flow through with the set
265of dependencies of the value. At various times, we may wish to either
266throw an error or declare that the actual result cannot be found until a
267particular resource is retrieved. This is a perfect case for a monad, so
268here we define a data structure for it.
270At every step, we have a cache, so we store that in `p`. In `q` we store
273In the case of `%0`, we have the result in `q` and the set of
276In the case of `%1`, we have a set of dependencies on which we are
277blocking. When this happens, we make a call to clay to get the
278dependencies, and we proceed with the computation when we receive them.
279Technically, we restart the computation, but since every expensive step
280is cached, there is no significant performance penalty to doing this.
281Referential transparency has its uses.
283In the case of `%2`, we have a hit an error. This gets passed all the
284way through to the calling duct. The list of tanks is some description
285of what went wrong, often including a stack trace.
287### `++burg`, monadic rule
289 ++ burg :: gonadic rule
290 |* [a=$+(* *) b=$+(* *)] :: from and to
291 $+([c=cafe d=a] (bolt b)) ::
294To operate on bolts, we use `++cope` as our bind operator, and the
295functions it works on are of type `burg`. Our functions that operate on
296bolts should have a sample of the cache and a value. Their output should
297be a bolt of the output value. Then, `++cope` will only call the
298function when necessary (in the `%0` case), and it will do so without
299the wrapping of a bolt.
301If you understand monads, this is probably fairly obvious. Otherwise,
302see the discussion on `++cope` (link).
307Ford does not export a scry interface, so the only way to interact with
308ford is by sending kisses and receiving gifts. In fact, ford only sends
309accepts one kiss and gives one gift. This is, of course, misleading
310because ford actually does many different things. It does, however, only
311produce one type of thing -- a result of a computation, which is either
312an error or the value produced along with the set of dependencies
315 ++ kiss :: in request ->$
316 $% [%exec p=@p q=(unit silk)] :: make / kill
319The `%exec` gift requests ford to perform a computation on behalf of a
320particular ship. `p` is the ship, and `q` is the computation. If `q` is
321null, then we are requesting that ford cancel the computation that it is
322currently being run along this duct. Thus, if you wish to cancel a
323computation, you must send the kiss along the same duct as the original
326Otherwise, we ask ford to perform a certain computation, as defined in
327`++silk`. Since all computations produce the same type of result, we
328will discuss that result before we jump into `++silk`.
330 ++ gift :: out result <-$
331 $% [%made p=(each bead (list tank))] :: computed result
334We give either a `bead`, which is a result, or a list of tanks, which is
335an error messge, often including a stack trace.
337 ++ bead ,[p=(set beam) q=cage] :: computed result
339This is a set of dependencies required to compute this value and a cage
340of the result with its associated mark.
342There are twelve possible computations defined in `++silk`.
344 ++ silk :: construction layer
345 $& [p=silk q=silk] :: cons
346 $% [%bake p=mark q=beam r=path] :: local synthesis
347 [%boil p=mark q=beam r=path] :: general synthesis
348 [%call p=silk q=silk] :: slam
349 [%cast p=mark q=silk] :: translate
350 [%done p=(set beam) q=cage] :: literal
351 [%dude p=tank q=silk] :: error wrap
352 [%dune p=(set beam) q=(unit cage)] :: unit literal
353 [%mute p=silk q=(list (pair wing silk))] :: mutant
354 [%plan p=beam q=spur r=hood] :: structured assembly
355 [%reef ~] :: kernel reef
356 [%ride p=twig q=silk] :: silk thru twig
357 [%vale p=mark q=ship r=*] :: validate [our his]
360First, we allow silks to autocons. A cell of silks is also a silk, and
361the product vase is a cell of the two silks. This obviously extends to
362an arbitrary number of silks.
364`%bake` tries to functionally produce the file at a given beam with the
365given mark and heel. It fails if there is no way to translate at this
368`%boil` functionally produces the file at a given beam with the given
369mark and heel. If there is no way to translate at this beam, we pop
370levels off the stack and attempt to bake there until we find a level we
371can bake. This should almost always be called instead of `%bake`.
373`%call` slams the result of one silk against the result of another.
375`%cast` translates the given silk to the given mark, if possible. This
376is one of the critical and fundamental operations of ford.
378`%done` produces exactly its input. This is rarely used on its own, but
379many silks are recursively defined in terms of other silks, so we often
380need a silk that simply produces its input. A monadic return, if you
383`%diff` diffs the two given silks (which must be of the same mark),
384producing a cage of the mark specified in `++mark` in `++grad` for the
385mark of the two silks.
387`%dude` computes the given silk with the given tank as part of the stack
388trace if there is an error.
390`%dune` produces an error if the cage is empty. Otherwise, it produces
391the value in the unit.
393`%mute` takes a silk and a list of changes to make to the silk. At each
394wing in the list we put the value of the associated silk.
396`%pact` applies the second silk as a patch to the first silk. The second
397silk must be of the mark specified in `++mark` in `++grad` for the mark
400`%plan` performs a structured assembly directly. This is not generally
401directly useful because several other silks perform supersets of this
402functionality. We don't usually have naked hoods outside ford.
404`%reef` produces a core containing the entirety of zuse and hoon,
405suitable for running arbitrary code against. The mark is `%noun`.
407`%ride` slaps a twig against a subject silk. The mark of the result is
410`%vale` validates untyped data from a ship against a given mark. This is
411an extremely useful function.
419In the commentary on other vanes, we have traced through the lifecycle
420of various external requests. This is generally a very reasonable order
421to examine vanes since it will eventually cover the entire vane, and we
422are never left wondering why we are doing something.
424For ford, however, it makes more sense to begin by discussing the
425parsing and assembliing of hook files. Many of the possible requests
426require us to assemble hook files, so we may as well examine this
429First, we will examine the parsing. We parse a file at a beam to a hood
430in `++fade:zo:za`. The top-level parsing rule is `++fair`, which takes a
431beam and produces a rule to parse an entire hood file.
433A note on the naming scheme: the parsing the combinators that parse into
434a particular structure are conventionally given the same name as the
435structure. Although this locally clobbers the type names, this pattern
436makes obvious the intent of the parsing combinators.
438We kick off with `++hood:fair`.
444 (ifix [;~(plug fas wut gap) gap] dem)
449 (ifix [;~(plug fas hep gap) gap] (most ;~(plug com gaw) hoot))
454 (ifix [;~(plug fas lus gap) gap] (most ;~(plug com gaw) hoof))
458 (star ;~(sfix horn gap))
462There are five sections to a hood: system version, structures,
463libraries, resources, and body.
465First, we parse the requested version number of the system. This is
466specified with a unary `/?` rune. If not present, then we default to the
469Second, we may have zero or more `/-` runes followed by a parsing of a
470`++hoot`, which represents a shared structure.
472Third, we may have zero or more `/+` runes followed by a parsing of a
473`++hoof`, which represents a shared library.
475Fourth, we may have zero or more other `/` runes (as described in
476`++horn`), which represent program-specific resources to be loaded.
478Fifth and finally, we must have one or more body statements (hoops),
479which are either direct twigs or `//` runes.
483 (stag %| ;~(pfix tar hoof))
487A structure can either be a direct gate, or it can be a simple core.
488Either one is parsed with `++hoof`, so we distinguish the two cases by
489requireing core references to be prefixed by a `*`.
492 %+ cook |=(a=^hoof a)
497 ;~(plug ;~(pfix fas case) ;~(pfix ;~(plug fas sig) fed:ag))
502A hoof must have a name, which is a term. Optionally, we also include a
503case and a ship. This is marked by appending a `/` followed by a case to
504denote the requested version of the resource and a `/` followed by a
505ship name to denote the requested source of the resource. For example,
506`resource/1/~zod` requests the first version of `resource` on `~zod`.
512 ?. ?=([%$ ?(%da %ud %tas) *] a) ~
515Here, we parse a literal with `++nuck:so`, and we accept the input if it
516is either an absolute date, an unsigned decimal, or a label.
518This leaves only horns and hoops to parse. Hoops are much simple to
519parse, so we'll discuss those first.
523 (stag %| ;~(pfix ;~(plug fas fas gap) have))
527There are two types of hoops. Direct twigs are parsed with
528`++tall:vast`, which is the just the hoon parser for a tall-form twig.
530References to external twigs are marked with a `//` rune followed by a
531beam, which is parsed with `++have`.
533 ++ hath (sear plex:voz (stag %clsg poor:voz)) :: hood path
534 ++ have (sear tome ;~(pfix fas hath)) :: hood beam
536`++have` parses a path with `++hath`, and then it converts the path into
539`++hath` parses a `/`-separated list with `++poor:vast`, then converts
540it to an actual path with `++plex:vast`.
542This leaves only horns to parse.
552 (stag %toy ;~(sfix sym fas))
553 (stag %ape ;~(pfix sig ape:read))
554 (stag %arg ;~(pfix buc ape:read))
555 (stag %day ;~(pfix bar day:read))
556 (stag %dub ;~(pfix tis dub:read))
557 (stag %fan ;~(pfix dot fan:read))
558 (stag %for ;~(pfix com for:read))
559 (stag %hub ;~(pfix pat day:read))
560 (stag %man ;~(pfix tar man:read))
561 (stag %nap ;~(pfix cen day:read))
562 (stag %now ;~(pfix pam day:read))
563 (stag %saw ;~(pfix sem saw:read))
564 (stag %see ;~(pfix col see:read))
565 (stag %sic ;~(pfix ket sic:read))
569Horn parsing is slightly complex, so we create an internal core to
570organize our code. Our core has a global variable of `tol`, which is
571true if tall form is permissible and false if we're already in wide
572form. We kick off the parsing with `++apex`.
574`++apex` specifies how each rune is parsed. This allows us to offload
575the different ways of parsing the arguments to these runes into separate
576arms. The exception here is that the `%toy` horn is simply of the form
579We'll examine each of the horn parsing arms right after we discuss
580`++rail`, which is used in each one.
583 |* [wid=_rule tal=_rule]
587This takes a wide-form and a tall-form parsing rule. If tall form is
588permissible, then it allows either rule to match; else, it allows only
594 (ifix [sel ser] (stag %cltr (most ace wide:vez)))
595 ;~(pfix gap tall:vez)
597`++ape:read` parses for both the `/~` and the `/$` runes. It produces a
598twig. The wide form is a tuple of one or more ace-separated wide-form
599twigs parsed with `++wide:vast` and surrounded by `[` and `]`. The tall
600form is a single tall form twig parsed by `++tall:vast`
607This parses for the `/|`, `/@`, `/%`, and `/&` runes. It produces a
608horn. The wide form is, recursively, the entire horn parser with tall
609form disabled. The tall form is a gap followed by, recursively, the
614 ;~(plug sym ;~(pfix tis apex(tol |)))
615 ;~(pfix gap ;~(plug sym ;~(pfix gap apex)))
617This parses for the `/=` rune. It produces a term followed by a horn.
618The wide form is a symbol name followed by a `=` and, recursively, the
619entire horn parser with tall form disabled. The tall form is a gap
620followed by a symbol name, another gap, and, recursively, the entire
625 ;~(sfix (star ;~(pfix gap apex)) ;~(plug gap duz))
627This parses for the `/.` rune. It produces a list of horns. There is no
628wide form. The tall form is a stet-terminated series of gap-separated
629recursive calls to the entire horn parser.
633 ;~(plug (ifix [sel ser] hath) apex(tol |))
634 ;~(pfix gap ;~(plug hath ;~(pfix gap apex)))
636This parses for the `/,` rune. It produces a path and a horn. The wide
637form is a `[`-`]`-surrounded path followed by, recursively, the entire
638horn parser with tall form disabled. The tall form is a gap followed by
639a path, another gap, and, recursively, the entire horn parser.
644 :_ ;~(sfix (star ;~(pfix gap apex)) ;~(plug gap duz))
646 =| naf=(list (pair term ^horn))
647 |- ^- (unit (map term ^horn))
648 ?~ fan (some (~(gas by *(map term ^horn)) naf))
649 ?. ?=(%dub -.i.fan) ~
650 $(fan t.fan, naf [[p.i.fan q.i.fan] naf])
652This parses for the `/*` rune. It produces a map of spans to horns.
653There is no wide form. The tall form is a stet-terminated series of
654gap-separated recursive calls to the entire horn parser. All produced
655horns are expected to be from `/=` runes. The term and horn in each `/=`
656horn is inserted into the produced map as a key-value pair.
660 ;~(plug ;~(sfix wide:vez sem) apex(tol |))
661 ;~(pfix gap ;~(plug tall:vez ;~(pfix gap apex)))
663This parses for the `/;` rune. It produces a twig and a horn. The wide
664form is a wide-form twig followed by a `;` and, recursively, the entire
665horn parser with tall form disabled. The tall form is a gap followed by
666a tall-form twig, another gap, and, recursively, the entire horn parser.
670 ;~(plug ;~(sfix have col) apex(tol |))
671 ;~(pfix gap ;~(plug have ;~(pfix gap apex)))
673This parses for the `/:` rune. It produces a beam and a horn. The wide
674form is a beam followed by a `;` and, recursively, the entire horn
675parser with tall form disabled. The tall form is a gap followed by a
676beam, another gap, and, recursively, the entire horn parser.
680 ;~(plug ;~(sfix toil:vez ket) apex(tol |))
681 ;~(pfix gap ;~(plug howl:vez ;~(pfix gap apex)))
684This parses for the `/^` rune. It produces a tile and a horn. The wide
685form is a wide-form tile, parsed with `++toil:vast`, followed by a `^`
686and, recursively, the entire horn parser with tall form disabled. The
687tall form is a gap followed by a tall-form tile, parsed with
688`++howl:vast`, another gap, and, recursively, the entire horn parser.
693At this point, we've parsed a hook file into a hood. We will now
694describe exactly how this hood is assembled into a vase. The problem of
695assembling is handled entirely within the `++meow:zo:za` core.
698 |= [how=beam arg=heel]
699 =| $: rop=(map term (pair hoof twig)) :: structure/complex
700 zog=(set term) :: structure guard
701 bil=(map term (pair hoof twig)) :: libraries known
702 lot=(list term) :: library stack
703 zeg=(set term) :: library guard
704 boy=(list twig) :: body stack
705 hol=? :: horns allowed?
709We take two arguments and keep seven pieces of state. `how` is the
710location of the hook file we're assembling, and `arg` is the heel, or
711virtual path extension, of the file.
713In `rop`, we maintain a map of terms to pairs of hooves and twigs to
714represent the structures we've encountered that we will put together in
715a core at the top of the file.
717In `zog`, we maintain the set of structures we're in the middle of
718loading. If we try to load a structure already in our dependency
719ancestry, then we fail because we do not allow circular dependencies.
720This enforces that our structure dependency graph is a DAG.
722In `bil`, we maintain a map of terms to pairs of hooves and twigs to
723represent the libraries we've encountered that we will put together in a
724series of cores after the structure core.
726In `lot`, we maintain a stack of library names as they are encountered
727during a depth-first search. More precisely, we push a library onto the
728stack after we've processed all its children. Thus, every library
729depends only on things deeper in the list. The libraries must be loaded
730in the reverse of this order. Concisely, this is a topological sort of
731the library dependency partial ordering.
733In `zeg`, we maintain the set of libraries we're in the middle of
734loading. If we try to load a library already in our dependency ancestry,
735then we fail because we do not allow circular dependencies. This
736enforces that our library dependency graph is a DAG.
738In `boy`, we maintain a stack of body twigs, which we'll put together in
739a series of cores at the end of the file.
741In `hol`, we decide if we're allowed to contain horns. Libraries and
742structures are not allowed to contain horns.
744We in every case enter `++meow` through `++abut`. You'll notice that
745there are four (count 'em, four!) calls to `++cope` in `++abut`. If
746you've glanced at the ford code in general, you've probably seen cope
747over and over. It is called in 79 different places. We need to discuss
748the use of this critical function in detail, so we may as well do it
751 ++ cope :: bolt along
752 |* [hoc=(bolt) fun=(burg)]
756 %0 =+ nuf=(fun p.hoc q.q.hoc)
762 %0 [%0 p=(grom `_p.q.nuf`p.q.hoc p.q.nuf) q=q.q.nuf]
765In monad-speak, this is the bind operator for the bolt monad. If monads
766aren't your thing, don't worry, we're going to explain the use of cope
767without further reference to them.
769Recall that there are three different types of bolt. A `%2` error bolt
770contains a list of tanks describing the error, a `%1` block bolt
771contains a set of resources we're blocked on, and a `%0` value bolt
772contains an actual value and the set of its dependencies.
774We most commonly want to perform an operation on the value in a bolt if
775it is a `%0` bolt. If it's not a `%0` bolt, we want to leave it alone.
776This requires us to write a certain amount of boilerplate between each
777of our operations to see if any of them produced a `%1` or a `%2` bolt.
778This gets tiresome, so we pull it out into a separate arm and call it
781Intuitively, we're calling the function `fun` with the value in `hoc`,
782where `fun` takes an argument of type whatever is the value in a `%0`
783case of `hoc`, and it produces a bolt of some (possibly different) type.
784For brevity, we will refer to the type of the of the value in the `%0`
785case of a bolt as the "type of the bolt".
787If the `hoc` bolt we're given as input to `fun` is already a `%1` or a
788`%2` bolt, then we simply produce that. We don't even try to run `fun`
791Otherwise, we run `fun` with the arguments from the bolt and, if it
792produces a `%1` or a `%2` bolt, we simply produce that. If it produces a
793`%0` bolt, then we produce that with the old set of dependencies merged
796We'll see more about how the bolt monad works as we run into more
797interesting uses of it. For now, this is sufficient to move on with
801 |= [cof=cafe hyd=hood]
803 %+ cope (apex cof hyd)
804 |= [cof=cafe sel=_..abut]
806 %+ cope (maim cof pit able)
807 |= [cof=cafe bax=vase]
808 %+ cope (chap cof bax [%fan fan.hyd])
809 |= [cof=cafe gox=vase]
810 %+ cope (maim cof (slop gox bax) [%tssg (flop boy)])
811 |= [cof=cafe fin=vase]
814Our job is simple: we must assemble a hood file into a vase. Hopefully,
815the usage of `++cope` is fairly understandable. The correct way to read
816this is that it does essentially five things.
818First, we call `++apex` to process the structures, libraries, and body.
819This changes our state, so we set our context to the produced context.
820Second, we call `++able` to assemble the strucutres and libraries into a
821twig, which we slap against zuse with `++maim`. Third, we call `++chap`
822to process the resources in the context of the already-loaded structures
823and libraries. Fourth, we slap the body against the structures,
824libraries, and resources. Fifth and finally, we produce the resultant
827 ++ apex :: build to body
828 |= [cof=cafe hyd=hood]
830 ?. |(hol ?=(~ fan.hyd))
831 %+ flaw cof :_ ~ :- %leaf
832 "horns not allowed in structures and libraries: {<[how arg]>}"
833 %+ cope (body cof src.hyd)
834 |= [cof=cafe sel=_..apex]
836 %+ cope (neck cof lib.hyd)
837 |= [cof=cafe sel=_..apex]
838 =. ..apex sel(boy boy)
839 %+ cope (head cof sur.hyd)
840 |= [cof=cafe sel=_..apex]
843First, we make sure that if we're not allowed to have horns, we don't.
844Otherwise, we produce and error with `++flaw`.
846 ++ flaw |=([a=cafe b=(list tank)] [p=a q=[%2 p=b]]) :: bolt from error
848This produces a `%2` error bolt from a list of tanks. Fairly trivial.
850We should be starting to get used to the cope syntax, so we can see that
851we really only do three things here. We process the body with `++body`,
852the libraries with `++neck`, and the structures with `++head`.
854 ++ body :: produce functions
855 |= [cof=cafe src=(list hoop)]
857 ?~ src (fine cof ..body)
858 %+ cope (wilt cof i.src)
859 |= [cof=cafe sel=_..body]
860 ^$(cof cof, src t.src, ..body sel)
862We must process a list of hoops that represent our body. If there are no
863more hoops, we just produce our context in a `%0` bolt with `++fine`.
865 ++ fine |* [a=cafe b=*] :: bolt from data
866 [p=`cafe`a q=[%0 p=*(set beam) q=b]] ::
868In monad-speak, this is the return operator. For us, this just means
869that we're producing a `%0` bolt, which contains a path and a set of
870dependencies. We assume there are no dependencies for the given data, or
871that they will be added later.
873If there are more hoops in `++body`, we call `++wilt` to process an
874individual hoop and recurse.
876 ++ wilt :: process body entry
877 |= [cof=cafe hop=hoop]
880 %& (fine cof ..wilt(boy [p.hop boy]))
882 %+ cool |.(leaf/"ford: wilt {<[(tope p.hop)]>}")
883 %+ cope (lend cof p.hop)
884 |= [cof=cafe arc=arch]
885 ?: (~(has by r.arc) %hoon)
886 %+ cope (fade cof %hoon p.hop)
887 |= [cof=cafe hyd=hood]
888 %+ cope (apex(boy ~) cof hyd)
889 |= [cof=cafe sel=_..wilt]
890 (fine cof sel(boy [[%tssg boy.sel] boy]))
891 =+ [all=(lark (slat %tas) arc) sel=..wilt]
893 |- ^- (bolt (pair (map term foot) _..wilt))
894 ?~ all (fine cof ~ ..wilt)
896 |= [cof=cafe lef=(map term foot) sel=_..wilt]
897 %+ cope ^$(all r.all, cof cof, sel sel)
898 |= [cof=cafe rig=(map term foot) sel=_..wilt]
903 s.p.hop [p.n.all s.p.hop]
905 |= [cof=cafe sel=_..wilt]
907 [`(map term foot)`[[p.n.all [%ash [%tssg boy.sel]]] lef rig] sel]
908 |= [cof=cafe mav=(map term foot) sel=_..wilt]
910 (flaw cof [%leaf "source missing: {<(tope p.hop)>}"]~)
911 (fine cof sel(boy [[%brcn mav] boy]))
914In the case of a direct twig hoop, we just push it onto `boy` and we're
915done. In the case of an indirect hoop, we must compile the referenced
918First, we push onto the stack trace a message indicating which file
919exactly we're compiling at the moment with `++cool`.
921 ++ cool :: error caption
922 |* [cyt=trap hoc=(bolt)]
923 ?. ?=(%2 -.q.hoc) hoc
924 [p.hoc [%2 *cyt p.q.hoc]]
926If an error occurred in computing `hoc`, we put the bunt of `cyt` onto
927the stack trace. Thus, `cyt` is not evaluated at all unless an error
930Next in `++wilt`, we load the information about the filesystem node
931referenced by the hoop with `++lend`.
934 |= [cof=cafe bem=beam]
936 =+ von=(ska %cy (tope bem))
937 ?~ von [p=cof q=[%1 [bem ~] ~ ~]]
938 (fine cof ((hard arch) (need u.von)))
940This is a simple call to the namespace. If the resource does not yet
941exist, we block on it by producing a `%1` bolt. Otherwise, we cast it to
942an arch and produce this.
944Continuing in `++wilt`, we examine the produced arch. If the referenced
945filesystem node has a `hoon` child node, then we've found the required
946source, so we parse it with `++fade`. Recall that we referred earlier to
947`++fade`. The salient point there is that it takes a beam, reads in the
948hook file there, and parses it into a hood file with `++fair`.
950Now, we simply recurse on `++apex` to compile the new hood. Note that,
951while we do clear the `boy` list, we do not clear the other lists. Thus,
952we are accumulating all the structures and libraries referenced in all
953the referenced hook files in one group, which we will put at the top of
956After this, we put the new list of body twigs into a `=~`, push this
957onto our old list of body twigs, and produce the result.
959If there is no hoon file here, then we descend into each of our children
960until we find a hoon file. First, we produce a list of all our children
961whose names are terms with `++lark`.
963 ++ lark :: filter arch names
964 |= [wox=$+(span (unit ,@)) arc=arch]
966 %- ~(gas by *(map ,@ span))
967 =| rac=(list (pair ,@ span))
970 =. rac $(r.arc l.r.arc, rac $(r.arc r.r.arc))
971 =+ gib=(wox p.n.r.arc)
972 ?~(gib rac [[u.gib p.n.r.arc] rac])
974We traverse the children map of `arc` to filter out those children whose
975names aren't accepted by `wox` and produce a map from the product of
976`wox` to the original name. `++lark` is used in many cases to parse
977names into other types, like numbers or dates, ignoring those which do
978not fit the format. In `++wilt`, though, we simply want to filter out
979those children whose names are not terms.
981Next, we will produce a map from terms to feet. Each of these feet will
982be placed in a core named by the child name, and it will contain arms
983according to its children. Thus, if the indirect hoop references
984`/path`, then to access the twig defined in `/path/to/twig/hoon`, our
985body must refer to `twig:to`.
987If there are no more children, then we are done, so we produce our
990Else, we recurse into the left and right sides of our map. Finally, we
991process our current entry in the map. We first recurse by calling
992`++wilt` one level down. Thus, in the previous example, the first time
993we get to this point we are processing `/path`, so we recurse on
994`++wilt` with path `/path/to`. We also remove our current body from the
995recursion, so that we may add it back in later the way we want to.
997After recursing, we push the new body onto our map, keyed by its name.
998We also produce the new context so that all external structures,
999libraries, and resources are collected into the same place.
1001Finally, we have a map of names to feet. If this map is empty, then
1002there were no twigs at the requested path, so we give an error with
1005If the map is nonempty, then we finally produce our context with with
1006one thing pushed onto the front: a core made out of the map we just
1009This concludes our discussion of `++wilt` and `++body`. Thus, it remains
1010in `++apex` to discuss `++neck` and `++head`.
1012 ++ neck :: consume libraries
1013 |= [cof=cafe bir=(list hoof)]
1015 ?~ bir (fine cof ..neck)
1016 ?: (~(has in zeg) p.i.bir)
1017 (flaw cof [%leaf "circular library dependency: {<i.bir>}"]~)
1018 =+ gez=(~(put in zeg) p.i.bir)
1019 =+ byf=(~(get by bil) p.i.bir)
1021 ?. =(`hoof`i.bir `hoof`p.u.byf)
1022 (flaw cof [%leaf "library mismatch: {<~[p.u.byf i.bir]>}"]~)
1024 =+ bem=(hone %core %lib i.bir)
1025 %+ cope (fade cof %hook bem)
1026 |= [cof=cafe hyd=hood]
1027 %+ cope (apex(zeg gez, hol |, boy ~) cof hyd)
1028 |= [cof=cafe sel=_..neck]
1034 bil (~(put by bil) p.i.bir [i.bir [%tssg (flop boy.sel)]])
1036 ^^$(cof cof, bir t.bir)
1038Here, we're going to consume the list of libraries and place them in
1039`bil`. If there are no more libraries, we're done, so we just produce
1042Otherwise, we check to see if the next library in the list is in `zeg`.
1043If so, then this library is one of the libraries that we're already in
1044the middle of compiling. There is a circular dependency, so we fail.
1046Otherwise, we let `gez` be `zeg` plus the current library so that while
1047compiling the dependencies of this library we don't later create a
1048circular dependency. We check next to see if this library is alredy in
1049`bil`. If so, then we have already included this library earlier, so we
1050check to see if this is the same version of the library as we included
1051earlier. If so, we skip it. Else, we fail since we can't include two
1052different versions of a library. We really should allow for newer
1053versions of a library since in kelvin versioning we assume backwards
1054compatibility, but for now we require an exact match.
1056If we haven't already included this library, then we're going to do
1057that. First, we get the location of the library with `++hone`.
1059 ++ hone :: plant hoof
1060 |= [for=@tas way=@tas huf=hoof]
1063 how(s ~[for p.huf way])
1064 [[q.u.q.huf %main p.u.q.huf] ~[for p.huf way]]
1066If we haven't specified the version of the library, we use the current
1067ship, desk, and case. Otherwise, we use the given ship and case on desk
1068`%main`. In either case, the path is `/way/p.huf/for`. In the case of
1069`++neck`, this means `/lib/core/[library name]`.
1071In `++neck`, we next compile the hook file at that location with
1072`++fade`. Again, we will delay the discussion of `++fade`, noting only
1073that it takes a beam and parses the hook file there into a hood.
1075We recurse on this to compile the library. During the compilation, we
1076let `zeg` be `gez` to avoid circular dependencies, we let `hol` be false
1077since we don't allow horns in libraries, and we let `boy` be null so
1078that we can isolate the new body twigs.
1080Next, we reintegrate the new data into our context. We use the context
1081created by the recursion with four changes. First, we reset `zeg` to our
1082old `zeg`. Second, we reset `hol` to our old `hol`. Third, we put the
1083name of our library onto the stack of libraries. This means all of a
1084libraries dependencies will be earlier in `lot` than the library itself,
1085making `lot` a topological ordering on the dependency graph. Fourth, we
1086put in `bil` the library hoof and body (with all body twigs collected in
1087a `=~`), keyed by the library name.
1089Finally, we recurse, processing the next library in our list.
1091To complete our disucssion of `++apex`, we must process our structures.
1093 ++ head :: consume structures
1094 |= [cof=cafe bir=(list hoot)]
1095 |- ^- (bolt ,_..head)
1098 ?: (~(has in zog) p.q.i.bir)
1099 (flaw cof [%leaf "circular structure dependency: {<i.bir>}"]~)
1100 =+ goz=(~(put in zog) p.q.i.bir)
1101 =+ byf=(~(get by rop) p.q.i.bir)
1103 ?. =(`hoof`q.i.bir `hoof`p.u.byf)
1104 (flaw cof [%leaf "structure mismatch: {<~[p.u.byf q.i.bir]>}"]~)
1106 =+ bem=(hone ?:(p.i.bir %gate %core) %sur q.i.bir)
1107 %+ cope (fade cof %hook bem)
1108 |= [cof=cafe hyd=hood]
1109 %+ cope (apex(zog goz, hol |, boy ~) cof hyd)
1110 |= [cof=cafe sel=_..head]
1112 (flaw cof [%leaf "structures cannot include libraries: {<i.bir>}"]~)
1117 (welp boy [[[%cnzy p.q.i.bir] [%$ 1]] ~])
1120 rop %+ ~(put by (~(uni by rop) rop.sel))
1122 [q.i.bir [%tssg (flop boy.sel)]]
1124 ^^$(cof cof, bir t.bir)
1126The processing of our structures is very similar to that of our
1127libraries. For clarity, we'll use many of the same phrases in describing
1128the parallel natures. First, we check to see if there are more
1129structures to process. If not, we're done, so we produce our context.
1131Otherwise, we let `goz` be `zog` plus the current structure so that
1132while compiling the dependencies of this structure we don't later create
1133a circular dependency. We check next to see if this structure is alredy
1134in `rop`. If so, then we have already included this structure earlier,
1135so we check to see if this is the same version of the structure as we
1136included earlier. If so, we skip it. Else, we fail since we can't
1137include two different versions of a structure.
1139If we haven't loaded this structure, then we call `++hone` to get the
1140beam where the file structure should be. If the loobean in the hoot is
1141true, then we're looking for a gate; otherwise, we're looking for a
1142core. We parse this file with `++fade`.
1144Now, we recurse on this to compile the structure. During the recursion,
1145there we have threee changes. Frist, we let `zog` be `goz` so that we
1146don't create a circular dependency. Second, we let `hol` be false since
1147we do not allow horns in structures. Third, we let `boy` be null so that
1148we can isolate the new body twigs.
1150Next, we reintegrate the new data into our context. We use the context
1151cretaed by the recursion with four changes. First, if we're including a
1152gate structure, then we reset the body to its original body. Else we put
1153on the top of our list of body twigs what is essentially a
1154`=+ structure-name` to take off the face of the structure. Second, we
1155reset `zog` to our old `zog`. Third, we reset `hol` to our old `hol`.
1156Finally, we put in `rop` the structure hoof and body (with all body
1157twiggs collected in a `=~`), keyed by the structure name.
1159Finally, we recurse, processing the next structure in our list.
1161This concludes our discussion of `++apex`.
1164 |= [cof=cafe hyd=hood]
1166 %+ cope (apex cof hyd)
1167 |= [cof=cafe sel=_..abut]
1169 %+ cope (maim cof pit able)
1170 |= [cof=cafe bax=vase]
1171 %+ cope (chap cof bax [%fan fan.hyd])
1172 |= [cof=cafe gox=vase]
1173 %+ cope (maim cof (slop gox bax) [%tssg (flop boy)])
1174 |= [cof=cafe fin=vase]
1177Returning to `++abut`, we have now processed the structures, libraries
1178and body twigs. Next, we slap our preamble (structures and libraries)
1179against zuse. First, we construct our preamble in `++able`.
1181 ++ able :: assemble preamble
1184 ?:(=(~ rop) [%$ 1] [%brcn (~(run by rop) |=([* a=twig] [%ash a]))])
1185 [%tssg (turn (flop lot) |=(a=term q:(need (~(get by bil) a))))]
1187We first put the structures in `rop` into a single `|%` at the top and
1188`=>` it onto a `=~` of our libraries, in the reverse order that they
1189appear in `lot`. Thus, the structures are in a single core while the
1190libraries are in consecutive cores.
1192We slap the preamble against zuse with `++maim`.
1195 |= [cof=cafe vax=vase gen=twig]
1197 %+ (clef %slap) (fine cof vax gen)
1198 |= [cof=cafe vax=vase gen=twig]
1199 =+ puz=(mule |.((~(mint ut p.vax) [%noun gen])))
1202 & %+ (coup cof) (mock [q.vax q.p.puz] (mole ska))
1207Here we start to get into ford's caching system. We wrap our computation
1208in a call to `++clef` so that we only actually compute it if the result
1209is not already in our cache. First we'll discuss the computation, then
1210we'll discuss the caching system.
1212We call `++mule` with a call to `++mint:ut` on the type of our subject
1213vase against the given twig. In other words, we're compiling the twig
1214with against the subject type in the given subject vase.
1216If compilation fails, then we produce an error bolt with the produced
1217stack trace. Otherwise, we run the produced nock with `++mock` and our
1218sky function. We convert the produced toon to a bolt with `++coup` and
1219use the type from `puz` combined with the value from `mock` to produce
1222If this process seems harder than just calling `++slap`, it's because it
1223is. We have two requirements that `++slap` doesn't satisfy. First, we
1224want the to use an explicit sky function for use with `.^`. With
1225`++slap`, you get whatever sky function is available in the calling
1226context, which in ford is none. Second, we want to explicitly handle the
1227stack trace on failure. `++slap` would cause crash on failure.
1229We haven't yet discussed either `++clef` or `++coup`. We'll start with
1230`++coup` to finish the discussion of the computation.
1232\``++ coup :: toon to bolt |= cof=cafe |* [ton=toon fun=$+(* *)] :- p=cof ^= q ?- -.ton %2 [%2 p=p.ton] %0 [%0 p=*(set beam) q=(fun p.ton)] %1 ~& [%coup-need ((list path) p.ton)] =- ?- -.faw & [%1 p=(sa (turn p.faw |=(a=beam [a *(list tank)])))] | [%2 p=p.faw] == ^= faw |- ^- (each (list beam) (list tank)) ?~ p.ton [%& ~] =+ nex=$(p.ton t.p.ton) =+ pax=(path i.p.ton) ?~ pax [%| (smyt pax) ?:(?=(& -.nex) ~ p.nex)] =+ zis=(tome t.pax) ?~ zis [%| (smyt pax) ?:(?=(& -.nex) ~ p.nex)] ?- -.nex & [%& u.zis p.nex] | nex == ==`
1234Recall that a toon is either a `%0` value, a `%1` block, or a `%2`
1235failure. Converting a `%2` toon failure into a `%2` bolt failure is
1236trivial. Converting a `%0` toon value into a `%0` bolt value is easy
1237since we assume there were no dependencies. Converting the blocks is
1238rather more difficult.
1240To compute `faw`, we recurse through the list of paths in the `%1` toon.
1241At each one, we make sure with `++tome` that it is, in fact, a beam. If
1242so, then we check to see if the later paths succeed as well. If so, we
1243append the current path to the list of other paths. If not, we produce
1244the error message we got from processing the rest of the paths. If this
1245path is not a beam, then we fail, producing a list of tanks including
1246this path and, if later paths fail too, those paths as well.
1248If some paths were not beams, then we produce a `%2` error bolt. If all
1249paths were correct, then we produce a `%1` blocking bolt.
1251We will now discuss `++clef`. This is where the cache magic happens.
1253 ++ clef :: cache a result
1255 |* [hoc=(bolt) fun=(burg)]
1260 =^ cux p.hoc ((calk p.hoc) sem q.q.hoc)
1262 =+ nuf=(cope hoc fun)
1267 :- p=(came p.nuf `calx`[sem `calm`[now p.q.nuf] q.q.hoc q.q.nuf])
1270 [p=p.hoc q=[%0 p=p.q.hoc q=((calf sem) u.cux)]]
1273If the value is already an error or a block, we just pass that through.
1274Otherwise, we look up the request in the cache with `++calk`.
1276 ++ calk :: cache lookup
1279 ^- [(unit calx) cafe] ::
1280 =+ d=(~(get by q.a) [b c]) ::
1282 [d a(p (~(put in p.a) u.d))] ::
1284When looking up something in the cache, we mark it if we find it. This
1285way, we have in our cache the set of all cache entries that have been
1286referenced. While we do not at present do anything with this data, it
1287should be used to clear out old and unused entries in the cache.
1289Moving on in `++clef`, we check to see if we actually found anything. If
1290we didn't find a cache entry, then we run the computation in `fun`, and
1291examine its result. If it produced a `%2` error or `%1` block bolt, we
1292just pass that through. Otherwise, we produce both the value and an
1293updated cache with this new entry. We add the entry with `++came`.
1296 |= [a=cafe b=calx] :: cache install
1298 a(q (~(put by q.a) [-.b q.b] b)) ::
1300We key cache entries by the type of computation (`-:calx`) and the
1301inputs to the computation (`q:calc`). This just puts the cache line in
1302the cache at the correct key.
1304Back in `++clef`, if we did find a cache entry, then we just produce the
1305value at that cache line. We convert the cache line into a value with
1308 ++ calf :: reduce calx
1309 |* sem=* :: a typesystem hack
1312 %hood ?>(?=(%hood -.cax) r.cax)
1313 %slap ?>(?=(%slap -.cax) r.cax)
1314 %slam ?>(?=(%slam -.cax) r.cax)
1317This is simply a typesystem hack. Because the `sem` is passed in through
1318a wet gate, we know at type time which of the three cases will be
1319chosen. Thus, the correct type of the value in the cache line gets
1320passed through to the caller. This also depends on the fact that
1321`++clef` is wet. The type stuff here is mathematically interesting, but
1322the action is simple: we get the value from the cache line.
1324This concludes our discussion of `++clef` and `++maim`.
1326Back in `++abut`, recall that we processed the structures, libraries,
1327and body with `++apex`. Then, we slapped our preamble (structures and
1328libraries) against zuse with `++maim`. Next, we process our resources
1329with `++chap`. Note that we pass in the preamble so that we may refer to
1330anything in there in our resources.
1332`++chap` is broken up into a different case for each horn. We'll go
1333through them one by one.
1335 ++ chap :: produce resources
1336 |= [cof=cafe bax=vase hon=horn]
1339 %ape (maim cof bax p.hon)
1341This is `/~`. We slap the twig against our context.
1344 %+ cope (maim cof bax p.hon)
1345 |= [cof=cafe gat=vase]
1346 (maul cof gat !>([how arg]))
1348This is `/$`. We slap the twig against our context, which we expect to
1349produce a gate. We slam this gate with a sample of `how` and `arg`,
1350which is our location and the heel (virtual path extension).
1352`++maul` is similar to `++maim`, but it slams instead of slaps.
1355 |= [cof=cafe gat=vase sam=vase]
1357 %+ (clef %slam) (fine cof gat sam)
1358 |= [cof=cafe gat=vase sam=vase]
1359 =+ top=(mule |.((slit p.gat p.sam)))
1362 & %+ (coup cof) (mong [q.gat q.sam] (mole ska))
1367We cache slams exactly as we cache slaps. We use `++slit` to find the
1368type of the product of the slam given the types of the gate and the
1371If this type fails, we produce the given stack trace as a `%2` error
1372bolt. Otherwise, we produce the top produced above combined with the
1373value we get from slamming the values in the vases with `++mong`.
1377 %day (chad cof bax %dr p.hon)
1379This is `/|`. We call `++chad` to convert textual names to relative
1380dates and process the next horn against each of the discovered paths.
1382 ++ chad :: atomic list
1383 |= [cof=cafe bax=vase doe=term hon=horn]
1385 %+ cope ((lash (slat doe)) cof how)
1386 |= [cof=cafe yep=(map ,@ span)]
1387 =+ ^= poy ^- (list (pair ,@ span))
1388 %+ sort (~(tap by yep) ~)
1389 |=([a=[@ *] b=[@ *]] (lth -.a -.b))
1391 |- ^- (bolt (list (pair ,@ vase)))
1393 %+ cope $(poy t.poy)
1394 |= [cof=cafe nex=(list (pair ,@ vase))]
1395 %+ cope (chap(s.how [q.i.poy s.how]) cof bax hon)
1396 |= [cof=cafe elt=vase]
1397 (fine cof [[p.i.poy elt] nex])
1398 |= [cof=cafe yal=(list (pair ,@ vase))]
1401 ?~ yal [[%cube 0 [%atom %n]] 0]
1402 (slop (slop [[%atom doe] p.i.yal] q.i.yal) $(yal t.yal))
1404First, we call `++lash` to parse the children of the current beam and
1405pick out those ones that are of the requested format.
1407 ++ lash :: atomic sequence
1408 |= wox=$+(span (unit ,@))
1409 |= [cof=cafe bem=beam]
1410 ^- (bolt (map ,@ span))
1411 %+ cope (lend cof bem)
1412 |= [cof=cafe arc=arch]
1413 (fine cof (lark wox arc))
1415First, we get the arch with `++lend`, as described above. We filter and
1416parse the child names with `++lark` according to the given parser
1419In `++chad`, this parser function is `(slat doe)`, which will parse a
1420cord into an atom of the requested odor. For `%day` the odor is for
1423Thus, we now have a map from atoms of the given odor to the actual child
1424names. We next turn this map into a list and sort it in increasing order
1427We next convert this list of pairs of atoms and spans to a list of pairs
1428of atoms and vases. We process the given horn once at every child beam,
1429producing the resource at that location.
1431Finally, we convert this list of pairs of atoms and vases to a vase of a
1432list of pairs of atoms to (well-typed) values. Each entry in the list is
1433of type atom with the given odor combined with the type of the produced
1436Back in `++chap`, we continue parsing resources.
1439 %+ cope $(hon q.hon)
1440 |= [cof=cafe vax=vase]
1441 (fine cof [[%face p.hon p.vax] q.vax])
1443This is `/=`. We process the given horn, giving us a vase. We put as a
1444face on the vase so that it may be referred to later by name.
1448 |- ^- (bolt (list vase))
1449 ?~ p.hon (fine cof ~)
1450 %+ cope ^$(hon i.p.hon)
1451 |= [cof=cafe vax=vase]
1452 %+ cope ^$(cof cof, p.hon t.p.hon)
1453 |= [cof=cafe tev=(list vase)]
1454 (fine cof [vax tev])
1455 |= [cof=cafe tev=(list vase)]
1458 ?~ tev [[%cube 0 [%atom %n]] 0]
1459 (slop i.tev $(tev t.tev))
1461This is `/.`. We first process each of the child horns, producing a list
1462of vases. This is done by just recursing on `++chap`. Then, we simply
1463fold over this list to create a vase of the list of values.
1465 %for $(hon q.hon, s.how (weld (flop p.hon) s.how))
1467This is `/,`. We simply recurse on the horn with the given path welded
1468onto our current beam.
1470 %hub (chad cof bax %ud p.hon)
1472This is `/@`. This is exactly like the processing of `%day` except we
1473expect the children to be named as unsigned integers rather than
1474relative dates. We process the horn at each of the children's locations
1475and produce a list of pairs of absolute dates and values.
1479 ?~ p.hon (fine cof [[%cube 0 [%atom %n]] 0])
1480 %+ cope $(p.hon l.p.hon)
1481 |= [cof=cafe lef=vase]
1482 %+ cope ^$(cof cof, p.hon r.p.hon)
1483 |= [cof=cafe rig=vase]
1484 %+ cope ^^^$(cof cof, hon q.n.p.hon)
1485 |= [cof=cafe vax=vase]
1488 (slop [[%atom %tas] p.n.p.hon] vax)
1491This is `/*`. We process each of the horns in the given map by recursion
1492through `++chap`. Once we have these vases, we create a vase of a map
1493from the given textual names to the produced values.
1495 %now (chad cof bax %da p.hon)
1497This is `/&`. This is exactly like the processing of `%now` except we
1498expect the children to be names as absolute dates rather than relative
1499dates. We process the horn at each of the children's locations and
1500produce a list of pairs of absolute dates and values.
1502 %nap (chai cof bax p.hon)
1504This is `/%`. Here, we process the horn at each of our children with
1507 ++ chai :: atomic map
1508 |= [cof=cafe bax=vase hon=horn]
1510 %+ cope (lend cof how)
1511 |= [cof=cafe arc=arch]
1513 |- ^- (bolt (map ,@ vase))
1514 ?~ r.arc (fine cof ~)
1515 %+ cope $(r.arc l.r.arc)
1516 |= [cof=cafe lef=(map ,@ vase)]
1517 %+ cope `(bolt (map ,@ vase))`^$(cof cof, r.arc r.r.arc)
1518 |= [cof=cafe rig=(map ,@ vase)]
1519 %+ cope (chap(s.how [p.n.r.arc s.how]) cof bax hon)
1520 |= [cof=cafe nod=vase]
1521 (fine cof [[p.n.r.arc nod] lef rig])
1522 |= [cof=cafe doy=(map ,@ vase)]
1525 ?~ doy [[%cube 0 [%atom %n]] 0]
1527 (slop [[%atom %a] p.n.doy] q.n.doy)
1528 (slop $(doy l.doy) $(doy r.doy))
1530We get the arch at our current beam with `++lend`. Then, we process the
1531horn at each of our children to give us a map of atoms to vases.
1532Finally, we convert that into a vase of a map of these atoms to the
1533values. This is very similar to `++chad` and the handling of `%man`.
1535 %see $(hon q.hon, how p.hon)
1537This is `/:`. We process the given horn at the given beam.
1540 %+ cope $(hon q.hon)
1541 |= [cof=cafe sam=vase]
1542 %+ cope (maim cof bax p.hon)
1543 |= [cof=cafe gat=vase]
1546This is `/;`. First, we process the given horn. Then, we slap the given
1547twig against our context to produce (hopefully) a gate. Finally, we slam
1548the vase we got from processing the horn against the gate.
1551 %+ cope $(hon q.hon)
1552 |= [cof=cafe vax=vase]
1553 %+ cope (maim cof bax [%bctr p.hon])
1554 |= [cof=cafe tug=vase]
1555 ?. (~(nest ut p.tug) | p.vax)
1556 (flaw cof [%leaf "type error: {<p.hon>} {<q.hon>}"]~)
1557 (fine cof [p.tug q.vax])
1559This is `/^`. First, we process the given horn. Then, we slap the the
1560bunt of the given tile against our context. This will produce a vase
1561with the correct type. We test to see if this type nests within the type
1562of the vase we got from processing the horn. If so, we produce the value
1563from the horn along with the type from the tile. Otherwise, we produce a
1566 %toy (cope (make cof %bake p.hon how ~) feel)
1569This is `/mark/`. Here, we simply run the `%bake` silk on the given
1570mark, producing a cage. We convert this cage into a vase with `++feel`,
1571which is exactly as simple as it sounds like it should be.
1573 ++ feel |=([a=cafe b=cage] (fine a q.b)) :: cage to vase
1577We will discuss later `++make` and how `%bake` is processed. Suffice it
1578to say that baking a resource with a given mark gets the resource and
1579converts it, if necessary, to the requested mark.
1581This concludes our discussion of `++chap`.
1583We return once more to `++abut`.
1586 |= [cof=cafe hyd=hood]
1588 %+ cope (apex cof hyd)
1589 |= [cof=cafe sel=_..abut]
1591 %+ cope (maim cof pit able)
1592 |= [cof=cafe bax=vase]
1593 %+ cope (chap cof bax [%fan fan.hyd])
1594 |= [cof=cafe gox=vase]
1595 %+ cope (maim cof (slop gox bax) [%tssg (flop boy)])
1596 |= [cof=cafe fin=vase]
1599Recall that we processed our structures, libraries and body with
1600`++apex`. We slapped our structures and libraries against zuse with
1601`++maim`. We processed our resources with `++chap`. Now, all our body
1602twigs are collected in a `=~` and slapped against our structures,
1603libraries, and resources. This produces our final result.
1605The hook file has been assembled. And there was great rejoicing.
1610We're now going to go through a series of lifecycle descriptions. When a
1611user of ford sends a kiss, it is one of a dozen different types of silk.
1612We'll go through each one, tracing through the flow of control of each
1615First, though, we'll describe the common handling to all kisses.
1617The silk in a `%exec` kiss to ford ends up in `++apex`, so we'll enter
1624 =+ nym=(~(get by dym.bay) hen)
1625 ?~ nym :: XX should never
1626 ~& [%ford-mystery hen]
1628 =+ tas=(need (~(get by q.tad.bay) u.nym))
1629 amok:~(camo zo [u.nym tas])
1631 ?< (~(has by dym.bay) hen)
1632 =: p.tad.bay +(p.tad.bay)
1633 dym.bay (~(put by dym.bay) hen num)
1635 ~(exec zo [num `task`[hen u.kus 0 ~]])
1637Recall that a `%exec` kiss actually sends a unit silk. If it's null,
1638we're trying to cancel the request. We first look up the task number
1639keyed by duct. If we don't find it, then we're trying to cancel a
1640request that either was never started or has already completed. We print
1641out `%ford-mystery` and do nothing. If we do find the task number, then
1642we look up the task from it, call `++camo:zo` to cancel pending
1643requests, and call `++amok:zo` to remove the task from our task lists.
1645 ++ camo :: stop requests
1647 =+ kiz=(~(tap by q.kig) *(list ,[p=@ud q=beam]))
1654 :^ %pass [(scot %p our) (scot %ud num) (scot %ud p.i.kiz) ~]
1656 [%warp [our p.q.i.kiz] q.q.i.kiz ~]
1659Our list of blocks is in `q.kig`, so we iterate over it, cancelling our
1660pending requests for each block. Our requests are all to clay, so we
1661need only to send `%warp` kisses with a null instead of a rave.
1665 q.tad.bay (~(del by q.tad.bay) num)
1666 dym.bay (~(del by dym.bay) nah)
1669We remove the task number from the map of numbers to tasks and the duct
1670from the map of ducts to task numbers.
1672Back in `++apex`, if we were given a silk, we need to process it. We add
1673the task to our maps, increment the next task number, and call
1674`++exec:zo` on the new task.
1676 ++ exec :: execute app
1680 =+ bot=(make [~ jav.bay] kas)
1681 =. ..exec (dash p.bot)
1683 %0 amok:(expo [%made %& p.q.bot q.q.bot])
1684 %2 amok:(expo [%made %| p.q.bot])
1685 %1 =+ zuk=(~(tap by p.q.bot) ~)
1689 =+ foo=`_..exec`(camp %x `beam`p.i.zuk)
1690 $(zuk t.zuk, ..exec foo)
1693If we're still blocked on something in `q.kig`, we don't do anything.
1695Otherwise, we try to process the silk with `++make`. `++make` handles
1696each individual request and will be the entire focus of the remainder of
1697this doc after this section. It produces a bolt of a cage.
1699We put the new cache in our state with `++dash`.
1701 ++ dash :: process cache
1704 %_(+> jav.bay q.cof)
1706The cache is put in the baby so that it gets stored across calls to
1709In `++exec`, we process the bolt in three different ways according to
1710the type of bolt produced. If we produced a `%0` value bolt, we use
1711`++expo` to give the produced value and set of dependencies as a `%made`
1712gift, and we remove ourselves from the task list with `++amok`.
1714 ++ expo :: return gift
1716 %_(+> mow :_(mow [hen %give gef]))
1718We simply push the gift onto our list of moves.
1720In `++exec`, if we produced a `%2` error bolt, we produce a `%made` gift
1721with the stack trace.
1723If we produced a `%1` block bolt, we iterate through each of the blocks
1724and call `++camp` to produce a clay request for the resource.
1726 ++ camp :: request a file
1727 |= [ren=care bem=beam]
1730 kig [+(p.kig) (~(put by q.kig) p.kig bem)]
1733 :^ %pass [(scot %p our) (scot %ud num) (scot %ud p.kig) ~]
1735 [%warp [our p.bem] q.bem [~ %& %x r.bem s.bem]]
1738We put the resource in our block list in `q.kig` so that we save the
1739fact that we're blocked. We then produce the `%warp` request to clay for
1740the resource. Our request path has the format
1741\`/[our-ship]/[task-number]/[block-number]'.
1743We'll now describe how each of the individual silks are processed in
1750 %. [cof p.kas q.kas]
1753 |=([cof=cafe p=silk q=silk] ^$(cof cof, kas p.kas))
1754 |=([cof=cafe p=silk q=silk] ^$(cof cof, kas q.kas))
1757 |= [cof=cafe bor=cage heg=cage] ^- (bolt cage)
1758 [p=cof q=[%0 ~ [%$ (slop q.bor q.heg)]]]
1761Silks autocons. The product of a cell of silks is a cell of the products
1762of the silks, so we evaluate the two silks in parallel with `++coax` and
1763slop together the results in a cell vase. We mark the product with `%$`,
1764which means we know no more mark information than that it is a noun.
1766 ++ coax :: bolt across
1767 |* [hoc=(bolt) fun=(burg)]
1769 %0 =+ nuf=$:fun(..+<- p.hoc)
1773 %0 [%0 p=(grom p.q.hoc p.q.nuf) q=[q.q.hoc q.q.nuf]]
1777 %1 =+ nuf=$:fun(..+<- p.hoc)
1782 %1 [%1 p=(grom p.q.nuf p.q.hoc)]
1788If the first bolt is a value, we evaluate the burg to get the next bolt.
1789If that also produces a value, we merge the dependency sets and produce
1790a cell of the two values. Otherwise, we produce the block or error of
1793If the first bolt is a block, we evaluate the burg to get the next bolt.
1794If that produces a value, we just produce the block. If it produces a
1795block, we merge the two block sets. If it produces an error, we produce
1798If the first bolt is already an error, we just pass that through.
1800Note that `++coax` (and, indeed, `++cope`) is reasonable to use with
1803Lifecycle of a `%bake`
1804----------------------
1807 %+ cool |.(leaf/"ford: bake {<p.kas>} {<(tope q.kas)>}")
1808 %+ cope (lima cof p.kas q.kas r.kas)
1809 |= [cof=cafe vux=(unit vase)]
1811 (flaw cof (smyt (tope q.kas)) ~)
1812 (fine cof [p.kas u.vux])
1814This is one of the most critical silks. We are going to functionally
1815produce the hook file at the given beam with the given heel. The result
1816will be of the correct mark, even if we need to run conversion
1817functions. The functionality is encapsulated in `++lime`. If it produces
1818null, then we produce an error. Otherwise, we take the vase produced and
1819give it the correct mark.
1821 ++ lima :: load at depth
1822 |= [cof=cafe for=mark bem=beam arg=heel]
1823 ^- (bolt (unit vase))
1824 %+ cope (lend cof bem)
1825 |= [cof=cafe arc=arch]
1826 ^- (bolt (unit vase))
1827 ?: (~(has by r.arc) for)
1828 (lace cof for bem(s [for s.bem]) arg)
1829 =+ haz=(turn (~(tap by r.arc) ~) |=([a=@tas b=~] a))
1831 %+ cope (lion cof for -.bem haz)
1832 |= [cof=cafe wuy=(unit (list ,@tas))]
1835 %+ cope (make cof %bake i.u.wuy bem arg)
1836 |= [cof=cafe hoc=cage]
1837 %+ cope (lope cof i.u.wuy t.u.wuy -.bem q.hoc)
1838 |= [cof=cafe vax=vase]
1841First, we load the arch at the given beam with `++lend`. If we have a
1842child named the mark, our job is straightforward, so we go ahead and
1843load that with `++lace`.
1845Otherwise, we iterate through our children. If we have no children, we
1846produce null, signifying that we didn't find any way to convert to the
1847requested mark. Otherwise, we call `++lion` to find a translation path
1848from one of the available marks into the target mark. We recursively
1849bake the child that has a path to the target mark, and then we call
1850`++lope` to translate this mark into the target mark.
1852We'll first discuss the direct case of when one of our children is of
1855 ++ lace :: load and check
1856 |= [cof=cafe for=mark bem=beam arg=heel]
1857 ^- (bolt (unit vase))
1858 =+ bek=`beak`[p.bem q.bem r.bem]
1859 %+ cope (lend cof bem)
1860 |= [cof=cafe arc=arch]
1862 (cope (cope (liar cof bem) (lake for bek)) fest)
1863 ?: (~(has by r.arc) %hook)
1864 %+ cope (fade cof %hook bem)
1865 |= [cof=cafe hyd=hood]
1866 (cope (cope (abut:(meow bem arg) cof hyd) (lake for bek)) fest)
1869First, we get the arch at the given beam with `++lend`. If this is a
1870file, we load the file with `++liar` and coerce the type with `++lake`.
1871Otherwise, we check to see if we have a hook file here. If so, we parse
1872it with `++fade`, compile it with `++abut:meow`, and coerce the type
1875Otherwise, there is no way to translate this, so we produce null.
1877`++fest` is one line, so we'll get that one out of the way first.
1879 ++ fest |*([a=cafe b=*] (fine a [~ u=b])) :: bolt to unit
1881This is just `++some` for bolts.
1883We've delayed the discussion of `++fade` far too many times. It's not
1884complicated, we just wanted to spare a premature discussion of `++make`
1885and the `%bake` silk. We 're now able to discuss everything in `++fade`
1888 ++ fade :: compile to hood
1889 |= [cof=cafe for=mark bem=beam]
1891 %+ cool |.(leaf/"ford: fade {<[(tope bem)]>}")
1892 %+ cope (make cof [%bake for bem ~])
1893 |= [cof=cafe cay=cage]
1894 %+ (clef %hood) (fine cof bem cay)
1895 ^- (burg (pair beam cage) hood)
1896 |= [cof=cafe bum=beam cay=cage]
1900 =+ vex=((full rul) [[1 1] (trip q.q.cay)])
1902 (flaw cof [%leaf "syntax error: {<p.p.vex>} {<q.p.vex>}"] ~)
1903 (fine cof p.u.q.vex)
1905We first push a line onto a stack trace to say that we're parsing into a
1908We bake the given beam with the given mark and no heel. Recall that
1909baking gate, core, door, hoon, and hook files produces simply an atom of
1910the text. We check to make sure that our value is an atom, failing
1913The parsing step is run within `++clef` so that the result is cached. We
1914call `++fair` with the current beam to generate the parsing rule, and we
1915parse the file. If parsing fails, we fail giving a syntax error with the
1916line and column number. Otherwise, we produce the value.
1918 ++ liar :: load vase
1919 |= [cof=cafe bem=beam]
1921 =+ von=(ska %cx (tope bem))
1923 [p=*cafe q=[%1 [[bem ~] ~ ~]]]
1925 (flaw cof (smyt (tope bem)) ~)
1926 (fine cof ?^(u.u.von [%cell %noun %noun] [%atom %$]) u.u.von)
1928This takes a beam and loads the file at that location. If our sky
1929function produces null, that means the resource is currently
1930unavailable, so we block on it. If it produces `[~ ~]`, that means our
1931resource is permanently unavailable, so we produce an error. Otherwise,
1932we produce the value there with a type of either a cell of two nouns or
1933an atom, depending on whether the value is a cell or not.
1935Back in `++lima`, recall that we call `++lion` to find a translation
1938 ++ lion :: translation search
1939 |= [cof=cafe too=@tas bek=beak fro=(list ,@tas)]
1940 ^- (bolt (unit (list ,@tas)))
1942 =< -:(apex (fine cof fro))
1945 |= rof=(bolt (list ,@tas))
1946 ^- [(bolt (unit (list ,@tas))) _+>]
1947 ?. ?=(%0 -.q.rof) [rof +>.$]
1949 [[p.rof [%0 p.q.rof ~]] +>.$]
1950 =^ orf +>.$ (apse cof i.q.q.rof)
1954 $(cof p.orf, q.q.rof t.q.q.rof)
1955 [[p.orf [%0 (grom p.q.rof p.q.orf) q.q.orf]] +>.$]
1958 |= [cof=cafe for=@tas]
1959 ^- [(bolt (unit (list ,@tas))) _+>]
1961 [(fine cof [~ too ~]) +>.$]
1962 ?: (~(has in war) for) [(fine cof ~) +>]
1963 =. war (~(put in war) for)
1964 =^ hoc +>.$ (apex (lily cof for bek))
1967 |= [cof=cafe ked=(unit (list ,@tas))]
1968 (fine cof ?~(ked ~ [~ for u.ked]))
1971At a high level, we have `++apex` and `++apse`. `++apex` takes a list of
1972marks to try in succession until we find one that can be translated into
1973the target mark. On each one, it calls `++apse`, which takes a single
1974mark and tries to find a translation path from this mark to the target.
1975To do this, it sees which marks we know how to directly translate to,
1976and calls `++apex` on this list. The result of this mututal recursion is
1977a depth-first search of the translation graph to find the target mark.
1978Since the translation graph is not necessarily acyclic, we maintain a
1979set of marks that we've already tried.
1981We kick off our search in `++apex`, starting with the given initial list
1982of marks that we know how to get to.
1984If `++apex` is called with a bolt other than a `%0` value bolt, we
1985simply produce it. Otherwise, we check to see if the list of available
1986marks to investigate is null. If so, then we're done, so we produce a
1987`%0` bolt with a null list of accessible marks.
1989Otherwise, we process this next mark with `++apse`, which will produce a
1990possible list of marks from this one to the target mark. If it fails to
1991produce a `%0` bolt, we just produce that. Otherwise, if it produces
1992null, we can't get to our target through this mark, so we move on to the
1995If it doesn't produce null, then we have successfully found a
1996translation path, so we produce it.
1998In `++apse`, we first test to see if we've arrived at the target path.
1999If so, we're done, so we produce a list including just ourself.
2000Otherwise, we check to see if we've already tried this mark. If so, we
2001know we can't succeed here, so we produce null. Otherwise, we put
2002ourselves in the set of already-tried marks, and we move on.
2004We call `++lily` to get the list of marks we can translate this one
2007 ++ lily :: translation targets
2008 |= [cof=cafe for=mark bek=beak]
2009 ^- (bolt (list ,@tas))
2010 =+ raf=(fang cof for bek)
2011 ?: =(%2 -.q.raf) (fine p.raf ~)
2013 |= [cof=cafe vax=vase]
2017 ?. (slab %garb p.vax) ~
2018 =+ gav=((soft (list ,@tas)) q:(slap vax [%cnzy %garb]))
2020 ?. (slab %grow p.vax) ~
2021 =+ gow=(slap vax [%cnzy %grow])
2024We call `++fang` to get the mark definition door. This is documented
2025under `%vale`. If getting the mark fails, we produce null because we
2026can't translate a non-existent mark into anything.
2028Otherwise, we examine the door. The door may have a `++garb`, which is
2029simply a list of marks which know how to translate from the current one.
2030There must be a corresponding `++grab` in the definition of the other
2031mark, though we don't check that here.
2033The door may also have a `++grow`, which defines how to translate this
2034mark into another one. Each arm in `++grow` is the name of a mark we can
2035translate into. The call to `++sloe` simply produces a list of arm names
2038Back in `++apse:lion`, we take the list of translation targets we just
2039found and call `++apex` on it. If we got back a null, we produce a null;
2040otherwise, we produce the list of marks we got back plus the current
2043This concludes our discussion of `++lion`.
2045The final piece of `++lima` is `++lope`, which performs the actual
2046translation along the path we just computed.
2048 ++ lope :: translation pipe
2049 |= [cof=cafe for=mark yaw=(list mark) bek=beak vax=vase]
2051 ?~ yaw (fine cof vax)
2052 %+ cope (link cof i.yaw for bek vax)
2053 |= [cof=cafe yed=vase]
2054 ^$(cof cof, for i.yaw, yaw t.yaw, vax yed)
2056We iterate through our list, calling `++link` on every adjacent pair of
2057marks, translating from one mark to the next until we finish the list of
2058marks. A call to `++link` is equivalent to a `%cast` silk, so we
2059document it there. After we've called performed every step in the
2060translation pipeline, we're done.
2062Lifecycle of a `%boil`
2063----------------------
2066 %+ cool |.(leaf/"ford: boil {<p.kas>} {<(tope q.kas)>} {<r.kas>}")
2067 %+ cope (lamp cof q.kas)
2068 |= [cof=cafe bem=beam]
2069 %+ cope (lime cof p.kas bem r.kas)
2070 |= [cof=cafe vax=vase]
2071 (fine cof `cage`[p.kas vax])
2073At a high level, we try to bake at the given beam, and if it fails, we
2074go up a level and try again. This is the usual semantics of ford, and
2075this should nearly always be preferred over directly baking.
2077First, we normalize the version case to a number with `++lamp`. This
2078allows caching to be based on revision number rather than something more
2079ephemeral like a particular time.
2081 ++ lamp :: normalize version
2082 |= [cof=cafe bem=beam]
2084 =+ von=(ska %cw (tope bem(s ~)))
2085 ?~ von [p=cof q=[%1 [bem ~] ~ ~]]
2086 (fine cof bem(r [%ud ((hard ,@) (need u.von))]))
2088We call the sky function with `%cw`, asking clay for the revision number
2089at this case. If the case refers to a revision that isn't there yet, we
2090produce a `%1` blocking bolt. Otherwise, we require that the value exist
2091and that it's a number, both of which are guaranteed by clay. We produce
2094Next for `%boil` we call `++lime` to try to load the beam.
2096 ++ lime :: load beam
2097 |= [cof=cafe for=mark bem=beam arg=heel]
2098 =+ [mob=bem mer=(flop arg)]
2100 %+ cope (lima cof for mob (flop mer))
2101 |= [cof=cafe vux=(unit vase)]
2102 ?^ vux (fine cof u.vux)
2104 (flaw cof (smyt (tope bem)) ~)
2105 ^$(s.mob t.s.mob, mer [i.s.mob mer])
2107We start at the given beam and try to bake it. If it succeeds, we're
2108good. Otherwise, we pop off the top level of the path and put it in our
2109heel (virtual path extension). We do this recursively until either we
2110find something we can bake or we've gone all the way up to the root path
2111of the desk, in which case we fail.
2113Lifecycle of a `%call`
2114----------------------
2117 %+ cool |.(leaf/"ford: call {<`@p`(mug kas)>}")
2118 %. [cof p.kas q.kas]
2121 |=([cof=cafe p=silk q=silk] ^$(cof cof, kas p))
2122 |=([cof=cafe p=silk q=silk] ^$(cof cof, kas q))
2125 |= [cof=cafe gat=cage sam=cage]
2126 (maul cof q.gat q.sam)
2128 |= [cof=cafe vax=vase]
2129 (fine cof %noun vax)
2132This is slam for silks. We process both of the given silks in parallel
2133with `++coax`. We then slam the two produced vases together with
2134`++maul` and mark the produced vase with `%noun` since we don't know any
2137`++coax` is documented under Lifecycle of a Cell.
2139Lifecycle of a `%cast`
2140----------------------
2143 %+ cool |.(leaf/"ford: cast {<p.kas>}")
2144 %+ cope $(kas q.kas)
2145 |= [cof=cafe cay=cage]
2146 %+ cope (link cof p.kas p.cay [our %main %da now] q.cay)
2147 |= [cof=cafe vax=vase]
2148 (fine cof [p.kas vax])
2150This is a request to convert data of one mark to another mark directly.
2151We evaluate the given silk and pass the result into `++link`, which
2152performs the actual translation. Note that this will not search for
2153indirect conversion paths, so the conversion must be defined either in
2154the `++grow` of the given mark or the `++grab` of the target mark.
2156 ++ link :: translate
2157 |= [cof=cafe too=mark for=mark bek=beak vax=vase]
2159 ?: =(too for) (fine cof vax)
2160 ?: |(=(%noun for) =(%$ for))
2161 ((lake too bek) cof vax)
2162 %+ cope (fang cof for bek)
2163 |= [cof=cafe pro=vase]
2164 ?: &((slab %grow p.pro) (slab too p:(slap pro [%cnzy %grow])))
2165 %+ cope (keel cof pro [[%& 6]~ vax]~)
2166 |= [cof=cafe pox=vase]
2167 (maim cof pox [%tsgr [%cnzy %grow] [%cnzy too]])
2168 %+ cope (fang cof too bek)
2169 |= [cof=cafe pro=vase]
2170 =+ ^= zat ^- (unit vase)
2171 ?. (slab %grab p.pro) ~
2172 =+ gab=(slap pro [%cnzy %grab])
2173 ?. (slab for p.gab) ~
2174 `(slap gab [%cnzy for])
2176 (flaw cof [%leaf "ford: no link: {<[for too]>}"]~)
2177 (maul cof u.zat vax)
2179This performs one step in the translation pipeline. If the given and
2180target marks are the same, we're done. If we're translating from a noun
2181or the empty mark, we coerce with `++lake` (documented in `%vale`).
2182Otherwise, we're translating from a user-defined mark.
2184We load the definition of the given mark with `++fang`, and we check to
2185see if it has an arm in `++grow` named the target mark. If so, we place
2186our data in the sample of the door with `++keel` and slap the arm.
2187`++keel` is equivalent to a `%mute` silk, so we document it there.
2189If there is no arm in `++grow` of the given mark named the target mark,
2190we suppose there must be an arm in `++grab` of the target mark named the
2191given mark. We get the definition of the target mark and check to see if
2192it has the required arm, failing if it doesn't. Finally, we slam the
2193data against the correct arm, producing the translated data.
2195If you're confused as to why the handling of `++grow` and `++grab` look
2196superficially so different, remember that the correct arm in `++grow`
2197does not have a sample while the one in `++grab` does. This means they
2198must be called rather differently.
2200Lifecycle of a `%diff`
2201----------------------
2204 %+ cool |.(leaf/"ford: diff {<`@p`(mug p.kas)>} {<`@p`(mug q.kas)>}")
2205 (diff cof p.kas q.kas)
2207We push debug information onto the trace and go right to `++diff`.
2210 |= [cof=cafe kas=silk kos=silk]
2215 |=([cof=cafe p=silk q=silk] (make cof p))
2216 |=([cof=cafe p=silk q=silk] (make cof q))
2218 |= [cof=cafe cay=cage coy=cage]
2220First, we process the two given silks to get our arguments.
2224 leaf/"diff on data of different marks: {(trip p.cay)} {(trip p.coy)}"
2226If the two cages have different marks, then we can't diff them, so we
2229 %+ cope (fang cof p.cay [our %main %da now])
2230 |= [cof=cafe pro=vase]
2232We pull in the relevant mark's definition.
2234 ?. (slab %grad p.pro)
2235 (flaw cof leaf/"no ++grad" ~)
2236 =+ gar=(slap pro [%cnzy %grad])
2237 ?. (slab %form p.gar)
2238 ?. (slab %sted p.gar)
2239 (flaw cof leaf/"no ++form:grad nor ++sted:grad" ~)
2240 =+ for=((soft ,@tas) q:(slap gar [%cnzy %sted]))
2242 (flaw cof leaf/"bad ++sted:grad" ~)
2243 (make cof %diff [%cast u.for kas] [%cast u.for kos])
2245If there's no `++grad`, we complain. If there's no `++form:grad`, then
2246we look for a `++sted:grad`. If we can't find either, or if
2247`++sted:grad` isn't a term, then we complain. If `++sted:grad` exists
2248and is a term, then it represents the mark we should use as a proxy to
2249get our diff. So, we cast both our given cages to the new mark and start
2252 ?. (slab %diff p.gar)
2253 (flaw cof leaf/"no ++diff:grad" ~)
2255Otherwise, we expect a `++diff:grad`.
2257 %+ cope (keel cof pro [[%& 6]~ q.cay]~)
2258 |= [cof=cafe pox=vase]
2260We put the first cage's data into the sample of the given mark's
2265 (slap (slap pox [%cnzy %grad]) [%cnzy %diff])
2267 |= [cof=cafe dif=vase]
2269We run `++diff:grad` with a sample of the second cage's data.
2271 =+ for=((soft ,@tas) q:(slap gar [%cnzy %form]))
2273 (flaw cof leaf/"bad ++form:grad" ~)
2274 (fine cof u.for dif)
2277We check that `++form:grad` exists, and we tag the result with it to
2280Lifecycle of a `%done`
2281----------------------
2283 %done [cof %0 p.kas q.kas]
2285This is trivial. We simply produce the given cage with the given set of
2286dependencies. This is used when we already have a cage that we want to
2287insert into another silk that requires a silk argument. It's analogous
2288to the return operator in a monad -- which makes it sound way more
2289complicated than it is.
2291Lifecycle of a `%dude`
2292----------------------
2294 %dude (cool |.(p.kas) $(kas q.kas))
2296This simply puts a given tank on the stack trace if the given silk
2297produces an error. This is implemented as a simple call to `++cool`.
2299Lifecycle of a `%dune`
2300----------------------
2303 ?~ q.kas [cof [%2 [%leaf "no data"]~]]
2304 $(kas [%done p.kas u.q.kas])
2306This is a sort of a `++need` for silks. If there is no data in the unit
2307cage, we produce an error. Else, we simply produce the data in the cage.
2309Lifcycle of a `%mute`
2310---------------------
2312 %mute (kale cof p.kas q.kas)
2314This mutates a silk by putting the values of other silks at particular
2315axes. This is useful in, for example, replacing the sample of the door
2316in a mark definition.
2319 |= [cof=cafe kas=silk muy=(list (pair wing silk))]
2322 |- ^- (bolt (list (pair wing vase)))
2324 %+ cope (make cof q.i.muy)
2325 |= [cof=cafe cay=cage]
2326 %+ cope ^$(muy t.muy)
2327 |= [cof=cafe rex=(list (pair wing vase))]
2328 (fine cof [[p.i.muy q.cay] rex])
2329 |= [cof=cafe yom=(list (pair wing vase))]
2330 %+ cope (make cof kas)
2331 |= [cof=cafe cay=cage]
2332 %+ cope (keel cof q.cay yom)
2333 |= [cof=cafe vax=vase]
2334 (fine cof p.cay vax)
2336First, we process each of the silks by calling `++make` on them. We pass
2337the resultant vase and list of pairs of wings and silks to `++keel` to
2338do the actual mutation. We assume the mutation doesn't change the mark
2339of the main silk, so we mark the produced vase with the original mark.
2341 ++ keel :: apply mutations
2342 |= [cof=cafe suh=vase yom=(list (pair wing vase))]
2347 ?~ yom [[%atom %n] ~]
2348 (slop q.i.yom $(yom t.yom))
2352 |- ^- (list (pair wing twig))
2354 :- [p.i.yom [%$ (peg axe 2)]]
2355 $(yom t.yom, axe (peg axe 3))
2357We first put the vases together in one big tuple starting with the
2358subject and going through the mutations. We slap against this tuple a
2359`%_` twig we directly construct. Since a `%_` twig takes a list of pairs
2360of wings and twigs, we simply have to generate twigs referring to the
2361correct axes in the subject. This is very easy since we just recur on
2362axis 3 of whatever axis we were already at.
2364Note the use of `%_` instead of `%=` enforces that our mutations don't
2365change the type of the subject, which justifies our use of the original
2368Lifecycle of a `%pact`
2369----------------------
2372 %+ cool |.(leaf/"ford: pact {<`@p`(mug p.kas)>} {<`@p`(mug q.kas)>}")
2373 (pact cof p.kas q.kas)
2375We push debug information onto the trace and go right to `++pact`.
2378 |= [cof=cafe kas=silk kos=silk]
2383 |=([cof=cafe p=silk q=silk] (make cof p))
2384 |=([cof=cafe p=silk q=silk] (make cof q))
2386 |= [cof=cafe cay=cage coy=cage]
2388First, we process the two given silks to get our arguments.
2390 %+ cope (fang cof p.cay [our %main %da now])
2391 |= [cof=cafe pro=vase]
2393We pull in the relevant mark's definition.
2395 ?. (slab %grad p.pro)
2396 (flaw cof leaf/"no ++grad" ~)
2397 =+ gar=(slap pro [%cnzy %grad])
2398 ?. (slab %form p.gar)
2399 ?. (slab %sted p.gar)
2400 (flaw cof leaf/"no ++form:grad nor ++sted:grad" ~)
2401 =+ for=((soft ,@tas) q:(slap gar [%cnzy %sted]))
2403 (flaw cof leaf/"bad ++sted:grad" ~)
2404 (make cof %cast p.cay %pact [%cast u.for kas] kos)
2406If there's no `++grad`, we complain. If there's no `++form:grad`, then
2407we look for a `++sted:grad`. If we can't find either, or if
2408`++sted:grad` isn't a term, then we complain. If `++sted:grad` exists
2409and is a term, then it represents the mark we should use as a proxy to
2410get our diff. So, we cast the first argument to the new mark, then try
2411to patch. Afterward, we cast the result back to the original mark.
2413 =+ for=((soft ,@tas) q:(slap gar [%cnzy %form]))
2415 (flaw cof leaf/"bad ++form:grad" ~)
2418 =< leaf/"pact on data with wrong form: {-} {+<} {+>}"
2419 [(trip p.cay) (trip u.for) (trip p.coy)]
2421If `++form:grad` isn't a term, or else our second argument isn't of that
2424 ?. (slab %pact p.gar)
2425 (flaw cof leaf/"no ++pact:grad" ~)
2427If we don't have a `++pact:grad`, we complain.
2429 %+ cope (keel cof pro [[%& 6]~ q.cay]~)
2430 |= [cof=cafe pox=vase]
2432We put the first cage's data into the sample of the given mark's
2437 (slap (slap pox [%cnzy %grad]) [%cnzy %pact])
2439 |= [cof=cafe pat=vase]
2441We run `++pact:grad` with a sample of the second cage's data, which is
2444 (fine cof p.cay pat)
2447We tag the result with the mark of our first argument.
2449Lifecycle of a `%plan`
2450----------------------
2453 %+ cope (abut:(meow p.kas q.kas) cof r.kas)
2454 |= [cof=cafe vax=vase]
2455 (fine cof %noun vax)
2457This is a direct request to compile a hood at a given beam with a heel
2458of the given path. We comply by calling `++abut` with the given
2459arguments and producing the vase with a mark of `%noun`.
2461Lifecycle of a `%reef`
2462----------------------
2464 %reef (fine cof %noun pit)
2466This is one of the simplest silks. We simply produce our context, which
2467is zuse compiled against hoon. The mark is a `%noun`.
2469Lifcycle of a `%ride`
2470---------------------
2473 %+ cool |.(leaf/"ford: ride {<`@p`(mug kas)>}")
2474 %+ cope $(kas q.kas)
2475 |= [cof=cafe cay=cage]
2476 %+ cope (maim cof q.cay p.kas)
2477 |= [cof=cafe vax=vase]
2478 (fine cof %noun vax)
2480This slaps evaluates the given silk, then it slaps the result against
2481the given twig. Since we don't know what of what mark (if any) is the
2482result, we give it a mark of `%noun`.
2484Lifecycle of a `%vale`
2485----------------------
2488 %+ cool |.(leaf/"ford: vale {<p.kas>} {<q.kas>} {<`@p`(mug r.kas)>}")
2489 %+ cope (lave cof p.kas q.kas r.kas)
2490 |= [cof=cafe vax=vase]
2491 (fine cof `cage`[p.kas vax])
2493This checks whether given data is of the given mark. If we don't have
2494the definition of the mark, we check the given ship for it.
2496We call `++lave` to perform the check, producing a vase. We produce this
2497vase tagged with the given mark.
2500 |= [cof=cafe for=mark his=ship som=*]
2502 ((lake for [our %main [%da now]]) cof [%noun som])
2504This is a thinly-veiled wrapper over `++lake`. Note that, contrary to
2505documented opinion, we do not in fact check the other ship's definition
2506of a mark. This is likely a bug.
2508At any rate, `++lake` coerces a noun into the correct type for a mark.
2510 ++ lake :: check/coerce
2511 |= [for=mark bek=beak]
2512 |= [cof=cafe sam=vase]
2514 %+ cool |.(leaf/"ford: check {<[for bek `@p`(mug q.sam)]>}")
2515 ?: ?=(?(%gate %core %door %hoon %hook) for)
2516 :: ~& [%lake-easy for bek]
2518 %+ cope (fang cof for bek)
2519 |= [cof=cafe tux=vase]
2521 ?: (~(nest ut p.bob) | p.sam)
2523 ?. (slab %grab p.tux)
2524 (flaw cof [%leaf "ford: no grab: {<[for bek]>}"]~)
2525 =+ gab=(slap tux [%cnzy %grab])
2526 ?. (slab %noun p.gab)
2527 (flaw cof [%leaf "ford: no noun: {<[for bek]>}"]~)
2528 %+ cope (maul cof (slap gab [%cnzy %noun]) [%noun q.sam])
2529 |= [cof=cafe pro=vase]
2530 ?: =(+<.q.pro q.sam)
2531 (fine cof (slot 6 pro))
2532 (flaw cof [%leaf "ford: invalid content: {<[for bek]>}"]~)
2534This is going to coerce the sample into the correct type for the mark.
2535First, we push a line onto the stack trace saying that we're checking
2536the type. If the requested mark is a gate, core, door, hoon, or hook,
2537then we don't do any more type information than just saying it's a noun,
2540Otherwise, we get the mark definition from our `/=main=/mar` directory
2541with `++fang`, which we'll describe below.
2543We check to see if our sample type nests within the type of the sample
2544to the door. If so, then we're already of the correct type, so we're
2547Otherwise, we check to see if there's a `++grab` in the door, and a
2548`++noun` in the `++grab`. If not, there's no way we can translate to
2549this mark, so we fail.
2551If we have everything we need, we slam our sample (typed as a noun)
2552against the `++noun` in `++grab`. If the sample of the door is the same
2553as our sample, then the check succeeded, so we produce the well-typed
2554sample of the door. Otherwise, we fail.
2556 ++ fang :: protocol door
2557 |= [cof=cafe for=mark bek=beak]
2559 =+ pax=/door/[for]/mar
2563 =+ oak=[our %main %da now]
2564 ?. =(~ (ska %cy (tope [oak pax]))) oak
2566 (cope (fade cof %hook bem) abut:(meow bem ~))
2568A mark's definition is generally in
2569`/=main=/mar/[mark-name]/door/hook'. If we don't find it there, we look in`/[given-beak]/mar/[mark-name]/door/hook'.
2570We parse the mark definition with `++fade` and assemble it with
2571`++abut:meow`. `++fade` is defined under the `%bake` silk.
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list