xquery version '4.0';
(:~  Symbols from walking the parse tree :)
module namespace syms="lsp/symbols";
import module namespace hnd="lsp/handlers" at "../handlers.xqm";
import module namespace lspt = 'lsp-typedefs' at "../lsp-typedefs.xqm";
import module namespace pos="lsp/position" at "../position.xqm";

declare variable $syms:actions as hnd:actionMap :={
      "ContextValueDecl":  syms:action#2,
      "VarDecl": syms:VarDecl#2,
      "FunctionDecl": syms:FunctionDecl#2,
      "ItemTypeDecl": syms:ItemTypeDecl#2,
      "NamedRecordTypeDecl": syms:NamedRecordTypeDecl#2
  };

declare function syms:list($parse as element(),$text as xs:string)
as lspt:DocumentSymbol*{
  let $state:= hnd:State((),false(),{"text":$text})
  let $state:= hnd:walk($parse,$syms:actions,$state)
  return $state?result
};

(: for testing only:)
declare function syms:dummy($parse as element(),$text as xs:string )
as lspt:DocumentSymbol*{
 let $fr:=(pos:full-range($text),message("dummy"))
 (: dummy data :)
 let $nameRange:=$fr
 return map:for-each($lspt:SymbolKindMap,
                  fn($k,$v){
                    lspt:DocumentSymbol($k,$v,$fr,$nameRange,`{$k} v:{$v}`)
                  })
};

(:~ just trace :)
declare function syms:action($parse  as element(),$state as hnd:State  )
as hnd:State{
  $state ,message(name($parse),"ACTION: ") 
};

declare function syms:VarDecl($parse  as element(VarDecl),$state as hnd:State  )
as hnd:State{
  let $name:=syms:localName($parse/VarNameAndType/EQName)
  let $length:=string($parse)=>string-length()
  let $range:=pos:range-from-ast($parse/VarNameAndType/EQName,$state?extras?text)
  let $full-range:=pos:range-from-ast($parse,$state?extras?text)
  let $sym:=lspt:DocumentSymbol($name,$lspt:SymbolKindMap('Variable'),$range,$full-range,"VAR")
  return  $state
            =>map:put("result",($state?result,$sym))
            =>map:put("skipchildren",true())
};

declare function syms:FunctionDecl($parse  as element(FunctionDecl),$state as hnd:State  )
as hnd:State{
  let $name:=syms:localName($parse/UnreservedFunctionEQName)
  let $prev:=$state?result[$name eq ?name]
  let $range:=pos:range-from-ast($parse/UnreservedFunctionEQName,$state?extras?text)
  let $full-range:=pos:range-from-ast($parse,$state?extras?text)
  let $sym:=lspt:DocumentSymbol($name,$lspt:SymbolKindMap('Method'),$range,$full-range,"FUN")
  return  $state
            =>map:put("result",($state?result,$sym))
            =>map:put("skipchildren",true())
};

declare function syms:ItemTypeDecl($parse  as element(ItemTypeDecl), $state as hnd:State  )
as hnd:State{
  let $name:=syms:localName($parse/EQName)
  let $range:=pos:range-from-ast($parse/EQName,$state?extras?text)
  let $full-range:=pos:range-from-ast($parse,$state?extras?text)
  let $sym:=lspt:DocumentSymbol($name,$lspt:SymbolKindMap('TypeParameter'),$range,$full-range,"--TYPE")
            =>trace("RECORD")
  return  $state
            =>map:put("result",($state?result,$sym))
            =>map:put("skipchildren",true())
};


declare function syms:NamedRecordTypeDecl($parse  as element(NamedRecordTypeDecl), $state as hnd:State  )
as hnd:State{
  let $name:=syms:localName($parse/EQName)
  let $range:=pos:range-from-ast($parse/EQName,$state?extras?text)
  let $full-range:=pos:range-from-ast($parse,$state?extras?text)
  let $sym:=lspt:DocumentSymbol($name,$lspt:SymbolKindMap('TypeParameter'),$range,$full-range,"--RECORD")
            =>trace("RECORD")
  return  $state
            =>map:put("result",($state?result,$sym))
            =>map:put("skipchildren",true())
};

declare function syms:localName($name as xs:string )
as xs:string{
  if(starts-with($name,"Q{"))
  then substring-after($name,"}")
  else if(contains($name,":"))
      then substring-after($name,":")
      else $name
};
