PmProject.icl 39.5 KB
Newer Older
Diederik van Arkel's avatar
Diederik van Arkel committed
1 2
implementation module PmProject

3
import StdClass,StdBool,StdInt,StdString,StdArray,StdFunc,StdTuple,StdList,StdStrictLists
Diederik van Arkel's avatar
Diederik van Arkel committed
4
import StdMaybe
5
from StdOverloadedList import ++|,Hd
Diederik van Arkel's avatar
Diederik van Arkel committed
6
import PmPath, UtilStrictLists
7
from UtilDate import NoDate, :: DATE
Diederik van Arkel's avatar
Diederik van Arkel committed
8 9 10
import UtilNewlinesFile
import PmTypes
import Platform
11
import UtilOptions, PmFiles
Diederik van Arkel's avatar
Diederik van Arkel committed
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

::	Def_and_Imp				:== Bool;
DclMod					:== True;
IclMod					:== False;

::	WindowOpen_and_Closed	:== Bool;
WinOpen					:== True;
WinClosed				:== False;
	
::	Modification			:== Bool;
Modified				:== True;
Unmodified				:== False;

//	The Project: A list of constituent modules and their mutual dependencies

::	Project	=
28
	{ saved						:: !Bool
Diederik van Arkel's avatar
Diederik van Arkel committed
29 30 31 32 33 34 35 36 37 38 39 40
	, exec						:: !Bool					// exe linked ok?
	, inflist					:: !InfList					// list with constituent modules
	, codegenopt				:: !CodeGenOptions			// code generator options
	, code_gen_options_unchanged :: !Bool
	, applicationopt			:: !ApplicationOptions		// application options
	, linkOptions				:: !LinkOptions
	, prjpaths					:: !List String				// project paths
	, staticLibInfo				:: !StaticLibInfo
	, target					:: !String					// environment

	, dynamic_info				:: !ProjectDynamicInfo

41 42
	, relative_root_directory	:: !String			// string of '.'s, relative to .prj file
	, root_directory			:: !String
Diederik van Arkel's avatar
Diederik van Arkel committed
43
	, execpath					:: !String			// move to app_opts
44
	, bytecode_path				:: !String
Diederik van Arkel's avatar
Diederik van Arkel committed
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
	, prec						:: !Maybe String	// " (precompile command)
	, posl						:: !Maybe String	// " (postlink command)
	}

//	First element of InfList (if any) is the root module.

::	InfList		:==	List InfListItem
	
::	InfListItem	=
	{ mn	:: !Modulename		// module name
	, info	:: !ModInfo			// module info
	, src	:: !Bool			// src up to date?
	, abc	:: !Bool 			// abc up to date?
	}

60
::	InfUpdate 	:== InfListItem -> (!InfListItem, Bool)
Diederik van Arkel's avatar
Diederik van Arkel committed
61 62 63

PR_InitProject :: Project;
PR_InitProject =
64
	{ saved				= True
Diederik van Arkel's avatar
Diederik van Arkel committed
65 66 67 68 69 70 71 72 73 74 75
	, exec				= True
	, execpath			= EmptyPathname
	, inflist			= Nil
	, codegenopt		= DefCodeGenOptions
	, code_gen_options_unchanged	= True
	, applicationopt	= DefApplicationOptions
	, linkOptions		= DefaultLinkOptions
	, prjpaths			= Nil
	, staticLibInfo		= DefStaticLibInfo
	, target			= ""
	, dynamic_info		= EmptyDynamicInfo
76 77
	, relative_root_directory = "."
	, root_directory = ""
Diederik van Arkel's avatar
Diederik van Arkel committed
78 79
	, prec = Nothing
	, posl = Nothing
80
	, bytecode_path		= EmptyPathname
Diederik van Arkel's avatar
Diederik van Arkel committed
81 82
	}

83
PR_GetExecPath	:: !Project -> String
Diederik van Arkel's avatar
Diederik van Arkel committed
84 85
PR_GetExecPath {execpath} = execpath

86
PR_SetExecPath	:: !String !Project -> Project
Diederik van Arkel's avatar
Diederik van Arkel committed
87 88
PR_SetExecPath pth prj = {prj & execpath = pth}

89 90 91
PR_GetByteCodePath	:: !Project -> String
PR_GetByteCodePath {bytecode_path} = bytecode_path

Camil Staps's avatar
Camil Staps committed
92 93 94
PR_SetByteCodePath :: !String !Project -> Project
PR_SetByteCodePath pth prj = {prj & bytecode_path=pth}

Diederik van Arkel's avatar
Diederik van Arkel committed
95 96 97 98 99 100 101 102 103 104 105 106
DefStaticLibInfo =
	{ sLibs = Nil
	, sDcls = Nil
	, sDeps = Nil
	}

PR_ProjectSet :: !Project -> Bool;
PR_ProjectSet project=:{inflist=Nil}	=  False;
PR_ProjectSet project=:{inflist}		=  True;

PR_NewProject :: !String !EditWdOptions !CompilerOptions !CodeGenOptions !ApplicationOptions
				!(List String) !LinkOptions -> Project;
107 108 109 110
PR_NewProject main_module_file_name eo compilerOptions cgo ao prjpaths linkOptions
	# modname	= GetModuleName main_module_file_name;
	  dirname	= RemoveFilename main_module_file_name;
	= { PR_InitProject
111
	& saved			= False
Diederik van Arkel's avatar
Diederik van Arkel committed
112
	, exec			= False
113
	, execpath		= IF_WINDOWS
114
						("{Project}"+++DirSeparatorString+++add_dot_exe_if_necessary modname)	// Win
115
						("{Project}"+++DirSeparatorString+++modname)				// Mac
Diederik van Arkel's avatar
Diederik van Arkel committed
116 117 118 119
	, inflist		=
		{ mn		= modname
		, info		=	{ dir		= "{Project}"//dirname
						, compilerOptions		= compilerOptions
120
						, mod_edit_options = {defeo=eo,impeo=eo,defopen=False,impopen=True}
Diederik van Arkel's avatar
Diederik van Arkel committed
121 122 123 124 125 126 127 128 129 130 131 132
						, abcLinkInfo = {linkObjFileNames = Nil, linkLibraryNames = Nil}
						}
		, src		= True
		, abc		= True
		} :! Nil
	, codegenopt	= cgo
	, code_gen_options_unchanged	= True
	, applicationopt= ao
	, prjpaths		= if (StringOccurs dirname prjpaths) prjpaths (dirname:!prjpaths)
	, linkOptions	= linkOptions
	, staticLibInfo = DefStaticLibInfo
	, target		= "StdEnv"
133
	, root_directory = dirname
Diederik van Arkel's avatar
Diederik van Arkel committed
134 135
	}

136 137 138 139 140 141 142
add_dot_exe_if_necessary :: !{#Char} -> {#Char};
add_dot_exe_if_necessary module_name
	# i=size module_name-4;
	| i>=0 && module_name.[i]=='.' && module_name.[i+1]=='e' && module_name.[i+2]=='x' && module_name.[i+3]=='e' 
		= module_name;
		= module_name+++".exe";

143
PR_SetBuilt	:: ![!ModuleDirAndName] !u:Project -> u:Project;
144
PR_SetBuilt used project=:{inflist=Nil}
145
	= project;
Diederik van Arkel's avatar
Diederik van Arkel committed
146 147 148 149 150
PR_SetBuilt used prj=:{inflist=infl=:(root:!rest),saved}
	#! len		= LLength rest
	# rest		= RemoveUnusedModules used rest
	# len`		= LLength rest
	# unchanged	= len == len`
151
	= {prj & saved=saved && unchanged,inflist= root:!rest}
Diederik van Arkel's avatar
Diederik van Arkel committed
152 153 154 155
where	
	{mn=rootmn,info} = root
	RemoveUnusedModules used list = FilterR member list
	where
156
		member {mn}	= module_occurs mn used && rootmn <> mn
Diederik van Arkel's avatar
Diederik van Arkel committed
157

158 159 160 161
module_occurs :: !String ![!ModuleDirAndName] -> Bool
module_occurs s [|x:xs] = x.mdn_name == s || module_occurs s xs
module_occurs s [!] =  False

162 163
PR_AddABCInfo :: !ModuleDirAndName !(List LinkObjFileName) !(List LinkLibraryName) !CompilerOptions !Project -> Project
PR_AddABCInfo mdn dep_objects dep_libraries compilerOptions project=:{inflist=Nil}
Diederik van Arkel's avatar
Diederik van Arkel committed
164
	= project
165
PR_AddABCInfo {mdn_dir=mod_dir,mdn_name=mod_name} dep_objects dep_libraries compilerOptions project=:{inflist}
Diederik van Arkel's avatar
Diederik van Arkel committed
166 167
	# inflist		= TryInsertInList mod_name mod_dir inflist
	# (inflist,_)	= UpdateList mod_name update inflist;
168
	= {project & saved=False,inflist=inflist}
Diederik van Arkel's avatar
Diederik van Arkel committed
169 170 171 172 173 174 175 176 177
where
	update infListItem=:{InfListItem | info}
		= (	{ InfListItem | infListItem
			& info.abcLinkInfo.linkObjFileNames		= dep_objects
			, info.abcLinkInfo.linkLibraryNames		= dep_libraries
			, info.dir								= mod_dir
			, info.compilerOptions					= compilerOptions
			}, True)

178
	TryInsertInList :: !String !String !InfList -> InfList
Diederik van Arkel's avatar
Diederik van Arkel committed
179 180 181 182 183 184 185 186 187
	TryInsertInList importermn importerdir Nil	// no root module...
		= Nil
	TryInsertInList importermn importerdir ((root=:{mn,info}):!rest)
		| importermn == mn	// updating root module...
			# root	= {InfListItem | root & info = {ModInfo | info & dir = importerdir}}
			= root :! rest
		# rest		= TryInsertImporter rest rest
		= root :! rest
	where
188
		TryInsertImporter ::	!InfList !InfList -> InfList
Diederik van Arkel's avatar
Diederik van Arkel committed
189
		TryInsertImporter Nil list
190
			# default_edit_options = {pos_size = NoWindowPosAndSize, eo = {newlines= HostNativeNewlineConvention}}
Diederik van Arkel's avatar
Diederik van Arkel committed
191 192 193
			# item =
				  {	mn		= importermn, 
					info	= { dir		= importerdir,
194 195 196
								compilerOptions = compilerOptions,
								mod_edit_options = {defeo = default_edit_options,impeo = default_edit_options,
													defopen = False, impopen = False},
Diederik van Arkel's avatar
Diederik van Arkel committed
197 198 199 200 201 202 203 204 205 206 207
								abcLinkInfo = {linkObjFileNames = Nil, linkLibraryNames = Nil} },
					src		= True,
					abc		= True }
			= item :! list
		TryInsertImporter (({mn}):!rest) list
			| importermn<>mn
				= TryInsertImporter rest list
				= list

PR_ClearDependencies :: !Project -> Project
PR_ClearDependencies project=:{inflist=Nil}
208
	= {project & saved = False, inflist = Nil}
Diederik van Arkel's avatar
Diederik van Arkel committed
209
PR_ClearDependencies project=:{inflist=il=:(root :! rest)}
210
	= {project & saved = False, inflist = root` :! Nil}
Diederik van Arkel's avatar
Diederik van Arkel committed
211
where
212 213
	root` = {InfListItem | root & info.abcLinkInfo = {linkObjFileNames = Nil, linkLibraryNames = Nil}}

Diederik van Arkel's avatar
Diederik van Arkel committed
214 215 216 217 218 219 220 221 222
PR_SetRoot :: !String !EditWdOptions !CompilerOptions !Project -> Project;
PR_SetRoot root eo co project=:{inflist=Nil}
	= project;
PR_SetRoot newroot eo compilerOptions project=:{prjpaths}
	=	{project &	saved	= False,
					exec	= False,
					inflist	= {	mn		= modname,
								info	= {	dir		= dirname,
											compilerOptions		= compilerOptions,
223 224 225 226
											mod_edit_options = {defeo = eo,impeo = eo,
																impopen = True,
																defopen = False	/* nonsense, we don't know this! */
															   },
Diederik van Arkel's avatar
Diederik van Arkel committed
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
											abcLinkInfo = {linkObjFileNames = Nil, linkLibraryNames = Nil} },
								src		= True,
								abc		= True
								} :! Nil,
					prjpaths= if (StringOccurs dirname prjpaths) prjpaths (dirname:!prjpaths) /* a bit iffy */
		  };
where 
	modname	= GetModuleName newroot;
	dirname	= RemoveFilename newroot;

PR_SetCompiled	:: !Modulename !Project -> Project;
PR_SetCompiled modname project=:{inflist}
	=  {project & inflist = inf`}
where 
	(inf`, _)	= UpdateList modname setcompiled inflist;
	
	setcompiled	:: !InfListItem -> (!InfListItem,!Bool);
	setcompiled itm=:{src,abc}
		= ({itm & src = True},True);
	
		
PR_SetCodeGenerated	:: !Modulename !Project -> Project;
PR_SetCodeGenerated modname project=:{inflist}
	= {project & inflist = inf`};
where 
	(inf`,_)	= UpdateList modname setcode inflist;
	
	setcode :: !InfListItem -> (!InfListItem, !Bool);
	setcode itm=:{InfListItem | src}
		= ({InfListItem | itm & abc = True}, True);
	
	
PR_SetSysCodeGenerated :: !Project -> Project;
PR_SetSysCodeGenerated project = {project & code_gen_options_unchanged = True};
	
PR_SetLinked	:: !Project -> Project;
PR_SetLinked project=:{inflist}
	=  {project & exec = True};
	
PR_SetSaved	:: !Project -> Project;
PR_SetSaved project = {Project | project & saved = True};
		
PR_SetCodeGenOptions	:: !CodeGenOptions !Project -> Project;
PR_SetCodeGenOptions options project=:{inflist,saved,codegenopt,code_gen_options_unchanged} =
	{ project
	& inflist						= infl`
	, saved							= saved && unchanged
	, code_gen_options_unchanged	= code_gen_options_unchanged && cg_unchanged
	, codegenopt					= options
	}
where 
	(infl`,_)				= infl`_;
	infl`_ | cg_unchanged	= (inflist,True);
							= P_MapR setcode inflist;
	unchanged				= cg_unchanged;
	cg_unchanged			= options == codegenopt;
	
	setcode :: !InfListItem -> (!InfListItem, !Bool);
	setcode itm=:{InfListItem | src}
		= ({InfListItem | itm & abc = False}, True);
	
	
PR_SetApplicationOptions :: !ApplicationOptions !Project -> Project;
PR_SetApplicationOptions options project=:{saved,exec,applicationopt}
	= {project & applicationopt = options, exec = exec && unchanged,saved=saved && unchanged};
	where 
		unchanged	= eqAppOpts options applicationopt;

eqAppOpts :: !ApplicationOptions !ApplicationOptions -> Bool
eqAppOpts ao1 ao2
	=	ao1.hs == ao2.hs &&
		ao1.ss == ao2.ss &&
		ao1.em == ao2.em &&
		ao1.heap_size_multiple == ao2.heap_size_multiple &&
		ao1.initial_heap_size == ao2.initial_heap_size &&
		ao1.set == ao2.set &&
		ao1.sgc == ao2.sgc &&
		ao1.pss == ao2.pss &&
		ao1.marking_collection == ao2.marking_collection &&
306
		ao1.disable_rts_flags == ao2.disable_rts_flags &&		
Diederik van Arkel's avatar
Diederik van Arkel committed
307 308 309 310 311 312 313 314
		ao1.o == ao2.o &&
		ao1.fn == ao2.fn &&
		ao1.fs == ao2.fs &&
		ao1.write_stderr_to_file == ao2.write_stderr_to_file &&
		ao1.memoryProfiling == ao2.memoryProfiling &&
		ao1.memoryProfilingMinimumHeapSize == ao2.memoryProfilingMinimumHeapSize &&
		ao1.profiling == ao2.profiling &&
		ao1.stack_traces == ao2.stack_traces &&
315
		ao1.generic_fusion == ao2.generic_fusion &&
316 317
		ao1.dynamics == ao2.dynamics &&
		ao1.desc_exl == ao2.desc_exl &&
Diederik van Arkel's avatar
Diederik van Arkel committed
318 319 320 321 322 323 324
		ao1.standard_rte == ao2.standard_rte

// do we need to check resource linking flags???
eqLinkOpts :: !LinkOptions !LinkOptions -> Bool
eqLinkOpts lo1 lo2 =
	lo1.method == lo2.method &&
	lo1.generate_relocations == lo2.generate_relocations &&
325
	lo1.generate_symbol_table == lo2.generate_symbol_table &&
Diederik van Arkel's avatar
Diederik van Arkel committed
326 327 328 329 330 331
	lo1.generate_link_map == lo2.generate_link_map &&
	lo1.link_resources == lo2.link_resources &&
	(if lo1.link_resources (lo1.resource_source == lo2.resource_source) True) &&
	EQStrings (SortStrings lo1.extraObjectModules) (SortStrings lo2.extraObjectModules) &&
	EQStrings (SortStrings lo1.libraries) (SortStrings lo2.libraries) &&
	lo1.generate_dll == lo2.generate_dll &&
Diederik van Arkel's avatar
Diederik van Arkel committed
332
	lo1.dll_export_list_name == lo2.dll_export_list_name
Diederik van Arkel's avatar
Diederik van Arkel committed
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347

	
PR_SetLinkOptions	:: !Project !LinkOptions -> Project;
PR_SetLinkOptions project linkOptions
	| eqLinkOpts linkOptions project.Project.linkOptions
		=	{Project | project & linkOptions = linkOptions, saved = False};
	| otherwise
		=	{Project | project & linkOptions = linkOptions, exec = False, saved = False};

PR_GetLinkOptions	:: !Project -> LinkOptions;
PR_GetLinkOptions project
	=  project.Project.linkOptions;

PR_SetPaths	:: !Bool !(List String) !(List String) !Project -> Project;
PR_SetPaths def defs new project=:{Project | inflist=Nil} = project;
348
PR_SetPaths def defs new project=:{Project | inflist=infl=:((root=:{InfListItem | info={dir}}):!rest),prjpaths,saved}
Diederik van Arkel's avatar
Diederik van Arkel committed
349
	| def	= {Project | project &
Diederik van Arkel's avatar
Diederik van Arkel committed
350 351
							saved				= saved && olddirs,
							inflist				= inflist1 };
Diederik van Arkel's avatar
Diederik van Arkel committed
352
			= {Project | project &
Diederik van Arkel's avatar
Diederik van Arkel committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366
							saved				= saved && unchanged && olddirs,
							inflist				= inflist1,
							prjpaths			= prjpaths1 };
	where 
		(inflist1,olddirs)	= P_MapR SetDcl_and_Icl_and_ABCModified infl;
		unchanged			= EQStrings (SortStrings prjpaths) (SortStrings prjpaths1);
		prjpaths1 	| def	= prjpaths;
					| StringOccurs dir new
							= new;
							= dir:!new;
						
		SetDcl_and_Icl_and_ABCModified :: !InfListItem -> (!InfListItem,!Bool);
		SetDcl_and_Icl_and_ABCModified itm=:{InfListItem | info=minfo=:{dir}}
		| unchanged	= ({itm & src=False}, True);
367
					= ({itm & info = {minfo & dir=""}, src=False},False);
Diederik van Arkel's avatar
Diederik van Arkel committed
368 369 370 371 372 373
			where 
				unchanged	= StringOccurs dir defs || StringOccurs dir prjpaths1;
			
		
		
PR_GetCodeGenOptions :: !Project -> CodeGenOptions;
374
PR_GetCodeGenOptions {codegenopt} =  codegenopt;
Diederik van Arkel's avatar
Diederik van Arkel committed
375

376 377
//PR_GetProcessor :: !Project -> Processor;
//PR_GetProcessor project=:{codegenopt={tp}} = tp;
Diederik van Arkel's avatar
Diederik van Arkel committed
378 379
	
PR_GetApplicationOptions :: !Project -> ApplicationOptions;
380 381
PR_GetApplicationOptions {applicationopt} =  applicationopt;

Diederik van Arkel's avatar
Diederik van Arkel committed
382
PR_GetPaths	:: !Project -> List String;
383
PR_GetPaths {Project | prjpaths} = prjpaths;
Diederik van Arkel's avatar
Diederik van Arkel committed
384 385

PR_GetRootModuleName :: !Project -> String
386
PR_GetRootModuleName {inflist=Nil}
Diederik van Arkel's avatar
Diederik van Arkel committed
387
	= EmptyPathname
388
PR_GetRootModuleName {inflist={mn}:!rest}
Diederik van Arkel's avatar
Diederik van Arkel committed
389 390
	= mn

391
PR_GetRootPathName	:: !Project -> (!String,!Project)
Diederik van Arkel's avatar
Diederik van Arkel committed
392 393 394 395 396 397 398
PR_GetRootPathName p=:{inflist=Nil}
	= (EmptyPathname,p)
PR_GetRootPathName p=:{inflist={mn,info={dir}}:!rest}
	| size dir==0
		= (EmptyPathname,p)
		= (MakeFullPathname dir (MakeImpPathname mn),p)

399 400
PR_GetRootModuleDir	:: !Project -> String
PR_GetRootModuleDir {inflist=Nil}
Diederik van Arkel's avatar
Diederik van Arkel committed
401
	= EmptyPathname;
402
PR_GetRootModuleDir {inflist={mn,info={dir}}:!rest}
Diederik van Arkel's avatar
Diederik van Arkel committed
403 404 405 406
	| size dir==0
		= EmptyPathname;
		= dir;

407 408 409 410 411 412 413 414
PR_GetRootModuleDirAndName :: !Project -> (!ModuleDirAndName,!Project)
PR_GetRootModuleDirAndName p=:{inflist=Nil}
	= ({mdn_dir=EmptyPathname,mdn_name=""},p)
PR_GetRootModuleDirAndName p=:{inflist={mn,info={dir}}:!rest}
	| size dir==0
		= ({mdn_dir=EmptyPathname,mdn_name=""},p)
		= ({mdn_dir=dir,mdn_name=mn},p)

415 416 417 418 419 420 421 422
PR_GetRootDir :: !Project -> String
PR_GetRootDir {root_directory}
	= root_directory;

PR_GetRelativeRootDir :: !Project -> String
PR_GetRelativeRootDir {relative_root_directory}	
	= relative_root_directory

423 424 425
PR_SetRelativeRootDir	:: !String !Project -> Project
PR_SetRelativeRootDir pth prj = {prj & relative_root_directory = pth}

Diederik van Arkel's avatar
Diederik van Arkel committed
426 427 428 429
PR_GetModulenames	:: !Bool !Def_and_Imp !Project -> (List String,Project)
PR_GetModulenames full def project=:{inflist}
	= (modnames,project)
where 
430
	modnames	= MapR GetModulenames inflist
Diederik van Arkel's avatar
Diederik van Arkel committed
431
	
432
	GetModulenames :: !InfListItem -> String
Diederik van Arkel's avatar
Diederik van Arkel committed
433
	GetModulenames {mn,info={dir}}
434 435 436
		| full && def	= MakeFullPathname dir (MakeDefPathname mn)
		| full			= MakeFullPathname dir (MakeImpPathname mn)
						= mn
Diederik van Arkel's avatar
Diederik van Arkel committed
437

438 439 440 441 442 443 444 445 446 447
PR_GetDirAndModulenames	:: !Project -> ([!ModuleDirAndName],Project)
PR_GetDirAndModulenames project=:{inflist}
	# modnames = get_dir_and_module_names_r inflist [|]
	= (modnames,project)
where
	get_dir_and_module_names_r ({mn,info={dir}}:!inflist) r
		= get_dir_and_module_names_r inflist [|{mdn_dir=dir,mdn_name=mn}:r]
	get_dir_and_module_names_r Nil r
		= r

Diederik van Arkel's avatar
Diederik van Arkel committed
448 449 450 451
PR_GetOpenModulenames	:: !Project -> List String
PR_GetOpenModulenames project=:{inflist}
	= FlattenList modnames
where 
452 453 454
	modnames = MapR GetModulenames inflist

	GetModulenames :: !InfListItem -> List String
455
	GetModulenames {mn,info={dir,mod_edit_options={defopen,impopen}}}
456 457 458 459
		| defopen && impopen	= defname :! impname :! Nil
		| defopen				= defname :! Nil
		| impopen				= impname :! Nil
								= Nil
Diederik van Arkel's avatar
Diederik van Arkel committed
460
	where
461 462
		defname = ModuleDirAndNameToDefPathname {mdn_dir=dir,mdn_name=mn}
		impname = ModuleDirAndNameToImpPathname {mdn_dir=dir,mdn_name=mn}
Diederik van Arkel's avatar
Diederik van Arkel committed
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480

PR_GetModuleStuff :: !Project -> List (Modulename,String,Modulename,String)
PR_GetModuleStuff project=:{inflist}
	= stuff
where 
	(stuff,_)	= P_MapR GetModulenames inflist
	
	GetModulenames :: !InfListItem -> ((!Modulename,!String,!Modulename,!String),!Bool)
	GetModulenames {mn,info={dir}}
						= ((MakeDefPathname mn,dir,MakeImpPathname mn,dir),True)
		
PR_SrcUpToDate :: !Modulename !Project -> Bool;
PR_SrcUpToDate modname project=:{inflist}
	# item = FindInList modname inflist
	| isNothing item
		= False
	# item = fromJust item
	= item.src
481

Diederik van Arkel's avatar
Diederik van Arkel committed
482 483 484 485 486 487 488
PR_ABCUpToDate	:: !Modulename !Project -> Bool;
PR_ABCUpToDate modname project=:{inflist}
	# item = FindInList modname inflist
	| isNothing item
		= False
	# item = fromJust item
	= item.abc
489

Diederik van Arkel's avatar
Diederik van Arkel committed
490 491 492 493 494 495 496 497 498
PR_SysUptoDate :: !Project -> Bool;
PR_SysUptoDate project=:{code_gen_options_unchanged} = code_gen_options_unchanged;
	
PR_ExecUpToDate	:: !Project -> Bool;		
PR_ExecUpToDate project=:{exec} = exec;

PR_Saved :: !Project -> Bool;
PR_Saved {Project | saved} = saved;

499
PR_AddRootModule ::	!CodeGenOptions !ApplicationOptions !(List String) !LinkOptions
Diederik van Arkel's avatar
Diederik van Arkel committed
500
					!Modulename !ModInfo -> Project;
501
PR_AddRootModule cg ao prjs linkOptions mn info=:{dir}
Diederik van Arkel's avatar
Diederik van Arkel committed
502
  = { PR_InitProject
503
  	& saved			= False
Diederik van Arkel's avatar
Diederik van Arkel committed
504
	, exec			= True
505
	, execpath		= ""
Diederik van Arkel's avatar
Diederik van Arkel committed
506 507 508 509 510 511 512 513 514 515 516 517
	, code_gen_options_unchanged
						= True
	, inflist			= root:!Nil
	, codegenopt		= cg
	, applicationopt	= ao
	, prjpaths		= prjs
	, linkOptions	= linkOptions
	, staticLibInfo = DefStaticLibInfo
	, target = ""
	};
where 
	root	= {	mn		= mn,info	= info,src		= True,abc		= True };
518

Diederik van Arkel's avatar
Diederik van Arkel committed
519
PR_AddModule :: !Modulename !ModInfo !Project -> Project;
520 521
PR_AddModule mn info=:{dir} project=:{inflist=root:!rest}
	= {project & inflist = root:!new:!rest};
Diederik van Arkel's avatar
Diederik van Arkel committed
522 523 524 525 526
where 
	new	= {	mn		= mn,
			info	= info,
			src		= True,
			abc		= True };
527 528
PR_AddModule mn info=:{dir} project=:{inflist=Nil}
	= {project & inflist = new:!Nil};
Diederik van Arkel's avatar
Diederik van Arkel committed
529 530 531 532 533 534
where 
	new	= {	mn		= mn,
			info	= info,
			src		= True,
			abc		= True };
	
535
PR_GetModuleInfo :: !Modulename !Project -> Maybe ModInfo
Diederik van Arkel's avatar
Diederik van Arkel committed
536 537 538 539 540 541
PR_GetModuleInfo mn {Project | inflist}
	# item = FindInList mn inflist
	| isNothing item
		= Nothing
	= Just (fromJust item).InfListItem.info
	
542
PR_UpdateModule :: !Modulename !(ModInfo -> ModInfo) !Project -> Project;
Diederik van Arkel's avatar
Diederik van Arkel committed
543 544 545 546 547 548 549 550 551 552
PR_UpdateModule mn update project=:{inflist,saved}
	= {project & inflist = infl`,saved = saved && unchanged};
where 
	(infl`,unchanged)	= UpdateList mn update` inflist;
	update` itm=:{InfListItem | info}	= ({InfListItem | itm & info = info`}, unchanged);
	where 
		info`		= update info;
		unchanged	= eqInfo info info`;

eqInfo :: !ModInfo !ModInfo -> Bool
553 554 555
eqInfo info1=:{mod_edit_options=mod_edit_options1} info2=:{mod_edit_options=mod_edit_options2}
	=	mod_edit_options1.defeo.eo == mod_edit_options2.defeo.eo &&
		mod_edit_options1.impeo.eo == mod_edit_options2.impeo.eo &&
Diederik van Arkel's avatar
Diederik van Arkel committed
556
		eqCO info1.compilerOptions info2.compilerOptions &&
557 558 559 560
		mod_edit_options1.defeo.pos_size == mod_edit_options2.defeo.pos_size && 
		mod_edit_options1.impeo.pos_size == mod_edit_options2.impeo.pos_size &&
		mod_edit_options1.defopen == mod_edit_options2.defopen &&
		mod_edit_options1.impopen == mod_edit_options2.impopen
Diederik van Arkel's avatar
Diederik van Arkel committed
561 562 563 564 565 566 567 568 569 570 571

eqCO :: !CompilerOptions !CompilerOptions -> Bool
eqCO co1 co2
	=	co1.neverTimeProfile == co2.neverTimeProfile &&
		co1.neverMemoryProfile == co2.neverMemoryProfile &&
		co1.sa == co2.sa &&
		co1.CompilerOptions.listTypes == co2.CompilerOptions.listTypes &&
		co1.gw == co2.gw &&
		co1.bv == co2.bv &&
		co1.gc == co2.gc
							
572
PR_UpdateModules :: ![Modulename] !(ModInfo -> ModInfo) !Project -> Project
Diederik van Arkel's avatar
Diederik van Arkel committed
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
PR_UpdateModules mn update project
	= seq [(PR_UpdateModule m update) \\ m <- mn] project	// DvA quick hack, not very efficient!

//	Operations on tables

UpdateList :: !String InfUpdate !InfList -> (!InfList,!Bool)
UpdateList key update list = UpdateList2 key update list Nil
where
	UpdateList2 :: !String InfUpdate !InfList !InfList -> (!InfList,!Bool)
	UpdateList2 key update Nil acc
		=  (Reverse2 acc Nil,True)
	UpdateList2 key update ((first=:{mn,info}):!rest) acc
		| mn <> key
			= UpdateList2 key update rest (first:!acc)
		# (first,changed)	= update first
		= (Reverse2 acc (first :! rest), changed)

590
FindInList	:: !String !InfList -> Maybe InfListItem
Diederik van Arkel's avatar
Diederik van Arkel committed
591 592 593 594 595
FindInList key Nil									= Nothing
FindInList key ((itm=:{mn,info}):!rest)	| mn <> key	= FindInList key rest
													= Just itm

SetProject :: !{#Char} !{#Char} !ProjectGlobalOptions -> Project
596
SetProject applicationDir project_file_dir
597
		{ pg_codegen, pg_application
598 599
		, pg_projectPaths, pg_link, pg_mainModuleInfo={name, info}, pg_otherModules
		, pg_target, pg_staticLibInfo, pg_execpath, pg_dynamic
600
		, pg_root_directory, pg_precompile, pg_postlink, pg_bytecode_path
Diederik van Arkel's avatar
Diederik van Arkel committed
601
		}
602 603 604
	# project_dir = make_project_dir (size pg_root_directory) project_file_dir
	# paths = ExpandPaths applicationDir project_dir pg_projectPaths
	# linkOptions = ExpandLinkOptionsPaths applicationDir project_dir pg_link
605
	# project = PR_AddRootModule pg_codegen pg_application paths linkOptions name (ExpandModuleInfoPaths applicationDir project_dir info)
606 607
	# project		= addModules pg_otherModules project_dir project
	# staticLibInfo = ExpandStaticLibPaths applicationDir project_dir pg_staticLibInfo
Diederik van Arkel's avatar
Diederik van Arkel committed
608 609
	# project		= PR_SetStaticLibsInfo staticLibInfo project
	# project		= PR_SetTarget pg_target project
610
	# exepath		= ExpandPath applicationDir project_dir pg_execpath
611
	# bytecode_path	= if (pg_bytecode_path=="") "" (ExpandPath applicationDir project_dir pg_bytecode_path)
Diederik van Arkel's avatar
Diederik van Arkel committed
612 613
	# project		= PR_SetExecPath exepath project
	// default of used appopts in exe are ok isn't right :-(
614
	# pg_postlink	= case pg_postlink of
615
							Just post_link -> Just (ExpandPath applicationDir project_dir post_link)
616
							Nothing -> Nothing
617
	= {project & relative_root_directory = pg_root_directory, root_directory = project_dir, dynamic_info = pg_dynamic,
618
				 prec = pg_precompile, posl = pg_postlink, bytecode_path = bytecode_path}
Diederik van Arkel's avatar
Diederik van Arkel committed
619
where
620
	addModules Nil project_dir project
Diederik van Arkel's avatar
Diederik van Arkel committed
621
		=	project
622 623 624 625 626 627 628 629
	addModules ({name, info} :! t) project_dir project
		=	addModules t project_dir (PR_AddModule name (ExpandModuleInfoPaths applicationDir project_dir info) project)

GetProject :: !{#Char} !Project -> ProjectGlobalOptions
GetProject applicationDir project
	# project_dir = project.root_directory
	  post_link = case project.posl of
					Just post_link -> Just (SubstitutePath applicationDir project_dir post_link)
630
					Nothing -> Nothing 
631 632 633
	  mainModuleName = PR_GetRootModuleName project
	  target = PR_GetTarget project
	  (otherModuleNames,project`) = PR_GetModulenames False IclMod project
634 635 636 637 638
	  mainModuleInfo = getModule project_dir mainModuleName
	  otherModules = Map (getModule project_dir) (Filter ((<>) mainModuleName) otherModuleNames)
	  linkOptions = SubstituteLinkOptionsPaths applicationDir project_dir (PR_GetLinkOptions project)
	  projectPaths = SubstitutePaths applicationDir project_dir (PR_GetPaths project)
	  staticLibInfo = SubstituteStaticLibPaths applicationDir project_dir (PR_GetStaticLibsInfo project)
639
	=	{ pg_codegen			= PR_GetCodeGenOptions project
Diederik van Arkel's avatar
Diederik van Arkel committed
640 641 642 643 644 645 646
		, pg_application		= PR_GetApplicationOptions project
		, pg_projectPaths		= projectPaths
		, pg_link				= linkOptions
		, pg_mainModuleInfo		= mainModuleInfo
		, pg_otherModules		= otherModules
		, pg_staticLibInfo		= staticLibInfo
		, pg_target				= target
647
		, pg_execpath			= exepath project_dir
648
		, pg_bytecode_path		= bytecodepath project_dir
Diederik van Arkel's avatar
Diederik van Arkel committed
649
		, pg_dynamic			= project.dynamic_info
650
		, pg_root_directory		= project.relative_root_directory
Diederik van Arkel's avatar
Diederik van Arkel committed
651
		, pg_precompile			= project.prec
652
		, pg_postlink			= post_link
Diederik van Arkel's avatar
Diederik van Arkel committed
653 654
		}
where
655
	exepath project_dir
Diederik van Arkel's avatar
Diederik van Arkel committed
656
		# xp	= PR_GetExecPath project
657
		= symPath applicationDir project_dir xp
658 659 660
	bytecodepath project_dir
		# bcp	= PR_GetByteCodePath project
		= if (bcp=="") "" (symPath applicationDir project_dir bcp)
661

662
	getModule project_dir name
Diederik van Arkel's avatar
Diederik van Arkel committed
663 664
		# info = PR_GetModuleInfo name project
		# info = if (isJust info) (fromJust info) defaultModInfo
665
		# info = SubstituteModuleInfoPaths applicationDir project_dir info
Diederik van Arkel's avatar
Diederik van Arkel committed
666
		= {name = name, info = info}
667

Diederik van Arkel's avatar
Diederik van Arkel committed
668 669
	defaultModInfo :: ModInfo
	defaultModInfo	=
670 671 672 673
		{ dir = EmptyPathname
		, compilerOptions = DefaultCompilerOptions
		, mod_edit_options = {	defeo = defaultEditWdOptions,impeo = defaultEditWdOptions,
								defopen = False,impopen = False}
Diederik van Arkel's avatar
Diederik van Arkel committed
674 675 676
		, abcLinkInfo = {linkObjFileNames = Nil, linkLibraryNames = Nil} 
		}
	where
677
		defaultEditWdOptions = {eo=DefaultEditOptions,pos_size=NoWindowPosAndSize}
Diederik van Arkel's avatar
Diederik van Arkel committed
678 679 680 681 682 683 684 685 686 687 688 689
		DefaultEditOptions =
			{ newlines = HostNativeNewlineConvention}
/*			{ tabs = 4
			, fontname = "Courier New"	//NonProportionalFontDef.fName
			, fontsize = 10				//NonProportionalFontDef.fSize
			, autoi = True
			, newlines = HostNativeNewlineConvention
			, showtabs = False
			, showlins = False
			, showsync = True
			} 
*/
690

691 692 693 694 695 696 697 698 699
make_project_dir :: !Int !{#Char} -> {#Char}
make_project_dir n_dots project_directory
	| n_dots>1
		# parent_of_project_directory = RemoveFilename project_directory
		| size parent_of_project_directory==size project_directory || size parent_of_project_directory==0
			= project_directory // error, not enough directories
			= make_project_dir (n_dots-1) parent_of_project_directory
		= project_directory

Diederik van Arkel's avatar
Diederik van Arkel committed
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
ExpandModuleInfoPaths :: {#Char} {#Char} ModInfo -> ModInfo
ExpandModuleInfoPaths applicationDir projectDir moduleInfo=:{dir}
	= {moduleInfo & dir = ExpandPath applicationDir projectDir dir}

ExpandLinkOptionsPaths :: {#Char} {#Char} LinkOptions -> LinkOptions
ExpandLinkOptionsPaths applicationDir projectDir linkOptions=:{extraObjectModules, libraries}
	=	{ linkOptions
		& extraObjectModules	= ExpandPaths applicationDir projectDir extraObjectModules
		, libraries				= ExpandPaths applicationDir projectDir libraries
		}

ExpandStaticLibPaths :: {#Char} {#Char} StaticLibInfo -> StaticLibInfo
ExpandStaticLibPaths applicationDir projectDir staticLibs=:{sLibs}
	=	{ staticLibs
		& sLibs = ExpandPaths applicationDir projectDir sLibs
		}

//ExpandPaths :: {#Char} {#Char} (List {#Char}) -> List {#Char}
ExpandPaths applicationDir projectDir list
	:== fulPaths applicationDir projectDir list

ExpandPath applicationDir projectDir path
	:== fulPath applicationDir projectDir path

SubstituteModuleInfoPaths :: {#Char} {#Char} ModInfo -> ModInfo
SubstituteModuleInfoPaths applicationDir projectDir info
	=	{info & dir = SubstitutePath applicationDir projectDir info.dir}

SubstituteLinkOptionsPaths :: {#Char} {#Char} LinkOptions -> LinkOptions
SubstituteLinkOptionsPaths applicationDir projectDir linkOptions=:{extraObjectModules, libraries}
	=	{linkOptions
		& extraObjectModules = SubstitutePaths applicationDir projectDir extraObjectModules
		, libraries = SubstitutePaths applicationDir projectDir libraries
		}

SubstituteStaticLibPaths :: {#Char} {#Char} StaticLibInfo -> StaticLibInfo
SubstituteStaticLibPaths applicationDir projectDir staticLibs=:{sLibs}
	=	{ staticLibs
		& sLibs = SubstitutePaths applicationDir projectDir sLibs
		}

//SubstitutePaths :: {#Char} {#Char} (List {#Char}) -> List {#Char}
SubstitutePaths applicationDir projectDir list
	:== symPaths applicationDir projectDir list

SubstitutePath applicationDir projectDir path
	:== symPath applicationDir projectDir path

748
PR_GetABCLinkInfo :: !Project -> (!(List (Modulename, LinkObjFileName)), !(List (Modulename, LinkLibraryName)))
Diederik van Arkel's avatar
Diederik van Arkel committed
749
PR_GetABCLinkInfo project=:{inflist}
750
	# allLinkInfoRecords = [toRecord el\\el<|-inflist];
751
	= foldl mergeTwoRecords emptyRecord allLinkInfoRecords;
Diederik van Arkel's avatar
Diederik van Arkel committed
752
where
753 754 755 756
		toRecord {InfListItem | mn,info={abcLinkInfo}} =
			(Map mkHierarchical abcLinkInfo.linkObjFileNames
			,Map mkHierarchical abcLinkInfo.linkLibraryNames)
		where
757
			mkHierarchical linkobj = (removeLastComponent mn (max 0 (size mn - 1)), linkobj)
758 759 760 761 762 763

			removeLastComponent s 0 = ""
			removeLastComponent s i
				| s.[i] == '.' = s % (0, i-1)
				= removeLastComponent s (i-1)

764 765
		mergeTwoRecords (objs, libs) (cobjs, clibs) = (UnionList objs cobjs, UnionList libs clibs)
		emptyRecord = (Nil, Nil);
Diederik van Arkel's avatar
Diederik van Arkel committed
766

767
PR_GetStaticLibsInfo :: !Project -> StaticLibInfo
Diederik van Arkel's avatar
Diederik van Arkel committed
768 769 770 771 772 773
PR_GetStaticLibsInfo {Project | staticLibInfo} = staticLibInfo

PR_SetStaticLibsInfo :: !StaticLibInfo !Project -> Project
PR_SetStaticLibsInfo staticLibInfo project
	= {Project | project & staticLibInfo = staticLibInfo}

774
PR_GetTarget :: !Project -> String
Diederik van Arkel's avatar
Diederik van Arkel committed
775 776 777
PR_GetTarget {Project | target} = target

PR_SetTarget :: !String !Project -> Project
Diederik van Arkel's avatar
Diederik van Arkel committed
778 779 780 781
PR_SetTarget target project
	| target == project.Project.target
		= project
		= {Project | project & target = target, exec = False, saved = False}
Diederik van Arkel's avatar
Diederik van Arkel committed
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816

SL_Add :: !String !StaticLibInfo -> StaticLibInfo
SL_Add pathname sl
	// load sDcls and sDeps info...
	// read some kind of libdef file...
	= {sl & sLibs = Append sl.sLibs pathname}

SL_Rem :: ![String] !String !String !StaticLibInfo -> StaticLibInfo
SL_Rem pathsel ap pp sl
	// remove sDcls and sDeps...
	= {sl & sLibs = seq
		[ RemoveStringFromList (fulPath ap pp s)
		\\ s <- pathsel
		] sl.sLibs}

SL_Libs :: !StaticLibInfo -> List String
SL_Libs sl=:{sLibs} = sLibs

SL_Dcls :: !StaticLibInfo -> List String
SL_Dcls sl=:{sDcls} = sDcls

SL_Deps :: !StaticLibInfo -> List String
SL_Deps sl=:{sDeps} = sDeps

SL_SetLibs :: !(List String) !StaticLibInfo -> StaticLibInfo
SL_SetLibs lp sl = {sl & sLibs = lp}

SL_SetDcls :: !(List String) !StaticLibInfo -> StaticLibInfo
SL_SetDcls lp sl = {sl & sDcls = lp}

SL_SetDeps :: !(List String) !StaticLibInfo -> StaticLibInfo
SL_SetDeps lp sl = {sl & sDeps = lp}

SaveProjectFile	:: !String !Project !String !*Files -> (!Bool, !*Files);
SaveProjectFile	projectPath project applicationDir files
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
	= IF_WINDOWS
		(SaveProjectAndPropsFile projectPath project applicationDir files)
		(SaveProjectFileOnly projectPath project applicationDir files)
where
	SaveProjectAndPropsFile	projectPath project applicationDir files
		# (opened, prj_file, files) = fopen projectPath FWriteText files
		| not opened
			=	(False, files)
		# prp_path = RemoveSuffix` projectPath +++ ".prp"
		# (opened, prp_file, files) = fopen prp_path FWriteText files
		| not opened
			# (_,files) = fclose prj_file files
			=	(False, files)
		#! projectGO				= GetProject applicationDir project
		# projectGO = sort_modules projectGO
		# prj_file = WriteOptionsFile ProjectFileVersion (PutOptions project_table projectGO) prj_file
		# prp_file = WriteOptionsFile ProjectFileVersion (PutOptions edit_options_table projectGO) prp_file
		#! (prj_ok, files) = fclose prj_file files
		#! (prp_ok, files) = fclose prp_file files
		= (prj_ok && prp_ok, files)
		
	SaveProjectFileOnly projectPath project applicationDir files
		# (opened, prj_file, files) = fopen projectPath FWriteText files
		| not opened
			=	(False, files)
		#! projectGO				= GetProject applicationDir project
		# projectGO = sort_modules projectGO
		# prj_file = WriteOptionsFile ProjectFileVersion (PutOptions project_table projectGO) prj_file
		#! (prj_ok, files) = fclose prj_file files
		= (prj_ok, files)
847

848 849 850 851 852 853 854 855 856 857 858
save_project_template_file :: !String !Project !String !*Files -> (!Bool, !*Files);
save_project_template_file projectPath project applicationDir files
	# (opened, prt_file, files) = fopen projectPath FWriteText files
	| not opened
		=	(False, files)
	#! projectGO = GetProject applicationDir project
	#! main_module_dir_path = projectGO.pg_mainModuleInfo.ModInfoAndName.info.dir
	# projectGO = {projectGO & pg_projectPaths = [|p \\ p<|-projectGO.pg_projectPaths | p<>main_module_dir_path]}
	# prt_file = WriteOptionsFile ProjectFileVersion (PutOptions project_template_table projectGO) prt_file
	= fclose prt_file files

859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
sort_modules :: !ProjectGlobalOptions -> ProjectGlobalOptions
sort_modules projectGO=:{pg_projectPaths,pg_otherModules}
	# project_paths = {project_path \\ project_path<|-pg_projectPaths}
	# n_project_paths = size project_paths
	# (project_modules,other_modules) = collect_project_modules pg_otherModules (createArray n_project_paths [!!]) project_paths
	# pg_otherModules = append_project_modules 0 project_modules other_modules
	= {projectGO & pg_otherModules=pg_otherModules}
  where
	collect_project_modules :: ![!ModInfoAndName!] !*{![!ModInfoAndName!]} !{#Pathname} -> (!*{![!ModInfoAndName!]},![!ModInfoAndName!])
	collect_project_modules [!mod=:{ModInfoAndName|info={dir}}:mods!] project_modules project_paths
		# path_index = find_path dir 0 project_paths
		| path_index>=0
			# (modules_in_dir,project_modules) = project_modules![path_index]
			# project_modules = {project_modules & [path_index] = [!mod:modules_in_dir!]}
			= collect_project_modules mods project_modules project_paths
			# (project_modules,other_modules) = collect_project_modules mods project_modules project_paths
			= (project_modules,[!mod:other_modules!])
	collect_project_modules [!!] project_modules project_paths
		= (project_modules,[!!])

	find_path :: !{#Char} !Int !{#{#Char}} -> Int
	find_path dir i project_paths
		| i<size project_paths
			| project_paths.[i]==dir
				= i
				= find_path dir (i+1) project_paths
			= -1

	append_project_modules :: !Int !{![!ModInfoAndName!]} [!ModInfoAndName!] -> [!ModInfoAndName!]
	append_project_modules i project_modules other_modules
		| i<size project_modules
			= sort_by_name project_modules.[i] ++| append_project_modules (i+1) project_modules other_modules
			= sort_by_dir_and_name other_modules

	sort_by_name :: !u:[!ModInfoAndName!] -> u:[!ModInfoAndName!]
	sort_by_name l = Hd (msort (pair l)) // mergesort
	  where
		pair [|x1,x2:xs]
			| x2.name < x1.name
				= [[|x2,x1]:pair xs];
				= [[|x1,x2]:pair xs];
		pair x = [|x];

		msort [|x1,x2:xs] = msort (merge_stage [|x1,x2:xs]);
		msort x	= x;

		merge_stage [|xs1,xs2:xxs] = [|merge xs1 xs2 : merge_stage xxs];
		merge_stage x = x;
	
		merge :: !u:[!ModInfoAndName!] !v:[!ModInfoAndName!] -> w:[!ModInfoAndName!], [u v <= w];
		merge [|] y = y
		merge f=:[|x:xs] [|] = f
		merge f=:[|x:xs] s=:[|y:ys]
			| y.name < x.name
				= [|y:merge f ys]
				= [|x:merge xs s]

	sort_by_dir_and_name :: !u:[!ModInfoAndName!] -> u:[!ModInfoAndName!]
	sort_by_dir_and_name l = Hd (msort (pair l)) // mergesort
	  where
		pair [|x1,x2:xs]
			| x2.ModInfoAndName.info.dir == x1.ModInfoAndName.info.dir
				| x2.name < x1.name
					= [[|x2,x1]:pair xs];
					= [[|x1,x2]:pair xs];
				| x2.ModInfoAndName.info.dir < x1.ModInfoAndName.info.dir
					= [[|x2,x1]:pair xs];
					= [[|x1,x2]:pair xs];
		pair x = [|x];

		msort [|x1,x2:xs] = msort (merge_stage [|x1,x2:xs]);
		msort x	= x;

		merge_stage [|xs1,xs2:xxs] = [|merge xs1 xs2 : merge_stage xxs];
		merge_stage x = x;
	
		merge :: !u:[!ModInfoAndName!] !v:[!ModInfoAndName!] -> w:[!ModInfoAndName!], [u v <= w];
		merge [|] y = y
		merge f=:[|x:xs] [|] = f
		merge f=:[|x:xs] s=:[|y:ys]
			| y.ModInfoAndName.info.dir == x.ModInfoAndName.info.dir
				| y.name < x.name
					= [|y:merge f ys]
					= [|x:merge xs s]
				| y.ModInfoAndName.info.dir < x.ModInfoAndName.info.dir
					= [|y:merge f ys]
					= [|x:merge xs s]
Diederik van Arkel's avatar
Diederik van Arkel committed
946

947 948 949
ReadProjectFile	:: !String !String !*Files -> (!(!Project, !Bool, !{#Char}),!*Files)
ReadProjectFile projectPath applicationDir files
	#	(opened, file, files)	= fopen projectPath FReadData files
Diederik van Arkel's avatar
Diederik van Arkel committed
950 951 952 953
		emptyProject			= PR_InitProject
		projectName				= RemovePath projectPath
		projectDir				= RemoveFilename projectPath
	| not opened
954
		= ((emptyProject,False,"The file \"" +++  projectName +++ "\" could not be opened."),files)
Diederik van Arkel's avatar
Diederik van Arkel committed
955 956
	#	(version, file)			= ReadVersion file
	| version == ""
957 958
		#	(_, files)			= fclose file files
		=	((emptyProject,False,"The file \"" +++  projectName +++ "\" is an old project and could not be opened."),files)
Diederik van Arkel's avatar
Diederik van Arkel committed
959
	#!	(options, file)			= ReadOptionsFile file
960 961 962 963
		empty_projectGO			= GetProject applicationDir emptyProject
		projectGO				= GetOptions ProjectTable options empty_projectGO
		(projectGO,files)
			= add_edit_options_from_prp_file (RemoveSuffix` projectPath +++ ".prp") projectGO empty_projectGO files
964
		projectGO				= (if (version == "1.3")
Diederik van Arkel's avatar
Diederik van Arkel committed
965 966
									(\p->{p&pg_target="StdEnv"})
									(id)
967 968 969
								) projectGO	// DvA: need to set needs save flag for project;
		unexpanded_exec_path	= projectGO.pg_execpath
		project					= SetProject applicationDir projectDir projectGO
Diederik van Arkel's avatar
Diederik van Arkel committed
970 971
		execpath				= PR_GetExecPath project
		(rootpath,project)		= PR_GetRootPathName project
972
		project					= PR_SetExecPath (if (size unexpanded_exec_path==0) (MakeExecPathname rootpath) execpath) project
973
		(closed, files)			= fclose file files
Diederik van Arkel's avatar
Diederik van Arkel committed
974 975
	| not closed
		// generate warning?
976 977 978
		=	((project, True,"The file \"" +++ projectName +++ "\" could not be closed."), files)
	=	((project, True,""), files)

979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999
read_project_template_file :: !String !String !*Files -> (!(!Bool, !Project, !{#Char}),!*Files)
read_project_template_file template_file_path applicationDir files
	# (opened, file, files)	= fopen template_file_path FReadData files
	  empty_project = PR_InitProject
	  template_file_name = RemovePath template_file_path
	  template_file_dir = RemoveFilename template_file_path
	| not opened
		= ((False,empty_project,"The file \"" +++  template_file_name +++ "\" could not be opened."),files)
	# (version, file) = ReadVersion file
	| size version==0
		# (_, files) = fclose file files
		= ((False,empty_project,"The file \"" +++  template_file_name +++ "\" is not a project template and could not be opened."),files)
	# (options, file) = ReadOptionsFile file
	  empty_projectGO = GetProject applicationDir empty_project
	  projectGO = GetOptions project_template_table options empty_projectGO
	  project = SetProject applicationDir template_file_dir projectGO
	  (closed, files) = fclose file files
	| not closed
		= ((False,empty_project,"Could not read the file \"" +++ template_file_name +++ "\"."), files)
	= ((True,project,""), files)

1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
add_edit_options_from_prp_file :: !String !ProjectGlobalOptions !ProjectGlobalOptions !*Files -> (!ProjectGlobalOptions, !*Files)
add_edit_options_from_prp_file prp_path projectGO empty_projectGO files
	# (opened, prp_file, files) = fopen prp_path FReadData files
	| not opened
		= (projectGO, files)
	# (version, prp_file) = ReadVersion prp_file
	| size version==0
		= (projectGO, files)
	# (options,prp_file) = ReadOptionsFile prp_file
	#! edit_projectGO = GetOptions ProjectTable options empty_projectGO
	# (closed, files) = fclose prp_file files
	| not closed
		= (projectGO, files)
		# projectGO = add_edit_options edit_projectGO projectGO
		= (projectGO, files)

add_edit_options :: !ProjectGlobalOptions !ProjectGlobalOptions -> ProjectGlobalOptions
add_edit_options {pg_mainModuleInfo,pg_otherModules} projectGO
	#! edit_options = pg_mainModuleInfo.ModInfoAndName.info.mod_edit_options
	# other_modules = add_edit_options_of_other_modules pg_otherModules projectGO.pg_otherModules
	= {projectGO & pg_mainModuleInfo.ModInfoAndName.info.mod_edit_options = edit_options, pg_otherModules = other_modules}
  where
	add_edit_options_of_other_modules (m=:{name,info}:!mods_edit_options) (mod:!mods)
		// the IDE saves the modules in the .prj and .prp files in the same order
		| mod.ModInfoAndName.name==name && mod.ModInfoAndName.info.dir==info.dir
			# mod = {mod & ModInfoAndName.info.mod_edit_options = info.mod_edit_options}
			  mods = add_edit_options_of_other_modules mods_edit_options mods
			= mod:!mods
			// slow version in case the .prj and .prp file were not saved together 
			# mods = add_edit_options_of_other_module m mods
			= add_edit_options_of_other_modules mods_edit_options (mod:!mods)
	add_edit_options_of_other_modules mods_edit_options Nil
		= mods_edit_options
	add_edit_options_of_other_modules Nil mods
		= mods

	add_edit_options_of_other_module m=:{name,info} (mod:!mods)
		| mod.ModInfoAndName.name==name && mod.ModInfoAndName.info.dir==info.dir
			= {mod & ModInfoAndName.info.mod_edit_options = info.mod_edit_options} :! mods
			= mod :! add_edit_options_of_other_module m mods
	add_edit_options_of_other_module m Nil
	 	= m:!Nil

1043 1044 1045
change_root_directory_of_project :: !{#Char} !{#Char} !Project -> Project 
change_root_directory_of_project relative_root_dir root_dir project
	= {project & relative_root_directory=relative_root_dir, root_directory=root_dir}
Diederik van Arkel's avatar
Diederik van Arkel committed
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063

getDynamicInfo :: !Project -> (ProjectDynamicInfo,Project)
getDynamicInfo prj=:{dynamic_info} = (dynamic_info,prj)

setDynamicInfo :: !.ProjectDynamicInfo !.Project -> .Project
setDynamicInfo inf prj = {prj & dynamic_info = inf}

PR_SetPrecompile	:: !(Maybe String) !Project -> Project
PR_SetPrecompile prec prj = {prj & prec = prec}

PR_GetPrecompile	:: !Project -> (!Maybe String, !Project)
PR_GetPrecompile prj=:{prec} = (prec,prj)

PR_SetPostlink		:: !(Maybe String) !Project -> Project
PR_SetPostlink posl prj = {prj & posl = posl}

PR_GetPostlink		:: !Project -> (!Maybe String, !Project)
PR_GetPostlink prj=:{posl} = (posl,prj)