mirror of
https://github.com/jackfoxy/urQL.git
synced 2024-08-16 23:30:51 +03:00
support multi-line comments
This commit is contained in:
parent
89d0d8c76f
commit
827338daca
@ -1,4 +1,5 @@
|
||||
/- ast
|
||||
/+ regex
|
||||
!:
|
||||
:: a library for parsing urQL tapes
|
||||
:: (parse:parse(default-database '<db>') "<script>")
|
||||
@ -6,8 +7,9 @@
|
||||
::
|
||||
:: +parse: parse urQL script, emitting list of high level AST structures
|
||||
++ parse
|
||||
|= script=tape
|
||||
|= raw-script=tape
|
||||
^- (list command:ast)
|
||||
=/ script=tape (gsub:regex "\\/\\*[^\\*]*\\*\\/" ~ raw-script) :: multiline comments
|
||||
=/ commands `(list command:ast)`~
|
||||
=/ script-length (lent script)
|
||||
=/ displacement 0
|
||||
|
798
urql/lib/regex.hoon
Normal file
798
urql/lib/regex.hoon
Normal file
@ -0,0 +1,798 @@
|
||||
=>
|
||||
|%
|
||||
+$ range (pair pint tape)
|
||||
+$ match (map @u range)
|
||||
--
|
||||
=<
|
||||
|%
|
||||
::
|
||||
:: This outer core represents the main interface for executing regular
|
||||
:: expressions. Most of its arms produce a +$range (a tape annotated
|
||||
:: with location data) or a +$match (a map from capture numbers to
|
||||
:: +$range). These functions should serve your basic purposes, but for
|
||||
:: more complex operations you may use the inner core ++on (see below).
|
||||
::
|
||||
++ valid :: Determine if a regular expression is valid
|
||||
|= [regex=tape] ^- ?
|
||||
!=(~ (purse:on regex))
|
||||
::
|
||||
++ run :: Find the first match of a pattern in a subject
|
||||
|= [regex=tape text=tape] ^- (unit match)
|
||||
=+ pan=(parse:on regex)
|
||||
=+ ini=(init:on text)
|
||||
|-
|
||||
=+ sat=(long:on (pan ini))
|
||||
?~ sat
|
||||
?~ q.tub.ini ~
|
||||
$(ini (skip:on ini))
|
||||
`gru.u.sat
|
||||
::
|
||||
++ ran :: Find the first match; crash if there is none
|
||||
|= [regex=tape text=tape] ^- match
|
||||
=+ mat=(run regex text)
|
||||
?~(mat !! u.mat)
|
||||
::
|
||||
++ rut :: Find the text of the first match
|
||||
|= [regex=tape text=tape] ^- (unit range)
|
||||
=+ mat=(run regex text)
|
||||
?~(mat ~ `(~(got by u.mat) 0))
|
||||
::
|
||||
++ rat :: Find the text of the first match; crash if there is none
|
||||
|= [regex=tape text=tape] ^- range
|
||||
=+ mat=(ran regex text)
|
||||
(~(got by mat) 0)
|
||||
::
|
||||
++ all :: Find all non-empty, non-overlapping matches
|
||||
|= [regex=tape text=tape] ^- (list match)
|
||||
=+ pan=(parse:on regex)
|
||||
=+ ini=(init:on text)
|
||||
=+ lis=`(list match)`~
|
||||
|-
|
||||
=+ sat=(long:on (pan ini))
|
||||
?~ sat
|
||||
?~ q.tub.ini (flop lis)
|
||||
$(ini (skip:on ini))
|
||||
?: =(p.tub.ini p.tub.u.sat)
|
||||
?~ q.tub.ini (flop lis)
|
||||
$(ini (skip:on ini))
|
||||
$(ini u.sat(gru ~), lis [gru.u.sat lis])
|
||||
::
|
||||
++ alt :: Find the text of all non-empty, non-overlapping matches
|
||||
|= [regex=tape text=tape] ^- (list range)
|
||||
%+ turn (all regex text)
|
||||
|= [mat=match] (~(got by mat) 0)
|
||||
::
|
||||
++ is :: If regex validates text, produces nil; otherwise, produces
|
||||
:: the location of the first non-matching character
|
||||
|= [regex=tape text=tape] ^- (unit hair)
|
||||
=+ pan=(parse:on regex)
|
||||
=+ ini=(init:on text)
|
||||
|-
|
||||
?~ q.tub.ini ~
|
||||
=+ sat=(long:on (pan ini))
|
||||
?~ sat `p.tub.ini
|
||||
$(ini u.sat(gru ~))
|
||||
::
|
||||
++ as :: Produce nil, crashing if regex does not validate text
|
||||
|= [regex=tape text=tape] ^- ~
|
||||
?~((is regex text) ~ !!)
|
||||
::
|
||||
++ has :: Determine whether a pattern has a match
|
||||
|= [regex=tape text=tape] ^- ?
|
||||
?~ (run regex text)
|
||||
%.n
|
||||
%.y
|
||||
::
|
||||
++ from :: Find the next match after a certain point
|
||||
|= [regex=tape where=hair text=tape] ^- (unit match)
|
||||
=+ pan=(parse:on regex)
|
||||
=+ ini=(init:on text)
|
||||
|-
|
||||
?: (past:of p.tub.ini where)
|
||||
?~ q.tub.ini ~
|
||||
$(ini (skip:on ini))
|
||||
|-
|
||||
=+ sat=(long:on (pan ini))
|
||||
?~ sat
|
||||
?~ q.tub.ini ~
|
||||
$(ini (skip:on ini))
|
||||
`gru.u.sat
|
||||
::
|
||||
++ fort :: Find the text of the next match after a certain point
|
||||
|= [regex=tape where=hair text=tape] ^- (unit range)
|
||||
=+ mat=(from regex where text)
|
||||
?~(mat ~ `(~(got by u.mat) 0))
|
||||
::
|
||||
++ sub :: Replace the first match with a string
|
||||
|= [regex=tape repl=tape text=tape] ^- tape
|
||||
(subf regex |=(* repl) text)
|
||||
::
|
||||
++ gsub :: Replace all matches with a string
|
||||
|= [regex=tape repl=tape text=tape] ^- tape
|
||||
(gsubf regex |=(* repl) text)
|
||||
::
|
||||
++ subf :: Replace the first match by a function
|
||||
|= [regex=tape repl=$-(tape tape) text=tape] ^- tape
|
||||
=+ mat=(rut regex text)
|
||||
?~ mat text
|
||||
%+ weld q:(lant:of p.p.u.mat [[1 1] text])
|
||||
%+ weld (repl q.u.mat)
|
||||
q:(whet:of q.p.u.mat [[1 1] text])
|
||||
::
|
||||
++ gsubf :: Replace all matches by a function
|
||||
|= [regex=tape repl=$-(tape tape) text=tape] ^- tape
|
||||
=+ lis=(alt regex text)
|
||||
=+ tub=`nail`[[1 1] text]
|
||||
|- ^- tape
|
||||
?~ lis q.tub
|
||||
%+ weld q:(lant:of p.p.i.lis tub)
|
||||
%+ weld (repl q.i.lis)
|
||||
$(tub (whet:of q.p.i.lis tub), lis t.lis)
|
||||
--
|
||||
::
|
||||
|% :: Internal operations
|
||||
::
|
||||
:: Patterns are construed as a function that produces a promise-based
|
||||
:: stream of successive matches. This function accepts a +$state which
|
||||
:: is somewhat more complex than a tape; the ++on core is used for
|
||||
:: creating and operating on these states and patterns.
|
||||
::
|
||||
:: Applying a pattern to a match state produces a +$promise, which is a
|
||||
:: trap producing a +$product. +$product is either nil or a tuple,
|
||||
:: containing the state of the next match that was detected, alongside
|
||||
:: another promise that will produce the next +$product. The first
|
||||
:: match state is not necessarily the correct match; use ++long:on to
|
||||
:: extract the leftmost-longest match from a promise, according to
|
||||
:: Posix rules.
|
||||
::
|
||||
:: ++parse:of is the main entry point for creating patterns, but it
|
||||
:: needs an appropriate sample constructed by ++start:of; this logic
|
||||
:: is handled by ++parse:on.
|
||||
::
|
||||
:: When using patterns directly, remember that they only match text
|
||||
:: beginning at the given state. Use ++init:on and ++skip:on to test
|
||||
:: matches downstream in the subject text.
|
||||
::
|
||||
+$ state
|
||||
$: tub=nail :: Remaining text to be matched
|
||||
las=(unit @t) :: The previous character in the subject text
|
||||
gru=match :: Capture groups that have been matched so far
|
||||
==
|
||||
+$ product (unit (pair state promise))
|
||||
+$ promise _^&(|.(`(unit (pair state _^&(.)))``[*state .]))
|
||||
+$ pattern _^|(|=(state *promise))
|
||||
::
|
||||
++ on :: Basic operations on patterns and states
|
||||
|%
|
||||
++ parse :: Parse regex string
|
||||
|= [regex=tape] ^- pattern
|
||||
parse:(start:of regex)
|
||||
::
|
||||
++ purse :: Unitized parse
|
||||
|= [regex=tape] ^- (unit pattern)
|
||||
purse:(start:of regex)
|
||||
::
|
||||
++ init :: Create an initial state for subject text
|
||||
|= [sut=tape] ^- state
|
||||
=| sat=state
|
||||
%= sat
|
||||
tub [[1 1] sut]
|
||||
gru ~
|
||||
==
|
||||
::
|
||||
++ skip :: Advance a state's subject text by one character
|
||||
|= [sat=state] ^- state
|
||||
?~ q.tub.sat sat
|
||||
sat(tub (skip:of tub.sat), las `i.q.tub.sat)
|
||||
::
|
||||
++ long :: Get the leftmost-longest match from a promise
|
||||
|= [per=promise] ^- (unit state)
|
||||
=+ pro=(per)
|
||||
?~ pro ~
|
||||
=+ sat=p.u.pro
|
||||
=. per q.u.pro
|
||||
|- ^- (unit state)
|
||||
=+ pro=`product`(per)
|
||||
?~ pro `sat
|
||||
%= $
|
||||
per q.u.pro
|
||||
sat =| n=@ud
|
||||
=/ lim=@ud
|
||||
.+ %+ max
|
||||
(roll ~(tap in ~(key by gru.sat)) max)
|
||||
(roll ~(tap in ~(key by gru.p.u.pro)) max)
|
||||
|-
|
||||
?: =(n lim) sat
|
||||
=+ a=(~(get by gru.sat) n)
|
||||
?~ a
|
||||
?: (~(has by gru.p.u.pro) n)
|
||||
p.u.pro
|
||||
$(n +(n))
|
||||
=+ b=(~(get by gru.p.u.pro) n)
|
||||
?~ b sat
|
||||
?: (past:of p.p.u.a p.p.u.b) sat
|
||||
?: (past:of p.p.u.b p.p.u.a) p.u.pro
|
||||
?: (past:of q.p.u.a q.p.u.b) p.u.pro
|
||||
?: (past:of q.p.u.b q.p.u.a) sat
|
||||
$(n +(n))
|
||||
==
|
||||
--
|
||||
::
|
||||
++ of :: Pattern parsing operations
|
||||
::
|
||||
:: Parsing is done by constructing an initial sample with ++start
|
||||
:: and evaluating the ++parse arm. ++parse begins at the top level
|
||||
:: with ++top, making reference to the middle level ++mid and the
|
||||
:: bottom level ++bot, which recurs back to ++top in the case of
|
||||
:: capture groups.
|
||||
::
|
||||
:: The least tightly-binding regex operator is |, but there is also
|
||||
:: the case-sensitivity operator (?i), which is effective beyond
|
||||
:: subsequent | operators but not outside an enclosing group of ().
|
||||
:: Because (?i) can occur in the middle of an alternated pattern,
|
||||
:: like "a|b(?i)c|d", we parse the top level into a list of lists,
|
||||
:: then join the ends of these lists together by catenation into a
|
||||
:: flat list, which is then joined by alternation.
|
||||
::
|
||||
:: "a|b(?i)c|d" -> {(a or b), ([Cc] or [Dd])}
|
||||
:: -> (a or b[Cc] or [Dd]}
|
||||
::
|
||||
:: The middle level of parsing handles catenated sequences; for
|
||||
:: example "a(bcd)*e" is a sequence of three bottom-level regexes:
|
||||
:: a, (bcd)*, and e. The bottom level of parsing handles everything
|
||||
:: else (characters, anchors, capture groups, etc) with optional
|
||||
:: repetition. Capture groups recur to the top level, containing
|
||||
:: the effects of any case-sensitivity operators.
|
||||
::
|
||||
|_ $: reg=tape :: The pattern being parsed
|
||||
cas=? :: Are we parsing a case-sensitive pattern?
|
||||
arp=? :: Will a `)` in the pattern match literally?
|
||||
==
|
||||
++ start
|
||||
|= [regex=tape] ^- _..start
|
||||
..start(reg regex)
|
||||
++ parse ^- pattern
|
||||
(capt 0 (scan reg top))
|
||||
++ purse ^- (unit pattern)
|
||||
=+ pan=(rust reg top)
|
||||
?~ pan ~
|
||||
`(capt 0 u.pan)
|
||||
::
|
||||
+$ posix
|
||||
$: neg=?
|
||||
$? %ascii %alpha %alnum %blank
|
||||
%cntrl %digit %graph %lower
|
||||
%print %punct %space %upper
|
||||
%word %xdigit
|
||||
==
|
||||
==
|
||||
::
|
||||
++ skip :: Advance a nail by one character
|
||||
|= [tub=nail] ^- nail
|
||||
?~ q.tub tub
|
||||
[(lust i.q.tub p.tub) t.q.tub]
|
||||
::
|
||||
++ none :: Promise that produces nothing
|
||||
^& |. `(unit (pair state _^&(.)))`~
|
||||
::
|
||||
++ once :: Empty pattern (matches "" once)
|
||||
^- pattern
|
||||
|= [sat=state] `promise`|.(`[sat none])
|
||||
::
|
||||
++ cont :: Combine two patterns sequentially
|
||||
|= [pan=pattern pun=pattern] ^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
=+ per=(pan sat)
|
||||
|. ^- product
|
||||
=+ for=(per)
|
||||
?~ for ~
|
||||
=+ mid=(pun p.u.for)
|
||||
|- ^- product
|
||||
=+ aft=(mid)
|
||||
?~ aft ^$(per q.u.for)
|
||||
`[p.u.aft ..$(mid q.u.aft)]
|
||||
::
|
||||
++ fork :: Combine two patterns alternatively
|
||||
|= [pan=pattern pun=pattern] ^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
=+ per=(pan sat)
|
||||
|. ^- product
|
||||
=+ pro=(per)
|
||||
?~ pro ((pun sat))
|
||||
`[p.u.pro ..$(per q.u.pro)]
|
||||
::
|
||||
++ some :: Repeat a pattern
|
||||
|= [pan=pattern lo=@u hi=(unit @u)] ^- pattern
|
||||
=| n=@u
|
||||
|- ^- pattern
|
||||
?: =(lo n)
|
||||
?~(hi (many pan) (much pan (sub u.hi lo)))
|
||||
(cont pan $(n +(n)))
|
||||
::
|
||||
++ much :: Repeat a pattern, bounded
|
||||
|= [pan=pattern hi=@u] ^- pattern
|
||||
=| n=@u
|
||||
|- ^- pattern
|
||||
?: =(hi n) once
|
||||
(cont (fork pan once) $(n +(n)))
|
||||
::
|
||||
++ many :: Repeat a pattern, unbounded
|
||||
|= [pan=pattern] ^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
=+ per=(pan sat)
|
||||
|. ^- product
|
||||
=+ for=(per)
|
||||
?~ for `[sat none]
|
||||
?: =(p.tub.sat p.tub.p.u.for)
|
||||
`[p.u.for ..$(per q.u.for)]
|
||||
=+ mid=^$(sat p.u.for)
|
||||
|- ^- product
|
||||
=+ aft=(mid)
|
||||
?~ aft `[p.u.for ..^$(per q.u.for)]
|
||||
`[p.u.aft ..$(mid q.u.aft)]
|
||||
++ text :: Create a pattern that matches literal text
|
||||
|= [tet=tape] ^- pattern
|
||||
?: cas
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?~ tet `[sat none]
|
||||
?~ q.tub.sat ~
|
||||
?. =(i.tet i.q.tub.sat) ~
|
||||
$(tet t.tet, sat (skip:on sat))
|
||||
=. tet (cass tet)
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?~ tet `[sat none]
|
||||
?~ q.tub.sat ~
|
||||
?. .= i.tet
|
||||
?: &((gte i.q.tub.sat 'A') (lte i.q.tub.sat 'Z'))
|
||||
(add i.q.tub.sat 32)
|
||||
i.q.tub.sat
|
||||
~
|
||||
$(tet t.tet, sat (skip:on sat))
|
||||
++ capt :: Capture a pattern's matched text
|
||||
|= [n=@u pan=pattern] ^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
=+ per=(pan sat)
|
||||
|.
|
||||
=+ pro=(per)
|
||||
?~ pro ~
|
||||
:+ ~
|
||||
%= p.u.pro
|
||||
gru
|
||||
%- ~(put by gru.p.u.pro)
|
||||
:+ n [p.tub.sat p.tub.p.u.pro]
|
||||
q:(lant p.tub.p.u.pro tub.sat)
|
||||
==
|
||||
..$(per q.u.pro)
|
||||
++ back :: Create a backreference pattern
|
||||
|= [n=@u] ^- pattern
|
||||
|= [sat=state]
|
||||
=+ mat=(~(get by gru.sat) n)
|
||||
?~ mat none
|
||||
((text q.u.mat) sat)
|
||||
::
|
||||
::
|
||||
:: Helper functions
|
||||
::
|
||||
++ rant
|
||||
:: Determine if an atom is in a certain range
|
||||
|= [n=@ lo=@ hi=@]
|
||||
&((gte n lo) (lte n hi))
|
||||
++ past
|
||||
:: Determine whether hair `b` comes after hair `a`
|
||||
|= [a=hair b=hair] ^- ?
|
||||
?| (lth p.a p.b)
|
||||
&(=(p.a p.b) (lth q.a q.b))
|
||||
==
|
||||
++ prev
|
||||
:: Get the last character before a certain point
|
||||
|= [har=hair tub=nail] ^- (unit @t)
|
||||
?~ q.tub ~
|
||||
?. (past p.tub har) ~
|
||||
=+ c=i.q.tub
|
||||
%. tub
|
||||
|= [tub=nail]
|
||||
?. (past p.tub har) `c
|
||||
?~ q.tub `c
|
||||
$(c i.q.tub, tub (skip tub))
|
||||
++ lant :: Get the text of a nail up to a certain hair
|
||||
|= [wer=hair tub=nail] ^- nail
|
||||
:- p.tub
|
||||
=+ beh=""
|
||||
|-
|
||||
?~ q.tub (flop beh)
|
||||
?. (past p.tub wer) (flop beh)
|
||||
$(tub (skip tub), beh [i.q.tub beh])
|
||||
++ whet :: Get the text of a nail after a certain heir
|
||||
|= [wer=hair tub=nail] ^- nail
|
||||
?. (past p.tub wer) tub
|
||||
$(tub (skip tub))
|
||||
++ bond :: Determine if a state is at a word boundary
|
||||
|= [sat=state] ^- ?
|
||||
?~ las.sat
|
||||
?~ q.tub.sat %.n
|
||||
(memb i.q.tub.sat [| %word])
|
||||
?~ q.tub.sat (memb u.las.sat [| %word])
|
||||
?! .=
|
||||
(memb i.q.tub.sat [| %word])
|
||||
(memb u.las.sat [| %word])
|
||||
++ left :: Determine if a state is at the beginning of a word
|
||||
|= [sat=state] ^- ?
|
||||
?~ q.tub.sat %.n
|
||||
?& (memb i.q.tub.sat [| %word])
|
||||
|(?=(~ las.sat) (memb u.las.sat [& %word]))
|
||||
==
|
||||
++ rite :: Determine if a state is at the end of a word
|
||||
|= [sat=state] ^- ?
|
||||
?~ las.sat %.n
|
||||
?& (memb u.las.sat [| %word])
|
||||
|(?=(~ q.tub.sat) (memb i.q.tub.sat [& %word]))
|
||||
==
|
||||
++ what :: Determine a group's capture number by hair position
|
||||
|= [wer=hair] ^- @u
|
||||
=| n=@u
|
||||
=+ tub=`nail`[[1 1] reg]
|
||||
|^
|
||||
?. (past p.tub wer) n
|
||||
?~ q.tub n
|
||||
=+ vex=(non tub)
|
||||
?~ q.vex
|
||||
$(tub (skip tub), n ?:(=('(' i.q.tub) +(n) n))
|
||||
$(tub q.u.q.vex)
|
||||
++ non :: Skip over a non-capturing (?...) expression
|
||||
%+ knee *~
|
||||
|. ~+
|
||||
%+ cold ~
|
||||
;~(pose (ifix [(jest '(?') par] nom) cla)
|
||||
++ nom :: Skip over the contents of a non-capturing expression
|
||||
%+ knee *~
|
||||
|. ~+
|
||||
%+ cold ~
|
||||
;~ pose
|
||||
;~ plug
|
||||
;~ pose
|
||||
(ifix [pal par] nom)
|
||||
;~(plug bas next)
|
||||
;~(less (mask "\\()[") next)
|
||||
cla
|
||||
==
|
||||
::
|
||||
nom
|
||||
==
|
||||
::
|
||||
(easy ~)
|
||||
==
|
||||
--
|
||||
++ memb :: Determine if a character is a member of a POSIX class
|
||||
|= [=char =posix] ^- ?
|
||||
.= !neg.posix
|
||||
?- +.posix
|
||||
%ascii (rant char 0 127)
|
||||
%alnum ?| (rant char 'A' 'Z')
|
||||
(rant char 'a' 'z')
|
||||
(rant char '0' '9')
|
||||
==
|
||||
%alpha ?| (rant char 'A' 'Z')
|
||||
(rant char 'a' 'z')
|
||||
==
|
||||
%blank |(=(char ' ') =(char '\09'))
|
||||
%cntrl |((rant char '\00' '\1f') =(char '\7f'))
|
||||
%digit (rant char '0' '9')
|
||||
%graph (rant char '!' '~')
|
||||
%lower (rant char 'a' 'z')
|
||||
%print (rant char ' ' '~')
|
||||
%punct ?| (rant char '!' '/')
|
||||
(rant char ':' '@')
|
||||
(rant char '[' '`')
|
||||
(rant char '{' '~')
|
||||
==
|
||||
%space |(=(char ' ') (rant char '\09' '\0d'))
|
||||
%upper (rant char 'A' 'Z')
|
||||
%word ?| (rant char 'A' 'Z')
|
||||
(rant char 'a' 'z')
|
||||
(rant char '0' '9')
|
||||
=('_' char)
|
||||
==
|
||||
%xdigit ?| (rant char '0' '9')
|
||||
(rant char 'A' 'F')
|
||||
(rant char 'a' 'f')
|
||||
==
|
||||
==
|
||||
++ top :: Top-level parsing: alternation and regex mode
|
||||
%+ cook
|
||||
|= [lis=(lest (lest pattern))]
|
||||
=; end=(lest pattern)
|
||||
|- ^- pattern
|
||||
?~ t.end i.end
|
||||
(fork i.end $(end t.end))
|
||||
|- ^- (lest pattern)
|
||||
?~ t.lis i.lis
|
||||
=/ sal=(lest pattern) ?~(t.t.lis i.t.lis $(lis t.lis))
|
||||
|- ^- (lest pattern)
|
||||
?~ t.i.lis [(cont i.i.lis i.sal) t.sal]
|
||||
[i.i.lis $(i.lis t.i.lis)]
|
||||
|-
|
||||
%+ knee *(lest (lest pattern))
|
||||
|. ~+
|
||||
;~ plug
|
||||
(most bar mid)
|
||||
::
|
||||
;~ pose
|
||||
;~(pfix (jest '(?i)') %=(^$ cas %.n))
|
||||
;~(pfix (jest '(?-i)') %=(^$ cas %.y))
|
||||
(easy ~)
|
||||
==
|
||||
==
|
||||
++ mid :: Mid-level parsing: catenation
|
||||
%+ knee *pattern
|
||||
|. ~+
|
||||
;~ pose
|
||||
(cook cont ;~(plug ;~(pose str bot) mid))
|
||||
nil
|
||||
==
|
||||
++ bot :: Bottom-level parsing element
|
||||
%+ cook
|
||||
|= [pan=pattern ran=(unit [@u (unit @u)])]
|
||||
?~ ran pan
|
||||
(some pan u.ran)
|
||||
;~ plug
|
||||
;~ pose
|
||||
(cook text ;~(plug lit (easy ~))) :: literal or escaped character
|
||||
cap :: capture group
|
||||
bak :: backtrack
|
||||
cla :: character class
|
||||
ank :: control chars
|
||||
luk :: lookahead
|
||||
(cold any dot) :: match forward
|
||||
(cook text ;~(pfix bas ;~(plug next (easy ~)))) :: non-special escape
|
||||
==
|
||||
::
|
||||
(punt rep)
|
||||
==
|
||||
++ bak
|
||||
(cook back ;~(pfix bas dit))
|
||||
++ any ^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?~ q.tub.sat ~
|
||||
`[(skip:on sat) none]
|
||||
++ ank
|
||||
;~ pose
|
||||
%- cold :_ ket
|
||||
^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?~(las.sat `[sat none] ~)
|
||||
::
|
||||
%- cold :_ buc
|
||||
^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?~(q.tub.sat `[sat none] ~)
|
||||
::
|
||||
%- cold :_ (jest '\\b')
|
||||
^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?:((bond sat) `[sat none] ~)
|
||||
::
|
||||
%- cold :_ (jest '\\B')
|
||||
^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?:((bond sat) ~ `[sat none])
|
||||
::
|
||||
%- cold :_ (jest '\\<')
|
||||
^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?:((left sat) `[sat none] ~)
|
||||
::
|
||||
%- cold :_ (jest '\\>')
|
||||
^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?:((rite sat) `[sat none] ~)
|
||||
==
|
||||
++ nil :: Parse empty pattern
|
||||
(easy once)
|
||||
++ str :: Parse a long string of literal text
|
||||
(cook text (plus ;~(less ;~(sfix lit rep) lit)))
|
||||
++ lit ;~(pose cha esc)
|
||||
++ cha :: Literal character
|
||||
;~ less
|
||||
?: arp
|
||||
(mask "^$.|?+*([\{\\")
|
||||
(mask "^$.|?+*()[\{\\")
|
||||
::
|
||||
next
|
||||
==
|
||||
++ esc :: Escape code
|
||||
;~ pfix bas
|
||||
;~ pose
|
||||
%- sear :_ next
|
||||
%~ get by
|
||||
%- malt
|
||||
:~ ['a' '\07'] :: Bell
|
||||
['t' '\09'] :: Horizontal tab
|
||||
['n' '\0a'] :: Newline
|
||||
['v' '\0b'] :: Vertical tab
|
||||
['f' '\0c'] :: Form feed
|
||||
['r' '\0d'] :: Carriage return
|
||||
['e' '\1b'] :: Escape
|
||||
==
|
||||
::
|
||||
;~ pfix (jest 'x')
|
||||
%- cook :_ ;~(plug hit hit)
|
||||
|= [a=@u b=@u] ^- @t
|
||||
(add (mul 16 a) b)
|
||||
==
|
||||
::
|
||||
;~ pfix (jest '0')
|
||||
%- cook :_ ;~(plug cit cit cit)
|
||||
|= [a=@u b=@u c=@u] ^- @t
|
||||
(add (add (mul 64 a) (mul 8 b)) c)
|
||||
==
|
||||
::
|
||||
;~ pfix (jest 'c')
|
||||
%- cook :_ (shim '\00' '\7f')
|
||||
|= [c=@t]
|
||||
=. c ?:((rant c 'a' 'z') (sub c 32) c)
|
||||
?: =(0 (dis c '\40'))
|
||||
(add c '\40')
|
||||
(sub c '\40')
|
||||
==
|
||||
==
|
||||
==
|
||||
++ rep :: Repetition quantifier
|
||||
;~ pose
|
||||
(cold [0 `1] wut)
|
||||
(cold [0 ~] tar)
|
||||
(cold [1 ~] lus)
|
||||
::
|
||||
%+ ifix [kel ker]
|
||||
;~ pose
|
||||
;~(plug ;~(pose dem (easy 0)) ;~(pfix com (punt dem)))
|
||||
(cook |=(n=@u [n `n]) dem)
|
||||
==
|
||||
==
|
||||
++ cap :: Capture group
|
||||
%+ cook
|
||||
|= [wer=hair pan=pattern]
|
||||
(capt (what wer) pan)
|
||||
%+ ifix [pal par]
|
||||
;~ plug
|
||||
(here |=([a=pint *] p.a) (easy ~))
|
||||
top(arp %.n)
|
||||
==
|
||||
++ cla :: Character class
|
||||
|^
|
||||
%+ sear
|
||||
|= [neg=? lis=(list elem)] ^- (unit pattern)
|
||||
=* ok=(unit pattern) `(make neg lis)
|
||||
?: |-
|
||||
?~ lis %.y
|
||||
?@ i.lis $(lis t.lis)
|
||||
?^ +.i.lis $(lis t.lis)
|
||||
?: (lte -.i.lis +.i.lis) $(lis t.lis)
|
||||
%.n
|
||||
`(make neg lis)
|
||||
~
|
||||
;~ pose
|
||||
(cook |=(pos=[~ posix] [| ~[pos]]) ;~(less sel pec))
|
||||
(ifix [sel ser] ;~(plug (fuss '^' '') hed))
|
||||
==
|
||||
++ hed
|
||||
;~ pose
|
||||
;~ plug
|
||||
;~ less
|
||||
;~(pfix ser hep pec)
|
||||
;~(pfix ser hep cil hep ;~(pose pec cil))
|
||||
;~(pose ;~(plug ser ;~(pfix hep cil)) ser)
|
||||
==
|
||||
::
|
||||
tel
|
||||
==
|
||||
::
|
||||
tel
|
||||
==
|
||||
++ tel
|
||||
%+ knee *(list elem)
|
||||
|. ~+
|
||||
;~ pose
|
||||
;~ plug
|
||||
;~ pose
|
||||
;~(less ;~(pfix pec hep ;~(pose pec cil)) pec)
|
||||
::
|
||||
;~ less
|
||||
pec
|
||||
puc
|
||||
;~(pfix cil hep pec)
|
||||
;~(pfix cil hep cil hep ;~(pose pec cil))
|
||||
;~(pose ;~(plug cil ;~(pfix hep cil)) cil)
|
||||
==
|
||||
==
|
||||
::
|
||||
tel
|
||||
==
|
||||
::
|
||||
(easy ~)
|
||||
==
|
||||
++ cil :: Literal character for character classes
|
||||
;~(pose esc sec ;~(less bas ser next))
|
||||
++ sec :: Special escape character in this context
|
||||
;~(pose (cold '\08' (jest '\\b')) ;~(pfix bas next))
|
||||
+$ elem ?(@t [@t @t] [~ posix])
|
||||
++ make
|
||||
|= [neg=? lis=(list elem)] ^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?~ q.tub.sat ~
|
||||
?: .= neg
|
||||
|-
|
||||
?~ lis %.n
|
||||
?: (pass i.q.tub.sat i.lis) %.y
|
||||
$(lis t.lis)
|
||||
~
|
||||
`[sat(tub (skip tub.sat)) none]
|
||||
++ pass
|
||||
?: cas
|
||||
|= [=char =elem] ^- ?
|
||||
?- elem
|
||||
@ =(elem char)
|
||||
[@ @] &((lte -.elem char) (lte char +.elem))
|
||||
[~ posix] (memb char +.elem)
|
||||
==
|
||||
|= [=char =elem] ^- ?
|
||||
=+ p=pass(cas %.y)
|
||||
?| (p char elem)
|
||||
&((rant char 'A' 'Z') (p (add char 32) elem))
|
||||
&((rant char 'a' 'z') (p (sub char 32) elem))
|
||||
==
|
||||
++ pec :: Perl- or POSIX-style class
|
||||
;~ pose
|
||||
%- sear :_ ;~(pfix bas next)
|
||||
%~ get by ^- (map @t [~ posix])
|
||||
%- malt ^- (list [@t ~ posix])
|
||||
:~ ['d' `|^%digit] ['D' `&^%digit]
|
||||
['w' `|^%word] ['W' `&^%word]
|
||||
['s' `|^%space] ['S' `&^%space]
|
||||
['u' `|^%upper] ['U' `&^%upper]
|
||||
['l' `|^%lower] ['L' `&^%lower]
|
||||
==
|
||||
::
|
||||
%+ ifix [(jest '[:') (jest ':]')]
|
||||
;~ plug (easy ~) (fuss '^' '')
|
||||
%- perk
|
||||
:~ %ascii %alpha %alnum %blank
|
||||
%cntrl %digit %graph %lower
|
||||
%print %punct %space %upper
|
||||
%word %xdigit
|
||||
==
|
||||
==
|
||||
==
|
||||
++ puc :: Invalid POSIX-style class
|
||||
%+ ifix [(jest '[:') (jest ':]')]
|
||||
;~(plug (fuss '^' '') (star ;~(less col next)))
|
||||
--
|
||||
++ luk :: Lookahead, positive or negative
|
||||
;~ pose
|
||||
%+ ifix [(jest '(?=') par]
|
||||
%- cook :_ top(arp %.n)
|
||||
|= [pan=pattern] ^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?~ ((pan sat)) ~
|
||||
`[sat none]
|
||||
::
|
||||
%+ ifix [(jest '(?!') par]
|
||||
%- cook :_ top(arp %.n)
|
||||
|= [pan=pattern] ^- pattern
|
||||
|= [sat=state] ^- promise
|
||||
|. ^- product
|
||||
?~ ((pan sat)) `[sat none]
|
||||
~
|
||||
==
|
||||
--
|
||||
--
|
@ -2,14 +2,49 @@
|
||||
/+ parse, *test
|
||||
|%
|
||||
|
||||
++ m-cmnt-1
|
||||
"/* line1\0a line2 \0a line3\0a*/"
|
||||
|
||||
++ test-create-namespace-1
|
||||
=/ expected1 [%create-namespace database-name='other-db' name='my-namespace' as-of=~]
|
||||
=/ expected2 [%create-namespace database-name='my-db' name='another-namespace' as-of=~]
|
||||
++ m-cmnt-2
|
||||
"/* linea\0a lineb \0a linec */"
|
||||
|
||||
++ m-cmnt-3
|
||||
"/* linea1\0a lineb2 \0a linec3 */"
|
||||
|
||||
++ test-multiline-cmnt-00
|
||||
=/ expected1 [%create-namespace database-name='other-db' name='ns1' as-of=~]
|
||||
=/ expected2 [%create-namespace database-name='db1' name='db1-ns1' as-of=~]
|
||||
%+ expect-eq
|
||||
!> ~[expected1 expected2]
|
||||
!> (parse:parse(default-database 'other-db') "cReate\0d\09 namespace my-namespace ; cReate namesPace my-db.another-namespace")
|
||||
!> (parse:parse(default-database 'other-db') (zing (limo ~[m-cmnt-1 "cReate" m-cmnt-2 " namespace ns1\0a" " ; \0a" "cReate namesPace db1.db1-ns1\0a" m-cmnt-3])))
|
||||
|
||||
++ test-multiline-cmnt-01
|
||||
=/ expected1 [%create-namespace database-name='other-db' name='ns1' as-of=~]
|
||||
=/ expected2 [%create-namespace database-name='db1' name='db1-ns1' as-of=~]
|
||||
%+ expect-eq
|
||||
!> ~[expected1 expected2]
|
||||
!> (parse:parse(default-database 'other-db') (zing (limo ~["cReate\0a" m-cmnt-1 " namespace ns1\0a" m-cmnt-2 " ; \0a" m-cmnt-3 "cReate namesPace db1.db1-ns1\0a"])))
|
||||
|
||||
++ test-multiline-cmnt-02
|
||||
=/ expected1 [%create-namespace database-name='other-db' name='ns1' as-of=~]
|
||||
=/ expected2 [%create-namespace database-name='db1' name='db1-ns1' as-of=~]
|
||||
%+ expect-eq
|
||||
!> ~[expected1 expected2]
|
||||
!> (parse:parse(default-database 'other-db') (zing (limo ~[m-cmnt-1 "\0acReate\0a" " namespace ns1\0a" m-cmnt-2 m-cmnt-3 " ; \0a" "cReate namesPace db1.db1-ns1\0a"])))
|
||||
|
||||
++ test-multiline-cmnt-03
|
||||
=/ expected1 [%create-namespace database-name='other-db' name='ns1' as-of=~]
|
||||
=/ expected2 [%create-namespace database-name='db1' name='db1-ns1' as-of=~]
|
||||
%+ expect-eq
|
||||
!> ~[expected1 expected2]
|
||||
!> (parse:parse(default-database 'other-db') (zing (limo ~["cReate\0a" " namespace ns1\0a" m-cmnt-1 " ; \0a" m-cmnt-2 "cReate namesPace db1.db1-ns1\0a" m-cmnt-3])))
|
||||
|
||||
++ test-multiline-cmnt-04
|
||||
=/ expected1 [%create-namespace database-name='other-db' name='ns1' as-of=~]
|
||||
=/ expected2 [%create-namespace database-name='db1' name='db1-ns1' as-of=~]
|
||||
%+ expect-eq
|
||||
!> ~[expected1 expected2]
|
||||
!> (parse:parse(default-database 'other-db') (zing (limo ~["cReate\0a" " namespace ns1" m-cmnt-1 " ; " m-cmnt-2 "cReate namesPace db1.db1-ns1" m-cmnt-3])))
|
||||
|
||||
::@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
::
|
||||
|
@ -2369,4 +2369,43 @@
|
||||
!> ~[expected]
|
||||
!> (parse:parse(default-database 'db1') query)
|
||||
:: to do: tests for merge to new file
|
||||
::
|
||||
:: multiline comment
|
||||
::
|
||||
++ m-cmnt-1
|
||||
"/* line1\0a line2 \0a line3\0a*/"
|
||||
++ m-cmnt-2
|
||||
"/* linea\0a lineb \0a linec */"
|
||||
++ m-cmnt-3
|
||||
"/* linea1\0a lineb2 \0a linec3 */"
|
||||
++ test-multiline-cmnt-00
|
||||
=/ expected1 [%create-namespace database-name='other-db' name='ns1' as-of=~]
|
||||
=/ expected2 [%create-namespace database-name='db1' name='db1-ns1' as-of=~]
|
||||
%+ expect-eq
|
||||
!> ~[expected1 expected2]
|
||||
!> (parse:parse(default-database 'other-db') (zing (limo ~[m-cmnt-1 "cReate" m-cmnt-2 " namespace ns1\0a" " ; \0a" "cReate namesPace db1.db1-ns1\0a" m-cmnt-3])))
|
||||
++ test-multiline-cmnt-01
|
||||
=/ expected1 [%create-namespace database-name='other-db' name='ns1' as-of=~]
|
||||
=/ expected2 [%create-namespace database-name='db1' name='db1-ns1' as-of=~]
|
||||
%+ expect-eq
|
||||
!> ~[expected1 expected2]
|
||||
!> (parse:parse(default-database 'other-db') (zing (limo ~["cReate\0a" m-cmnt-1 " namespace ns1\0a" m-cmnt-2 " ; \0a" m-cmnt-3 "cReate namesPace db1.db1-ns1\0a"])))
|
||||
++ test-multiline-cmnt-02
|
||||
=/ expected1 [%create-namespace database-name='other-db' name='ns1' as-of=~]
|
||||
=/ expected2 [%create-namespace database-name='db1' name='db1-ns1' as-of=~]
|
||||
%+ expect-eq
|
||||
!> ~[expected1 expected2]
|
||||
!> (parse:parse(default-database 'other-db') (zing (limo ~[m-cmnt-1 "\0acReate\0a" " namespace ns1\0a" m-cmnt-2 m-cmnt-3 " ; \0a" "cReate namesPace db1.db1-ns1\0a"])))
|
||||
++ test-multiline-cmnt-03
|
||||
=/ expected1 [%create-namespace database-name='other-db' name='ns1' as-of=~]
|
||||
=/ expected2 [%create-namespace database-name='db1' name='db1-ns1' as-of=~]
|
||||
%+ expect-eq
|
||||
!> ~[expected1 expected2]
|
||||
!> (parse:parse(default-database 'other-db') (zing (limo ~["cReate\0a" " namespace ns1\0a" m-cmnt-1 " ; \0a" m-cmnt-2 "cReate namesPace db1.db1-ns1\0a" m-cmnt-3])))
|
||||
++ test-multiline-cmnt-04
|
||||
=/ expected1 [%create-namespace database-name='other-db' name='ns1' as-of=~]
|
||||
=/ expected2 [%create-namespace database-name='db1' name='db1-ns1' as-of=~]
|
||||
%+ expect-eq
|
||||
!> ~[expected1 expected2]
|
||||
!> (parse:parse(default-database 'other-db') (zing (limo ~["cReate\0a" " namespace ns1" m-cmnt-1 " ; " m-cmnt-2 "cReate namesPace db1.db1-ns1" m-cmnt-3])))
|
||||
--
|
Loading…
Reference in New Issue
Block a user