From 64feb6a5cd3bda525fc0dedccd8d7900abe88fe9 Mon Sep 17 00:00:00 2001 From: Michael VAN CANNEYT Date: Fri, 3 Feb 2023 17:28:28 +0100 Subject: [PATCH] * $NAMESPACES directive --- compiler/fmodule.pas | 23 ++++++++++++++++++++ compiler/fppu.pas | 50 ++++++++++++++++++++++++++----------------- compiler/globals.pas | 11 +++++++++- compiler/pmodules.pas | 16 ++++++++++++++ compiler/scandir.pas | 34 +++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 21 deletions(-) diff --git a/compiler/fmodule.pas b/compiler/fmodule.pas index 155ad7b148..004bd2279d 100644 --- a/compiler/fmodule.pas +++ b/compiler/fmodule.pas @@ -174,6 +174,7 @@ interface loaded_from : tmodule; _exports : tlinkedlist; dllscannerinputlist : TFPHashList; + localnamespacelist, resourcefiles, linkorderedsymbols : TCmdStrList; linkunitofiles, @@ -241,6 +242,7 @@ interface constructor create(LoadedFrom:TModule;const amodulename: string; const afilename:TPathStr;_is_unit:boolean); destructor destroy;override; procedure reset;virtual; + procedure loadlocalnamespacelist; procedure adddependency(callermodule:tmodule); procedure flagdependent(callermodule:tmodule); procedure addimportedsym(sym:TSymEntry); @@ -572,6 +574,7 @@ implementation localframeworksearchpath:=TSearchPathList.Create; used_units:=TLinkedList.Create; dependent_units:=TLinkedList.Create; + localnamespacelist:=TCmdStrList.Create; resourcefiles:=TCmdStrList.Create; linkorderedsymbols:=TCmdStrList.Create; linkunitofiles:=TLinkContainer.Create; @@ -946,6 +949,26 @@ implementation } end; + procedure tmodule.loadlocalnamespacelist; + + var + nsitem : TCmdStrListItem; + + begin + // Copying local namespace list + if premodule_namespacelist.Count>0 then + begin + nsitem:=TCmdStrListItem(premodule_namespacelist.First); + while assigned(nsItem) do + begin + localnamespacelist.Concat(nsitem.Str); + nsItem:=TCmdStrListItem(nsitem.Next); + end; + premodule_namespacelist.Clear; + end; + current_namespacelist:=localnamespacelist; + end; + procedure tmodule.adddependency(callermodule:tmodule); begin diff --git a/compiler/fppu.pas b/compiler/fppu.pas index c6670b9ef4..dce93c8cb7 100644 --- a/compiler/fppu.pas +++ b/compiler/fppu.pas @@ -562,10 +562,35 @@ var result:=SearchPathList(UnitSearchPath,prefix); end; + function SearchNamespaceList(const prefixes:TCmdStrList):boolean; + var + nsitem : TCmdStrListItem; + res : Boolean; + begin + res:=false; + nsitem:=TCmdStrListItem(prefixes.first); + while assigned(nsitem) do + begin + if not onlysource then + begin + res:=SearchPPUPaths(nsitem.str); + if res then + break; + end; + res:=SearchSourcePaths(nsitem.str); + if res then + break; + nsitem:=TCmdStrListItem(nsitem.next); + end; + if assigned(nsitem) then + nsprefix:=nsitem.str; + result:=res; + end; + + var fnd : boolean; hs : TPathStr; - nsitem : TCmdStrListItem; begin if shortname then filename:=FixFileName(Copy(realmodulename^,1,8)) @@ -618,26 +643,11 @@ var if not fnd then begin fnd:=SearchSourcePaths(''); + // current_namespacelist is set to the current module's namespacelist. + if not fnd and assigned(current_namespacelist) and (current_namespacelist.count>0) then + fnd:=SearchNameSpaceList(current_namespacelist); if not fnd and (namespacelist.count>0) then - begin - nsitem:=TCmdStrListItem(namespacelist.first); - while assigned(nsitem) do - begin - if not onlysource then - begin - fnd:=SearchPPUPaths(nsitem.str); - if fnd then - break; - end; - fnd:=SearchSourcePaths(nsitem.str); - if fnd then - break; - - nsitem:=TCmdStrListItem(nsitem.next); - end; - if assigned(nsitem) then - nsprefix:=nsitem.str; - end; + fnd:=SearchNameSpaceList(namespacelist); end; search_unit:=fnd; end; diff --git a/compiler/globals.pas b/compiler/globals.pas index 7117a0cb75..532e47a712 100644 --- a/compiler/globals.pas +++ b/compiler/globals.pas @@ -316,8 +316,13 @@ interface includesearchpath, frameworksearchpath : TSearchPathList; packagesearchpath : TSearchPathList; + { list of default namespaces } namespacelist : TCmdStrList; + // During scanning/parsing, a module may not yet be available. + // Scanner checks first current_namespacelist, then local_namespacelist + premodule_namespacelist, // always set: used as long as current_namespacelist is not correctly set. + current_namespacelist : TCmdStrList; // Set when parsing module to the current module's namespace. { contains tpackageentry entries } packagelist : TFPHashList; autoloadunits : string; @@ -378,6 +383,7 @@ interface LinkLibraryAliases : TLinkStrMap; LinkLibraryOrder : TLinkStrMap; + init_settings, current_settings : tsettings; @@ -1653,6 +1659,8 @@ implementation LinkLibraryOrder.Free; packagesearchpath.Free; namespacelist.Free; + premodule_namespacelist.Free; + current_namespacelist:=Nil; end; procedure InitGlobals; @@ -1694,7 +1702,8 @@ implementation frameworksearchpath:=TSearchPathList.Create; packagesearchpath:=TSearchPathList.Create; namespacelist:=TCmdStrList.Create; - + premodule_namespacelist:=TCmdStrList.Create; + current_namespacelist:=Nil; { Def file } usewindowapi:=false; description:='Compiled by FPC '+version_string+' - '+target_cpu_string; diff --git a/compiler/pmodules.pas b/compiler/pmodules.pas index e5f58a82dc..baf14eee49 100644 --- a/compiler/pmodules.pas +++ b/compiler/pmodules.pas @@ -1018,6 +1018,11 @@ type if not(cs_compilesystem in current_settings.moduleswitches) and (token=_USES) then begin + // We do this as late as possible. + if Assigned(current_module) then + current_module.Loadlocalnamespacelist + else + current_namespacelist:=Nil; loadunits(nil); { has it been compiled at a higher level ?} if current_module.state=ms_compiled then @@ -1640,6 +1645,12 @@ type { ensure that no packages are picked up from the options } packagelist.clear; + // There should always be a requires, except for the system package. So we load here + if Assigned(current_module) then + current_module.Loadlocalnamespacelist + else + current_namespacelist:=Nil; + {Read the packages used by the package we compile.} if (token=_ID) and (idtoken=_REQUIRES) then begin @@ -2188,6 +2199,11 @@ type { Load the units used by the program we compile. } if token=_USES then begin + // We can do this here: if there is no uses then the namespace directive makes no sense. + if Assigned(current_module) then + current_module.Loadlocalnamespacelist + else + current_namespacelist:=Nil; loadunits(nil); consume_semicolon_after_uses:=true; end diff --git a/compiler/scandir.pas b/compiler/scandir.pas index 36abc464c8..cf18f3f204 100644 --- a/compiler/scandir.pas +++ b/compiler/scandir.pas @@ -1019,6 +1019,39 @@ unit scandir; end; + procedure dir_namespaces; + + { add namespaces to the local namespace list } + var + s : string; + + begin + if not current_module.in_global then + Message(scan_w_switch_is_global) + else + begin + current_scanner.skipspace; + current_scanner.readstring; + s:=orgpattern; + While (s<>'') do + begin + // We may not yet have a correct module namespacelist. + if assigned(current_namespacelist) then + current_namespacelist.Insert(s) + else // copied when correct module is activated + premodule_namespacelist.Insert(s); + s:=''; + if c=',' then + begin + current_scanner.readchar; + current_scanner.skipspace; + current_scanner.readstring; + s:=orgpattern; + end; + end; + end; + end; + procedure dir_namespace; var s : string; @@ -2029,6 +2062,7 @@ unit scandir; AddDirective('MODE',directive_all, @dir_mode); AddDirective('MODESWITCH',directive_all, @dir_modeswitch); AddDirective('NAMESPACE',directive_all, @dir_namespace); + AddDirective('NAMESPACES',directive_all, @dir_namespaces); AddDirective('NODEFINE',directive_all, @dir_nodefine); AddDirective('NOTE',directive_all, @dir_note); AddDirective('NOTES',directive_all, @dir_notes);