[mod] ast

This commit is contained in:
Andy Bunce 2025-10-27 15:05:47 +00:00
parent e732d190e1
commit 0d80764174
9 changed files with 79 additions and 8 deletions

56
webapp/lsp/ast/ast.xqm Normal file
View file

@ -0,0 +1,56 @@
(: Abstract syntax tree
@author Andy Bunce
:)
module namespace ast="lsp/ast";
(: import module namespace p="xq4" at "xq4.xqm"; :)
import module namespace xq4="java:quodatum.parser.xq4";
(:~ build :)
declare function ast:build($text as xs:string,$uri as xs:string:="")
as element(*){
let $xml:= xq4:parseModule($text)=>prof:time("⏱️ p:parse-Module " || $uri)
return ($xml,
message(ast:report($xml),"REP"),
message(ast:report(ast:flatten($xml)),"flat")
)
};
(:~
:concrete to abstract: simplify by omitting elements with only one child
:)
declare function ast:flatten($input as element()) as element() {
if (1=count($input/*)) then ast:flatten($input/*)
else element {node-name($input) }
{$input/@*,
for $child in $input/node()
return
if ($child instance of element())
then ast:flatten($child)
else $child
}
};
(:-------------------------------------------:)
declare function ast:report($el as element(*)) {
<analysis>
<total-elements>{count($el//element())}</total-elements>
<max-depth>{ast:max-node-depth($el)}</max-depth>
</analysis>
};
declare function ast:max-depth($nodes as node()*) as xs:integer {
if (empty($nodes)) then 0
else
max((
for $node in $nodes
return
if ($node instance of element())
then ast:max-depth($node/node()) + 1
else ast:max-depth($node/node())
))
};
declare function ast:max-node-depth($root as node()) as xs:integer {
ast:max-depth($root)
};

View file

@ -4,11 +4,10 @@
@author Andy Bunce
:)
module namespace docs="lsp/docs";
(: import module namespace p="xq4" at "xq4.xqm"; :)
import module namespace xq4="java:quodatum.parser.xq4";
import module namespace pos="lsp/position" at "position.xqm";
import module namespace rpc = 'rpc' at 'jsonrpc.xqm';
import module namespace lsp-diags = 'lsp-diags' at 'providers/diagnostics.xqm';
import module namespace ast = 'lsp/ast' at 'ast/ast.xqm';
(: save $textDocument data as session $socket properties
@return uri
@ -119,7 +118,7 @@ declare function docs:parse(
)as map(*)?
{
let $text:=docs:get($socket,$file,"textDocument")?text
let $xml:= xq4:parseModule($text)=>prof:time("⏱️ p:parse-Module " || $file)
let $xml:= ast:build($text, $file)
let $diags:=lsp-diags:list($file, $text, $xml)=>prof:time("⏱️ diags " || $file)
return (
ws:set($socket,docs:key($socket,$file,"parse"),$xml),

View file

@ -50,6 +50,7 @@ as hnd:Result{
declare function syms:FunctionDecl($parse as element(FunctionDecl),$state as hnd:Result )
as hnd:Result{
let $name:=syms:localName($parse/UnreservedFunctionEQName)
let $prev:=$state?result[$name eq ?name]
let $range:=lspt:Range(lspt:Position(0,0),lspt:Position(0,3))
let $sym:=lspt:DocumentSymbol($name,$lspt:SymbolKindMap('Method'),$range,$range,"FUN")
return ($state?result,$sym)=>hnd:Result(true())