PmProject.icl 41.2 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

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
116
	, bytecode_path	= "{Project}"+++DirSeparatorString+++modname+++".bc"
Diederik van Arkel's avatar
Diederik van Arkel committed
117 118 119 120
	, inflist		=
		{ mn		= modname
		, info		=	{ dir		= "{Project}"//dirname
						, compilerOptions		= compilerOptions
121
						, mod_edit_options = {defeo=eo,impeo=eo,defopen=False,impopen=True}
Diederik van Arkel's avatar
Diederik van Arkel committed
122 123 124 125 126 127 128 129 130 131 132 133
						, 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"
134
	, root_directory = dirname
Diederik van Arkel's avatar
Diederik van Arkel committed
135 136
	}

137 138 139 140 141 142 143
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";

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

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

163 164
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
165
	= project
166
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
167 168
	# inflist		= TryInsertInList mod_name mod_dir inflist
	# (inflist,_)	= UpdateList mod_name update inflist;
169
	= {project & saved=False,inflist=inflist}
Diederik van Arkel's avatar
Diederik van Arkel committed
170 171 172 173 174 175 176 177 178
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)

179
	TryInsertInList :: !String !String !InfList -> InfList
Diederik van Arkel's avatar
Diederik van Arkel committed
180 181 182 183 184 185 186 187 188
	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
189
		TryInsertImporter ::	!InfList !InfList -> InfList
Diederik van Arkel's avatar
Diederik van Arkel committed
190
		TryInsertImporter Nil list
191
			# default_edit_options = {pos_size = NoWindowPosAndSize, eo = {newlines= HostNativeNewlineConvention}}
Diederik van Arkel's avatar
Diederik van Arkel committed
192 193 194
			# item =
				  {	mn		= importermn, 
					info	= { dir		= importerdir,
195 196 197
								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
198 199 200 201 202 203 204 205 206 207 208
								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}
209
	= {project & saved = False, inflist = Nil}
Diederik van Arkel's avatar
Diederik van Arkel committed
210
PR_ClearDependencies project=:{inflist=il=:(root :! rest)}
211
	= {project & saved = False, inflist = root` :! Nil}
Diederik van Arkel's avatar
Diederik van Arkel committed
212
where
213 214
	root` = {InfListItem | root & info.abcLinkInfo = {linkObjFileNames = Nil, linkLibraryNames = Nil}}

Diederik van Arkel's avatar
Diederik van Arkel committed
215 216 217 218 219 220 221 222 223
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,
224 225 226 227
											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
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 306
											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 &&
307
		ao1.disable_rts_flags == ao2.disable_rts_flags &&		
Diederik van Arkel's avatar
Diederik van Arkel committed
308 309 310 311 312 313 314 315
		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 &&
316
		ao1.generic_fusion == ao2.generic_fusion &&
317 318
		ao1.dynamics == ao2.dynamics &&
		ao1.desc_exl == ao2.desc_exl &&
Diederik van Arkel's avatar
Diederik van Arkel committed
319 320 321 322 323 324 325
		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 &&
326
	lo1.generate_symbol_table == lo2.generate_symbol_table &&
Diederik van Arkel's avatar
Diederik van Arkel committed
327 328 329 330 331 332
	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 &&
333
	lo1.dll_export_list_name == lo2.dll_export_list_name
Diederik van Arkel's avatar
Diederik van Arkel committed
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348

	
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;
349
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
350
	| def	= {Project | project &
Diederik van Arkel's avatar
Diederik van Arkel committed
351 352
							saved				= saved && olddirs,
							inflist				= inflist1 };
Diederik van Arkel's avatar
Diederik van Arkel committed
353
			= {Project | project &
Diederik van Arkel's avatar
Diederik van Arkel committed
354 355 356 357 358 359 360 361 362 363 364 365 366 367
							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);
368
					= ({itm & info = {minfo & dir=""}, src=False},False);
Diederik van Arkel's avatar
Diederik van Arkel committed
369 370 371 372 373 374
			where 
				unchanged	= StringOccurs dir defs || StringOccurs dir prjpaths1;
			
		
		
PR_GetCodeGenOptions :: !Project -> CodeGenOptions;
375
PR_GetCodeGenOptions {codegenopt} =  codegenopt;
Diederik van Arkel's avatar
Diederik van Arkel committed
376

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

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

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

392
PR_GetRootPathName	:: !Project -> (!String,!Project)
Diederik van Arkel's avatar
Diederik van Arkel committed
393 394 395 396 397 398 399
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)

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

408 409 410 411 412 413 414 415
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)

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

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

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

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

439 440 441 442 443 444 445 446 447 448
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
449 450 451 452
PR_GetOpenModulenames	:: !Project -> List String
PR_GetOpenModulenames project=:{inflist}
	= FlattenList modnames
where 
453 454 455
	modnames = MapR GetModulenames inflist

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

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
482

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

Diederik van Arkel's avatar
Diederik van Arkel committed
491 492 493 494 495 496 497 498 499
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;

500
PR_AddRootModule ::	!CodeGenOptions !ApplicationOptions !(List String) !LinkOptions
Diederik van Arkel's avatar
Diederik van Arkel committed
501
					!Modulename !ModInfo -> Project;
502
PR_AddRootModule cg ao prjs linkOptions mn info=:{dir}
Diederik van Arkel's avatar
Diederik van Arkel committed
503
  = { PR_InitProject
504
  	& saved			= False
Diederik van Arkel's avatar
Diederik van Arkel committed
505
	, exec			= True
506
	, execpath		= ""
Diederik van Arkel's avatar
Diederik van Arkel committed
507 508 509 510 511 512 513 514 515 516 517 518
	, 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 };
519

Diederik van Arkel's avatar
Diederik van Arkel committed
520
PR_AddModule :: !Modulename !ModInfo !Project -> Project;
521 522
PR_AddModule mn info=:{dir} project=:{inflist=root:!rest}
	= {project & inflist = root:!new:!rest};
Diederik van Arkel's avatar
Diederik van Arkel committed
523 524 525 526 527
where 
	new	= {	mn		= mn,
			info	= info,
			src		= True,
			abc		= True };
528 529
PR_AddModule mn info=:{dir} project=:{inflist=Nil}
	= {project & inflist = new:!Nil};
Diederik van Arkel's avatar
Diederik van Arkel committed
530 531 532 533 534 535
where 
	new	= {	mn		= mn,
			info	= info,
			src		= True,
			abc		= True };
	
536
PR_GetModuleInfo :: !Modulename !Project -> Maybe ModInfo
Diederik van Arkel's avatar
Diederik van Arkel committed
537 538 539 540 541 542
PR_GetModuleInfo mn {Project | inflist}
	# item = FindInList mn inflist
	| isNothing item
		= Nothing
	= Just (fromJust item).InfListItem.info
	
543
PR_UpdateModule :: !Modulename !(ModInfo -> ModInfo) !Project -> Project;
Diederik van Arkel's avatar
Diederik van Arkel committed
544 545 546 547 548 549 550 551 552 553
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
554 555 556
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
557
		eqCO info1.compilerOptions info2.compilerOptions &&
558 559 560 561
		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
562 563 564 565 566 567 568 569 570 571 572

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
							
573
PR_UpdateModules :: ![Modulename] !(ModInfo -> ModInfo) !Project -> Project
Diederik van Arkel's avatar
Diederik van Arkel committed
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
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)

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

SetProject :: !{#Char} !{#Char} !ProjectGlobalOptions -> Project
597
SetProject applicationDir project_file_dir
598
		{ pg_codegen, pg_application
599 600
		, pg_projectPaths, pg_link, pg_mainModuleInfo={name, info}, pg_otherModules
		, pg_target, pg_staticLibInfo, pg_execpath, pg_dynamic
601
		, pg_root_directory, pg_precompile, pg_postlink, pg_bytecode_path
Diederik van Arkel's avatar
Diederik van Arkel committed
602
		}
603 604 605
	# 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
606
	# project = PR_AddRootModule pg_codegen pg_application paths linkOptions name (ExpandModuleInfoPaths applicationDir project_dir info)
607 608
	# project		= addModules pg_otherModules project_dir project
	# staticLibInfo = ExpandStaticLibPaths applicationDir project_dir pg_staticLibInfo
Diederik van Arkel's avatar
Diederik van Arkel committed
609 610
	# project		= PR_SetStaticLibsInfo staticLibInfo project
	# project		= PR_SetTarget pg_target project
611
	# exepath		= ExpandPath applicationDir project_dir pg_execpath
612
	# bytecode_path	= if (pg_bytecode_path=="") "" (ExpandPath applicationDir project_dir pg_bytecode_path)
Diederik van Arkel's avatar
Diederik van Arkel committed
613 614
	# project		= PR_SetExecPath exepath project
	// default of used appopts in exe are ok isn't right :-(
615
	# pg_postlink	= case pg_postlink of
616
							Just post_link -> Just (ExpandPath applicationDir project_dir post_link)
617
							Nothing -> Nothing
618
	= {project & relative_root_directory = pg_root_directory, root_directory = project_dir, dynamic_info = pg_dynamic,
619
				 prec = pg_precompile, posl = pg_postlink, bytecode_path = bytecode_path}
Diederik van Arkel's avatar
Diederik van Arkel committed
620
where
621
	addModules Nil project_dir project
Diederik van Arkel's avatar
Diederik van Arkel committed
622
		=	project
623 624 625 626 627 628 629 630
	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)
631
					Nothing -> Nothing 
632 633 634
	  mainModuleName = PR_GetRootModuleName project
	  target = PR_GetTarget project
	  (otherModuleNames,project`) = PR_GetModulenames False IclMod project
635 636 637 638 639
	  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)
640
	=	{ pg_codegen			= PR_GetCodeGenOptions project
Diederik van Arkel's avatar
Diederik van Arkel committed
641 642 643 644 645 646 647
		, pg_application		= PR_GetApplicationOptions project
		, pg_projectPaths		= projectPaths
		, pg_link				= linkOptions
		, pg_mainModuleInfo		= mainModuleInfo
		, pg_otherModules		= otherModules
		, pg_staticLibInfo		= staticLibInfo
		, pg_target				= target
648
		, pg_execpath			= exepath project_dir
649
		, pg_bytecode_path		= bytecodepath project_dir
Diederik van Arkel's avatar
Diederik van Arkel committed
650
		, pg_dynamic			= project.dynamic_info
651
		, pg_root_directory		= project.relative_root_directory
Diederik van Arkel's avatar
Diederik van Arkel committed
652
		, pg_precompile			= project.prec
653
		, pg_postlink			= post_link
Diederik van Arkel's avatar
Diederik van Arkel committed
654 655
		}
where
656
	exepath project_dir
Diederik van Arkel's avatar
Diederik van Arkel committed
657
		# xp	= PR_GetExecPath project
658
		= symPath applicationDir project_dir xp
659 660 661
	bytecodepath project_dir
		# bcp	= PR_GetByteCodePath project
		= if (bcp=="") "" (symPath applicationDir project_dir bcp)
662

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

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

692 693 694 695 696 697 698 699 700
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
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 748
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

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

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

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

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

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

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

PR_SetTarget :: !String !Project -> Project
779 780 781 782
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
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 817

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
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 847
	= 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)
848

849 850 851 852 853 854 855 856 857 858 859
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

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 946
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
947

948 949 950
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
951 952 953 954
		emptyProject			= PR_InitProject
		projectName				= RemovePath projectPath
		projectDir				= RemoveFilename projectPath
	| not opened
955
		= ((emptyProject,False,"The file \"" +++  projectName +++ "\" could not be opened."),files)
Diederik van Arkel's avatar
Diederik van Arkel committed
956 957
	#	(version, file)			= ReadVersion file
	| version == ""
958 959
		#	(_, 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
960
	#!	(options, file)			= ReadOptionsFile file
961 962 963 964
		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
965
		projectGO				= (if (version == "1.3")
Diederik van Arkel's avatar
Diederik van Arkel committed
966 967
									(\p->{p&pg_target="StdEnv"})
									(id)
968 969 970
								) 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
971 972
		execpath				= PR_GetExecPath project
		(rootpath,project)		= PR_GetRootPathName project
973
		project					= PR_SetExecPath (if (size unexpanded_exec_path==0) (MakeExecPathname rootpath) execpath) project
974
		(closed, files)			= fclose file files
Diederik van Arkel's avatar
Diederik van Arkel committed
975 976
	| not closed
		// generate warning?
977 978 979
		=	((project, True,"The file \"" +++ projectName +++ "\" could not be closed."), files)
	=	((project, True,""), files)

980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
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)

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
create_new_project_using_template :: !String !String !CompilerOptions !EditWdOptions !Project !*Files -> ((!Bool, !Project), !*Files)
create_new_project_using_template path project_file_path compopts eo project ps
	# template_root_dir = PR_GetRootDir project
	# project = PR_SetRoot path eo compopts project
	# project = PR_SetExecPath (MakeExecPathname path) project
	# project = PR_SetByteCodePath (RemoveSuffix path +++ ".bc") project
	# project = set_root_directory_of_project (RemoveFilename project_file_path) template_root_dir project
	= ((True, project), ps)
  where
	set_root_directory_of_project :: !{#Char} !{#Char} !Project -> Project
	set_root_directory_of_project project_file_dir template_root_dir project
		| size project_file_dir<=size template_root_dir || project_file_dir % (0,size template_root_dir-1)<>template_root_dir
			= change_root_directory_of_project "." project_file_dir project
		# (n_removed_dirs,project_dir) = count_dirs_to_be_removed 0 (size template_root_dir) project_file_dir
		| project_dir==template_root_dir
			= change_root_directory_of_project (createArray (n_removed_dirs+1) '.') template_root_dir project
		= change_root_directory_of_project "." project_file_dir project

	count_dirs_to_be_removed :: !Int !Int !{#Char} -> (!Int,!{#Char}) 
	count_dirs_to_be_removed n_removed_dirs template_root_dir_size project_dir
		# project_dir_up = RemoveFilename project_dir
		| size project_dir_up==size project_dir
			= (n_removed_dirs,project_dir)
		| size project_dir_up>template_root_dir_size
			= count_dirs_to_be_removed (n_removed_dirs+1) template_root_dir_size project_dir_up
			= (n_removed_dirs+1,project_dir_up)

1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
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

1071 1072 1073
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
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091

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)