| description | Parser rule builders for constructing parsing rules and modifying parser behavior. | |||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| layout |
|
Parser modifier: LSB ordered +list as $atom of a $base.
.wuc is an $atom.
.tyd is a $rule.
A $rule.
++ bass
|* [wuc=@ tyd=rule]
%+ cook
|= waq=(list @)
%+ roll
waq
=|([p=@ q=@] |.((add p (mul wuc q))))
tyd> (scan "123" (bass 10 (star dit)))
q=123
> (scan "123" (bass 8 (star dit)))
q=83
> `@ub`(scan "123" (bass 8 (star dit)))
0b101.0011
Parser modifier, LSB.
Ordered +list as $atom of a $base.
.wuc is an $atom.
.tyd is a $rule.
A $rule.
++ boss
|* [wuc=@ tyd=rule]
%+ cook
|= waq=(list @)
%+ reel
waq
=|([p=@ q=@] |.((add p (mul wuc q))))
tyd> (scan "123" (boss 10 (star dit)))
321
> `@t`(scan "bam" (boss 256 (star alp)))
'bam'
> `@ux`(scan "bam" (boss 256 (star alp)))
0x6d.6162
Replace with constant.
Parser modifier. Accepts a $rule .sef and produces a parser that produces a constant .cus, assuming .sef is successful.
.cus is a constant $noun.
.sef is a $rule.
An $edge.
++ cold
~/ %cold
|* [cus=* sef=rule]
~/ %fun
|= tub=nail
=+ vex=(sef tub)
?~ q.vex
vex
[p=p.vex q=[~ u=[p=cus q=q.u.q.vex]]]> ((cold %foo (just 'a')) [[1 1] "abc"])
[p=[p=1 q=2] q=[~ u=[p=%foo q=[p=[p=1 q=2] q="bc"]]]]
> ((cold %foo (just 'a')) [[1 1] "bc"])
[p=[p=1 q=1] q=~]
Apply gate.
Parser modifier. Produces a parser that takes a (successful) result of a $rule .sef and slams it through .poq.
.poq is a gate.
.sef is a $rule.
A $rule.
++ cook
~/ %cook
|* [poq=gate sef=rule]
~/ %fun
|= tub=nail
=+ vex=(sef tub)
?~ q.vex
vex
[p=p.vex q=[~ u=[p=(poq p.u.q.vex) q=q.u.q.vex]]]> ((cook ,@ud (just 'a')) [[1 1] "abc"])
[p=[p=1 q=2] q=[~ u=[p=97 q=[p=[p=1 q=2] q="bc"]]]]
> ((cook ,@tas (just 'a')) [[1 1] "abc"])
[p=[p=1 q=2] q=[~ u=[p=%a q=[p=[p=1 q=2] q="bc"]]]]
> ((cook |=(a=@ +(a)) (just 'a')) [[1 1] "abc"])
[p=[p=1 q=2] q=[~ u=[p=98 q=[p=[p=1 q=2] q="bc"]]]]
> ((cook |=(a=@ `@t`+(a)) (just 'a')) [[1 1] "abc"])
[p=[p=1 q=2] q=[~ u=[p='b' q=[p=[p=1 q=2] q="bc"]]]]
Always parse.
Parser generator. Produces a parser that succeeds with given $noun +huf without consuming any text.
.huf is a $noun.
A $rule.
++ easy
~/ %easy
|* huf=*
~/ %fun
|= tub=nail
^- (like _huf)
[p=p.tub q=[~ u=[p=huf q=tub]]]> ((easy %foo) [[1 1] "abc"])
[p=[p=1 q=1] q=[~ [p=%foo q=[p=[p=1 q=1] q="abc"]]]]
> ((easy %foo) [[1 1] "bc"])
[p=[p=1 q=1] q=[~ [p=%foo q=[p=[p=1 q=1] q="bc"]]]]
> ((easy 'a') [[1 1] "bc"])
[p=[p=1 q=1] q=[~ [p='a' q=[p=[p=1 q=1] q="bc"]]]]
Has A or B?
If string .sic is parsed: %.y. If string .non is parsed: %.n. Otherwise, fail.
.sic is a @t.
.non is a @t.
A $rule.
++ fuss
|= [sic=@t non=@t]
;~(pose (cold %& (jest sic)) (cold %| (jest non)))> (rash 'foo' (fuss 'foo' 'bar'))
%.y
> (rash 'bar' (fuss 'foo' 'bar'))
%.n
> (rash 'baz' (fuss 'foo' 'bar'))
{1 3}
syntax error
Parse to end.
Parser modifier. Accepts a $rule .sef, and produces a parser that succeeds only when the $tape of .tub is fully consumed using .sef.
.sef is a $rule.
A $rule.
++ full
|* sef=rule
|= tub=nail
=+ vex=(sef tub)
?~(q.vex vex ?:(=(~ q.q.u.q.vex) vex [p=p.vex q=~]))> ((full (just 'a')) [[1 1] "ab"])
[p=[p=1 q=2] q=~]
> ((full (jest 'ab')) [[1 1] "ab"])
[p=[p=1 q=3] q=[~ u=[p='ab' q=[p=[p=1 q=3] q=""]]]]
> ((full ;~(plug (just 'a') (just 'b'))) [[1 1] "ab"])
[p=[p=1 q=3] q=[~ u=[p=['a' 'b'] q=[p=[p=1 q=3] q=""]]]]
Add to tape.
Parser modifier: prepend text to $tape before applying parser.
.pre is a $tape.
.sef is a $rule.
A $rule.
++ funk
|* [pre=tape sef=rule]
|= tub=nail
(sef p.tub (weld pre q.tub))> ((funk "abc prefix-" (jest 'abc')) [[1 1] "to be parsed"])
[p=[p=1 q=4] q=[~ [p='abc' q=[p=[p=1 q=4] q=" prefix-to be parsed"]]]]
> ((funk "parse" (just 'a')) [[1 4] " me"])
[p=[p=1 q=4] q=~]
Place-based apply.
Parser modifier. Similar to +cook in that it produces a parser that takes a (successful) result of .sef and slams it through .hez. .hez accepts a $pint .a and a $noun .b, which is what the parser parsed.
.hez is a gate.
.sef is a $rule.
A $rule.
++ here
~/ %here
|* [hez=_|=([a=pint b=*] [a b]) sef=rule]
~/ %fun
|= tub=nail
=+ vex=(sef tub)
?~ q.vex
vex
[p=p.vex q=[~ u=[p=(hez [p.tub p.q.u.q.vex] p.u.q.vex) q=q.u.q.vex]]]> (scan "abc" (star alf))
"abc"
> (scan "abc" (here |*(^ +<) (star alf)))
[[[p=1 q=1] p=1 q=4] "abc"]
> (scan "abc" (star (here |*(^ +<) alf)))
~[[[[p=1 q=1] p=1 q=2] ~~a] [[[p=1 q=2] p=1 q=3] ~~b] [[[p=1 q=3] p=1 q=4] ~~c]]
Indentation block.
Apply $rule to a delimited, indented block starting at the current column number, omitting the leading whitespace.
.ope is a $rule matching the block's opening delimiter.
.end is a $rule matching the block's closing delimiter.
.sef is a $rule applied to the block's contents.
The first two are passed together as a cell, so the call shape is
(inde [ope end] sef).
A $rule.
++ inde
|* [[ope=rule end=rule] sef=rule]
|= tub=nail ^+ (sef)
=* har p.tub
=* tap q.tub
=+ lev=(fil 3 (dec q.har) ' ')
=+ eol=(just `@t`10)
=+ and=;~(plug eol (jest lev) end)
:: get block contents without the indenting spaces
::
=/ roq
%. tub
=/ led
;~ pose
;~(sfix eol (jest lev)) :: eat leading spaces
;~(simu ;~(plug eol eol) eol) :: allow empty lines
==
;~ pfix ope led
%- star
;~(less and ;~(pose prn led))
==
?~ q.roq roq
:: parse block contents fully
::
=+ vex=((full sef) har(q 1) p.u.q.roq)
:: indent hair, produce result, continue after block
::
=+ fur=p.vex(q (add (dec q.har) q.p.vex))
?~ q.vex vex(p fur)
=+ vux=(and p.roq q.q.u.q.roq)
?~ q.vux vux
[p.vux ~ p.u.q.vex q.u.q.vux]> `tape`(scan "\"\"\"\0afoo\0abar\0a\"\"\"" (inde [(jest '"""') (jest '"""')] (star ;~(pose prn (just `@`10)))))
"foo\0abar"
Note the amount of indentation whitespace to be stripped from the beginning of each line is determined by the value of .q (the column) in the $hair when +inde is first called. Additionally, the $rule given to +inde must consume the whole line including the line ending.
+inde previously took only .sef and was called as (inde sef), with the
indentation level established by a preceding +pfix. It was rewritten to take
explicit opening and closing delimiters; the one-argument call now fails to
compile with mull-grow / -find.sef. The kernel uses it this way to parse
""" block strings (see +quote-innards in sys/hoon.hoon).
Infix.
Parser modifier: surround with pair of $rules, the output of which is discarded.
.fel is a pair of $rules.
.hof is a $rule.
A $rule.
++ ifix
|* [fel=[rule rule] hof=rule]
~! +<
~! +<:-.fel
~! +<:+.fel
;~(pfix -.fel ;~(sfix hof +.fel))> (scan "-40-" (ifix [hep hep] dem))
40
> (scan "4my4" (ifix [dit dit] (star alf)))
"my"
Match a cord.
Match and consume a cord.
.daf is a @t.
A $rule.
++ jest
|= daf=@t
|= tub=nail
=+ fad=daf
|- ^- (like @t)
?: =(`@`0 daf)
[p=p.tub q=[~ u=[p=fad q=tub]]]
?: |(?=(~ q.tub) !=((end 3 daf) i.q.tub))
(fail tub)
$(p.tub (lust i.q.tub p.tub), q.tub t.q.tub, daf (rsh 3 daf))> ((jest 'abc') [[1 1] "abc"])
[p=[p=1 q=4] q=[~ [p='abc' q=[p=[p=1 q=4] q=""]]]]
> (scan "abc" (jest 'abc'))
'abc'
> (scan "abc" (jest 'acb'))
! {1 2}
! 'syntax-error'
! exit
> ((jest 'john doe') [[1 1] "john smith"])
[p=[p=1 q=6] q=~]
> ((jest 'john doe') [[1 1] "john doe"])
[p=[p=1 q=9] q=[~ [p='john doe' q=[p=[p=1 q=9] q=""]]]]
Match a char.
Match and consume a single character.
.daf is a $char
A $rule.
++ just
~/ %just
|= daf=char
~/ %fun
|= tub=nail
^- (like char)
?~ q.tub
(fail tub)
?. =(daf i.q.tub)
(fail tub)
(next tub)> ((just 'a') [[1 1] "abc"])
[p=[p=1 q=2] q=[~ [p='a' q=[p=[p=1 q=2] q="bc"]]]]
> (scan "abc" (just 'a'))
! {1 2}
! 'syntax-error'
! exit
> (scan "a" (just 'a'))
'a'
> (scan "%" (just '%'))
'%'
Recursive parsers.
Used for recursive parsers, which would otherwise be infinite when compiled.
+gar is a $noun.
.sef is a gate that accepts a $rule
A $rule.
++ knee
|* [gar=* sef=_|.(*rule)]
|= tub=nail
^- (like _gar)
((sef) tub)> |-(;~(plug prn ;~(pose $ (easy ~))))
! rest-loop
! exit
> |-(;~(plug prn ;~(pose (knee *tape |.(^$)) (easy ~))))
< 1.obo
[ c=c=tub=[p=[p=@ud q=@ud] q=""]
b
< 1.bes
[ c=tub=[p=[p=@ud q=@ud] q=""]
b=<1.tnv [tub=[p=[p=@ud q=@ud] q=""] <1.ktu [daf=@tD <414.fvk 101.jzo 1.ypj %164>]>]>
a=<1.fvg [tub=[p=[p=@ud q=@ud] q=""] <1.khu [[les=@ mos=@] <414.fvk 101.jzo 1.ypj %164>]>]>
v=<414.fvk 101.jzo 1.ypj %164>
]
>
a
... 450 lines omitted ...
]
>
> (scan "abcd" |-(;~(plug prn ;~(pose (knee *tape |.(^$)) (easy ~)))))
['a' "bcd"]
Match char.
Parser generator. Matches the next character if it is in a list of characters.
.bud is a list of $char.
A $rule.
++ mask
~/ %mask
|= bud=(list char)
~/ %fun
|= tub=nail
^- (like char)
?~ q.tub
(fail tub)
?. (lien bud |=(a=char =(i.q.tub a)))
(fail tub)
(next tub)> (scan "a" (mask "cba"))
'a'
> ((mask "abc") [[1 1] "abc"])
[p=[p=1 q=2] q=[~ [p='a' q=[p=[p=1 q=2] q="bc"]]]]
> ((mask "abc") [[1 1] "bbc"])
[p=[p=1 q=2] q=[~ [p='b' q=[p=[p=1 q=2] q="bc"]]]]
> ((mask "abc") [[1 1] "dbc"])
[p=[p=1 q=1] q=~]
Parse list with delimiter.
Parser modifier: Parse a list of matches using a delimiter $rule.
.bus is a $rule.
.fel is a $rule.
A $rule.
++ more
|* [bus=rule fel=rule]
;~(pose (most bus fel) (easy ~))> (scan "" (more ace dem))
~
> (scan "40 20" (more ace dem))
[40 [i=20 t=~]]
> (scan "40 20 60 1 5" (more ace dem))
[40 [i=20 t=~[60 1 5]]]
Parse list of at least one match.
Parser modifier: parse a +list of at least one match using a delimiter $rule.
.bus is a $rule.
.fel is a $rule.
A $rule.
++ most
|* [bus=rule fel=rule]
;~(plug fel (star ;~(pfix bus fel)))> (scan "40 20" (most ace dem))
[40 [i=20 t=~]]
> (scan "40 20 60 1 5" (most ace dem))
[40 [i=20 t=~[60 1 5]]]
> (scan "" (most ace dem))
! {1 1}
! exit
Consume char.
Consume any character, producing it as a result.
.tub is a $nail.
An $edge.
++ next
|= tub=nail
^- (like char)
?~ q.tub
(fail tub)
=+ zac=(lust i.q.tub p.tub)
[zac [~ i.q.tub [zac t.q.tub]]]> (next [[1 1] "ebc"])
[p=[p=1 q=2] q=[~ [p='e' q=[p=[p=1 q=2] q="bc"]]]]
> (next [[1 1] "john jumps jones"])
[p=[p=1 q=2] q=[~ [p='j' q=[p=[p=1 q=2] q="ohn jumps jones"]]]]
Parse cube fork.
Given .a, a list of @tas, match any one in the list and produce it. Note the list should not be a +list type, but just a null-terminated cell like ~[%foo %bar %baz]. The type produced will be a union of the items in the given list, so you can use a ?- expression on the output.
.a is a (pole @tas).
A $rule.
++ perk
|* a=(pole @tas)
?~ a fail
;~ pose
(cold -.a (jest -.a))
$(a +.a)
==> (scan "foo" (perk ~[%foo %bar]))
%foo
> (scan "bar" (perk ~[%foo %bar]))
%bar
> (scan "baz" (perk ~[%foo %bar]))
{1 3}
syntax error
List of at least one match.
Parser modifier: parse +list of at least one match.
.fel is a $rule.
A $rule.
++ plus |*(fel=rule ;~(plug fel (star fel))) ::> (scan ">>>>" (cook lent (plus gar)))
4
> (scan "- - " (plus ;~(pose ace hep)))
['-' [i=' ' t=~[' ' '-' ' ']]]
> `tape`(scan "- - " (plus ;~(pose ace hep)))
"- - "
> `(pole ,@t)`(scan "- - " (plus ;~(pose ace hep)))
['-' [' ' [' ' ['-' [' ' ~]]]]]
Unitized parse.
Either successfully apply $rule .a and produce a +unit of the result, or produce ~.
.a is a $rule.
A $rule.
++ punt |*([a=rule] ;~(pose (stag ~ a) (easy ~)))> ((punt (jest 'foo')) 1^1 "foo")
[p=[p=1 q=4] q=[~ u=[p=[~ 'foo'] q=[p=[p=1 q=4] q=~]]]]
> ((punt (jest 'foo')) 1^1 "bar")
[p=[p=1 q=1] q=[~ [p=~ q=[p=[p=1 q=1] q="bar"]]]]
Conditional +cook.
Conditional +cook. Slams the result through a gate that produces a unit; if that unit is empty, fail.
.pyq is a gate that produces a +unit.
.sef is a $rule.
A $rule.
++ sear
|* [pyq=$-(* (unit)) sef=rule]
|= tub=nail
=+ vex=(sef tub)
?~ q.vex
vex
=+ gey=(pyq p.u.q.vex)
?~ gey
[p=p.vex q=~]
[p=p.vex q=[~ u=[p=u.gey q=q.u.q.vex]]]> ((sear |=(a=* ?@(a (some a) ~)) (just 'a')) [[1 1] "abc"])
[p=[p=1 q=2] q=[~ u=[p=97 q=[p=[p=1 q=2] q="bc"]]]]
> ((sear |=(* ~) (just 'a')) [[1 1] "abc"])
[p=[p=1 q=2] q=~]
Char in range.
Match characters ($char) within a range.
.les is an $atom.
.mos is an $atom.
A $rule.
++ shim
~/ %shim
|= [les=@ mos=@]
~/ %fun
|= tub=nail
^- (like char)
?~ q.tub
(fail tub)
?. ?&((gte i.q.tub les) (lte i.q.tub mos))
(fail tub)
(next tub)> `tape`(rash 'abc' (plus (shim 'a' 'z')))
"abc"
> `tape`(rash 'ABC' (plus (shim 'a' 'z')))
{1 1}
syntax error
Use gate to parse delimited list.
Parser modifier: By composing with a gate, parse a delimited +list of matches.
.raq is a binary gate.
.bus is a $rule.
.fel is a $rule.
A $rule.
++ slug
|* raq=_=>(~ |*([a=* b=*] [a b]))
|* [bus=rule fel=rule]
;~((comp raq) fel (stir +<+.raq raq ;~(pfix bus fel)))> (scan "20+5+110" ((slug add) lus dem))
135
> `@t`(scan "a b c" ((slug |=(a=[@t @t] (cat 3 a))) ace alp))
'abc'
Add label.
Add a label to an $edge parsed by a $rule.
.gob is a $noun.
.sef is a rule.
A $rule.
++ stag
~/ %stag
|* [gob=* sef=rule]
~/ %fun
|= tub=nail
=+ vex=(sef tub)
?~ q.vex
vex
[p=p.vex q=[~ u=[p=[gob p.u.q.vex] q=q.u.q.vex]]]> (rash 'abc' (stag %foo (jest 'abc')))
[%foo 'abc']
List of matches.
Parser modifier: parse +list of matches.
.fel is a $rule.
A $rule.
++ star
|* fel=rule
(stir `(list _(wonk *fel))`~ |*([a=* b=*] [a b]) fel)> (scan "aaaaa" (just 'a'))
! {1 2}
! 'syntax-error'
! exit
> (scan "aaaaa" (star (just 'a')))
"aaaaa"
> (scan "abcdef" (star (just 'a')))
! {1 2}
! 'syntax-error'
! exit
> (scan "abcabc" (star (jest 'abc')))
<|abc abc|>
> (scan "john smith" (star (shim 0 200)))
"john smith"
Add faces.
Add faces [p q] to range-parser pairs in a list. Typically used in combination with +stew.
.leh is a list of range-parsers.
A (list [p=?(@ [@ @]) q=rule]).
++ stet
|* leh=(list [?(@ [@ @]) rule])
|-
?~ leh
~
[i=[p=-.i.leh q=+.i.leh] t=$(leh t.leh)]> =rule %- stew
%- stet
%- limo
:~
[['a' 'z'] (cook |=(a=@ (sub a 32)) alp)]
[['A' 'Z'] (cook |=(a=@ (add a 32)) alp)]
==
> `tape`(rash 'fooBARbaz' (star rule))
"FOObarBAZ"
Switch by first char.
Parser generator. From an associative +list of characters or character ranges to $rules, construct a +map, and parse $tapes only with $rules associated with a range that the $tape's first character falls in.
.leh is a (list [p=?(@ [@ @]) q=rule]), where .p is a $char or $char range.
A $rule.
++ stew :: switch by first char
~/ %stew
|* 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 :: build parser map
=+ hel=`(tree _?>(?=(^ leh) i.leh))`~
|- ^+ hel
?~ leh
~
=+ yal=$(leh t.leh)
|- ^+ hel
?~ yal
[i.leh ~ ~]
?: (wor p.i.leh p.n.yal)
=+ nuc=$(yal l.yal)
?> ?=(^ nuc)
?: (mor p.n.yal p.n.nuc)
[n.yal nuc r.yal]
[n.nuc l.nuc [n.yal r.nuc r.yal]]
=+ nuc=$(yal r.yal)
?> ?=(^ nuc)
?: (mor p.n.yal p.n.nuc)
[n.yal l.yal nuc]
[n.nuc [n.yal l.yal l.nuc] r.nuc]
~% %fun ..^$ ~
|= tub=nail
?~ q.tub
(fail tub)
|-
?~ hel
(fail tub)
?: ?@ p.n.hel
=(p.n.hel i.q.tub)
?&((gte i.q.tub -.p.n.hel) (lte i.q.tub +.p.n.hel))
:: (q.n.hel [(lust i.q.tub p.tub) t.q.tub])
(q.n.hel tub)
?: (wor i.q.tub p.n.hel)
$(hel l.hel)
$(hel r.hel)> =rule %- stew
%- stet
%- limo
:~
[['a' 'z'] (cook |=(a=@ (sub a 32)) alp)]
[['A' 'Z'] (cook |=(a=@ (add a 32)) alp)]
==
> `tape`(rash 'fooBARbaz' (star rule))
"FOObarBAZ"
Parse repeatedly.
Parse with $rule as many times as possible, and fold over results with a binary gate.
.rud is a $noun.
.raq is a gate that takes two $nouns and produces a cell.
.fel is a $rule.
A $rule.
++ stir
~/ %stir
|* [rud=* raq=_=>(~ |*([a=* b=*] [a b])) fel=rule]
~/ %fun
|= tub=nail
^- (like _rud)
::
:: lef: successful interim parse results (per .fel)
:: wag: initial accumulator (.rud in .tub at farthest success)
::
=+ ^= [lef wag]
=| lef=(list _(fel tub))
|- ^- [_lef (pair hair [~ u=(pair _rud nail)])]
=+ vex=(fel tub)
?~ q.vex
:- lef
[p.vex [~ rud tub]]
$(lef [vex lef], tub q.u.q.vex)
::
:: fold .lef into .wag, combining results with .raq
::
%+ roll lef
|= _[vex=(fel tub) wag=wag] :: q.vex is always (some)
^+ wag
:- (last p.vex p.wag)
[~ (raq p.u.+.q.vex p.u.q.wag) q.u.q.wag]> (scan "abc" (stir *@ add prn))
294
> (roll "abc" add)
294
Parse several times.
Parse bounded number of times.
.lig is a cell of $atoms ([@ @]) indicating the bounds.
.fel is a $rule.
A $rule.
++ stun
~/ %stun
|* [lig=[@ @] fel=rule]
|= tub=nail
^- (like (list _(wonk (fel))))
?: =(0 +.lig)
[p.tub [~ ~ tub]]
=+ vex=(fel tub)
?~ q.vex
?: =(0 -.lig)
[p.vex [~ ~ tub]]
vex
=+ ^= wag %= $
-.lig ?:(=(0 -.lig) 0 (dec -.lig))
+.lig ?:(=(0 +.lig) 0 (dec +.lig))
tub q.u.q.vex
==
?~ q.wag
wag
[p.wag [~ [p.u.q.vex p.u.q.wag] q.u.q.wag]]> ((stun [5 10] prn) [1 1] "aquickbrownfoxran")
[p=[p=1 q=11] q=[~ [p="aquickbrow" q=[p=[p=1 q=11] q="nfoxran"]]]]
> ((stun [5 10] prn) [1 1] "aquickbro")
[p=[p=1 q=10] q=[~ [p="aquickbro" q=[p=[p=1 q=10] q=""]]]]
> ((stun [5 10] prn) [1 1] "aqui")
[p=[p=1 q=5] q=~]