Hello --

Using BaseX 9.6.1 on Linux.

So I'm trying to convert a compact-ish element pattern string, delimited with braces, back into something that looks like XML vocabulary for readability.  (The pattern strings are being used to detect similar structure in the content set.)

The test query (below) works fine.

Stick the functions in a module namespace, and run the real content, and I get the "Stack Overflow: Try tail recursion?" error.  (Query plan for this case attached.)

Nothing in the real data should be all that large.  I suspect I'm being too clever for my own good somehow, but if anyone can tell me specifically where I'd appreciate it.

Thanks!
Graydon

======

declare namespace fn = "http://www.w3.org/2005/xpath-functions";

declare variable $NMToken as xs:string := '[\p{L}\p{Nd}._\-:]+';

declare function local:tag($names as xs:string*,$active as xs:string*,$event as xs:string*) {

  let $do as xs:string := substring($event,1,1)
 
  return
    if (not(normalize-space($do)))
  then ()
  else if ($do eq '{')
      then (concat('<',head($names),'>'), local:tag(tail($names),(head($names),$active),substring($event,2)))
      else (concat('</',head($active),'>'), local:tag($names,tail($active),substring($event,2)))
};

declare function local:emitPattern($in as xs:string) as xs:string {

  let $chunked as element(fn:analyze-string-result) := analyze-string($in,$NMToken)
  let $names as xs:string+ := $chunked/fn:match/string()
  let $openClose as xs:string+ := $chunked/fn:non-match => string-join()
 
  return string-join(local:tag($names,(),$openClose))
};

let $pattern as xs:string := "{subblock{sublabel}{p}}"
let $yikes as xs:string := "{primaryblock{shortdesc}{table{title}{tgroup{colspec}{colspec}{colspec}{thead{row{entry{p}}{entry{p}}{entry{p}}}}{tbody{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p{xref}{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}{xref}{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}{xref}{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}{xref}}}{entry{p}}}{row{entry{p}}{entry{p}}{entry{p}}}{row{entry{p}}{entry{p}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p{xref}{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}}}}{note{p}}}"

return ($pattern,$yikes) ! local:emitPattern(.)