PageRenderTime 79ms CodeModel.GetById 2ms app.highlight 71ms RepoModel.GetById 1ms app.codeStats 0ms

/src/xf/nucleus/kdef/KDefProcessor.d

https://bitbucket.org/h3r3tic/boxen
D | 882 lines | 686 code | 162 blank | 34 comment | 116 complexity | 3400da440c64b57863d50e6708197f95 MD5 | raw file
  1module xf.nucleus.kdef.KDefProcessor;
  2
  3private {
  4	import tango.core.Tuple;
  5	
  6	import
  7		xf.nucleus.kdef.model.IKDefFileParser,
  8		xf.nucleus.kdef.model.KDefInvalidation,
  9		xf.nucleus.kdef.KDefParserBase,
 10		xf.nucleus.kdef.Common,
 11		xf.nucleus.kdef.ParamUtils;
 12
 13	import
 14		xf.nucleus.kernel.KernelDef;
 15
 16	import
 17		xf.nucleus.Defs,
 18		xf.nucleus.TypeSystem,
 19		xf.nucleus.TypeConversion,
 20		xf.nucleus.Function,
 21		xf.nucleus.Param,
 22		xf.nucleus.Value,
 23		xf.nucleus.KernelImpl,
 24		xf.nucleus.SurfaceDef,
 25		xf.nucleus.MaterialDef,
 26		Dep = xf.nucleus.DepTracker;
 27
 28	import
 29		xf.mem.ScratchAllocator,
 30		xf.mem.StackBuffer,
 31		xf.mem.Gather;
 32		
 33	import xf.utils.Graph	: findTopologicalOrder, CycleHandlingMode;
 34	import xf.utils.Memory	: alloc, free, append;
 35	import xf.nucleus.Log	: error = nucleusError, log = nucleusLog;
 36
 37	import tango.io.Stdout;		// for dumpInfo, could be moved outside, to another mod
 38	import tango.io.vfs.model.Vfs;
 39	
 40	alias char[] string;
 41}
 42
 43
 44
 45class KDefProcessor {
 46	alias DgScratchAllocator Allocator;
 47
 48
 49	this (IKDefFileParser fileParser) {
 50		this.fileParser = fileParser;
 51	}
 52
 53
 54	static Allocator modAlloc(KDefModule mod) {
 55		return mod.mem;
 56	}
 57	
 58	
 59	void processFile(string path) {
 60		if (auto mod = path in _modules) {
 61			if ((*mod).processing) {
 62				throw new Exception("Cyclic import in kernel module '" ~ path ~ "'");
 63			}
 64		} else {
 65			log.trace("KDefProcessor.parseFile({})", path);
 66			auto mod = fileParser.parseFile(path);
 67			_modules[path] = mod;
 68			mod.processing = true;
 69			mod.filePath = path;
 70			process(mod, modAlloc(mod));
 71			mod.processing = false;
 72		}
 73	}
 74	
 75	
 76	KDefModule getModuleForPath(string path) {
 77		if (auto mod = path in _modules) {
 78			return *mod;
 79		} else {
 80			return null;
 81		}
 82	}
 83	
 84	
 85	void doSemantics() {
 86		doKernelSemantics();
 87	}
 88	
 89	
 90	void dispose() {
 91		foreach (ref mod; _modules) {
 92			delete mod;
 93		}
 94		// TODO(?): do more thorough cleaning
 95		_modules = null;
 96	}
 97	
 98	
 99	void dumpInfo() {
100		Stdout.formatln("got {} modules:", _modules.keys.length);
101		foreach (name, mod; _modules) {
102			Stdout.formatln("mod {}:", name);
103			dumpInfo(mod);
104		}
105	}
106
107
108	struct KernelInfo {
109		KernelImpl*	impl;
110		KDefModule	mod;
111	}
112	
113	KernelInfo[string]	kernels;
114
115
116	int converters(int delegate(ref SemanticConverter) dg) {
117		foreach (name, mod; _modules) {
118			foreach (ref conv; mod.converters) {
119				if (auto r = dg(conv)) {
120					return r;
121				}
122			}
123		}
124		
125		return 0;
126	}
127
128	
129	KernelImpl getKernel(string name) {
130		if (auto impl = name in this.kernels) {
131			return *impl.impl;
132		} else {
133			error("Unknown kernel: '{}'.", name);
134			assert (false);
135		}
136	}
137
138
139	// BUG: this is slow
140	KernelImpl getKernel(KernelImplId id) {
141		assert (id.isValid);
142		
143		foreach (k, ref v; this.kernels) {
144			assert (v.impl.id.isValid);
145			if (v.impl.id == id) {
146				return *v.impl;
147			}
148		}
149
150		error("Unknown kernel id: '{}'.", id.value);
151		assert (false);
152	}
153
154
155	bool getKernel(string name, KernelImpl* res) {
156		if (auto impl = name in this.kernels) {
157			*res = *impl.impl;
158			return true;
159		} else {
160			return false;
161		}
162	}
163
164
165	int kernelImpls(int delegate(ref KernelImpl) dg) {
166		foreach (n, k; this.kernels) {
167			if (int r = dg(*k.impl)) {
168				return r;
169			}
170		}
171
172		return 0;
173	}
174
175
176	int surfaces(int delegate(ref string, ref SurfaceDef) dg) {
177		foreach (name, mod; _modules) {
178			foreach (name, ref surf; mod.surfaces) {
179				string meh = name;
180				if (auto r = dg(meh, surf)) {
181					return r;
182				}
183			}
184		}
185		
186		return 0;
187	}
188
189
190	int materials(int delegate(ref string, ref MaterialDef) dg) {
191		foreach (name, mod; _modules) {
192			foreach (name, ref surf; mod.materials) {
193				string meh = name;
194				if (auto r = dg(meh, surf)) {
195					return r;
196				}
197			}
198		}
199		
200		return 0;
201	}
202
203
204	int modules(int delegate(ref string, ref KDefModule) dg) {
205		foreach (name, mod; _modules) {
206			if (int r = dg(name, mod)) {
207				return r;
208			}
209		}
210		
211		return 0;
212	}
213
214
215	KDefInvalidationInfo invalidateDifferences(KDefProcessor other) {
216		KDefInvalidationInfo res;
217
218		foreach (modName, mod; other._modules) {
219			if (!(modName in this._modules)) {
220				if (mod.converters.length > 0) {
221					res.anyConverters = true;
222				}
223			}
224		}
225		
226		foreach (modName, mod; _modules) {
227			if (auto otherMod = modName in other._modules) {
228				foreach (name, ref o; mod.kernels) {
229					if (auto o2 = name in otherMod.kernels) {
230						if (o != *o2) {
231							o.invalidate();
232						}
233					} else {
234						o.invalidate();
235					}
236				}
237
238				foreach (name, ref o; mod.surfaces) {
239					if (auto o2 = name in otherMod.surfaces) {
240						if (o != *o2) {
241							o.invalidate();
242						}
243					} else {
244						o.invalidate();
245					}
246				}
247
248				foreach (name, ref o; mod.materials) {
249					if (auto o2 = name in otherMod.materials) {
250						if (o != *o2) {
251							o.invalidate();
252						}
253					} else {
254						o.invalidate();
255					}
256				}
257
258				if (!res.anyConverters) {
259					if (mod.converters.length != otherMod.converters.length) {
260						res.anyConverters = true;
261					} else {
262						foreach (i, ref c; mod.converters) {
263							if (c != otherMod.converters[i]) {
264								res.anyConverters = true;
265								break;
266							}
267						}
268					}
269				}
270			} else {
271				// If the module is missing from the other processor,
272				// invalidate all of the current module's items
273				
274				if (mod.converters.length > 0) {
275					res.anyConverters = true;
276				}
277
278				foreach (name, ref o; mod.kernels) {
279					o.invalidate();
280				}
281
282				foreach (name, ref o; mod.surfaces) {
283					o.invalidate();
284				}
285
286				foreach (name, ref o; mod.materials) {
287					o.invalidate();
288				}
289			}
290		}
291
292		Dep.invalidateGraph((void delegate(Dep.DepTracker*) depSink) {
293			void process(Dep.DepTracker* tr) {
294				if (!tr.valid) {
295					depSink(tr);
296				}
297			}
298			
299			foreach (modName, mod; _modules) {
300				foreach (name, ref o; mod.kernels) {
301					process(o.dependentOnThis);
302				}
303
304				foreach (name, ref o; mod.surfaces) {
305					process(o.dependentOnThis);
306				}
307
308				foreach (name, ref o; mod.materials) {
309					process(o.dependentOnThis);
310				}
311			}
312		});
313		
314		return res;
315	}
316
317	
318	private {
319		enum Processed {
320			Not,
321			InProgress,
322			Done
323		}
324
325
326		void doKernelSemantics() {
327			Processed[KernelImpl] processed;
328
329			foreach (name, mod; _modules) {
330				foreach (kname, ref kimpl; mod.kernels) {
331					if (kname in this.kernels) {
332						error(
333							"Multiple definitions of kernel '{}' in:\n  {}\n  and\n  {}.",
334							kname,
335							mod.filePath,
336							this.kernels[kname].mod.filePath
337						);
338					} else {
339						this.kernels[kname] = KernelInfo(
340							&kimpl,
341							mod
342						);
343					}
344
345					if (KernelImpl.Type.Kernel == kimpl.type) {
346						if (auto func = cast(Function)kimpl.kernel.func) {
347							static assert (is(typeof(mod) == KDefModule));
348							func.code._module = cast(void*)mod;
349						}
350						
351						kimpl.kernel._module = cast(void*)mod;
352					} else {
353						GraphDef(kimpl.graph)._module = cast(void*)mod;
354					}
355				}
356			}
357
358
359			foreach (name, mod; _modules) {
360				foreach (ref surf; mod.surfaces) {
361					getKernel(surf.reflKernelName)
362						.dependentOnThis.add(surf.dependentOnThis);
363				}
364
365				foreach (ref mat; mod.materials) {
366					getKernel(mat.materialKernelName)
367						.dependentOnThis.add(mat.dependentOnThis);
368				}
369			}
370			
371
372			foreach (n, ref k; kernels) {
373				_curSemModule = k.mod;
374				doKernelSemantics(*k.impl, modAlloc(k.mod), processed);
375			}
376		}
377
378		void inheritKernel(KernelDef sub, KernelImpl supr) {
379			iterKernelInputs(supr, (Param* p) {
380				if (!sub.func.params.get(p.name)) {
381					sub.func.params.add(*p);
382				}
383			});
384
385			iterKernelOutputs(supr, (Param* p) {
386				if (!sub.func.params.get(p.name)) {
387					sub.func.params.add(*p);
388				}
389			});
390		}
391
392		void getPlainSemanticForNode(Param* par, Semantic* plainSem, KernelImpl supr) {
393			findOutputSemantic(
394				par,
395
396				// getFormalParamSemantic
397				(string name) {
398					Semantic* res;
399					
400					iterKernelInputs(supr, (Param* p) {
401						if (p.isInput && p.name == name) {
402							res = p.semantic();
403						}
404					});
405					
406					if (res) {
407						return *res;
408					}
409					
410					error(
411						"simplifyParamSemantics: output param '{}' refers to a"
412						" nonexistent formal parameter '{}'.",
413						par.name,
414						name
415					);
416					assert (false);
417				},
418
419				// getActualParamSemantic
420				(string name) {
421					error(
422						"Cannot derive node params from {}: param {} has a semantic expression.",
423						supr.name,
424						par.name
425					);
426					return Semantic.init;
427				},
428				
429				plainSem
430			);
431		}
432
433		void inheritKernelInputs(GraphDefNode node, KernelImpl supr) {
434			iterKernelInputs(supr, (Param* p) {
435				if (!node.params.get(p.name)) {
436					assert (p.hasPlainSemantic);
437					node.params.add(*p).dir = ParamDirection.Out;
438				}
439			});
440		}
441
442		void inheritKernelOutputs(GraphDefNode node, KernelImpl supr) {
443			iterKernelOutputs(supr, (Param* p) {
444				if (!node.params.get(p.name)) {
445					if (!p.hasPlainSemantic) {
446						auto pnew = node.params.add(ParamDirection.In, p.name);
447						pnew.hasPlainSemantic = true;
448						getPlainSemanticForNode(p, pnew.semantic, supr);
449						pnew.copyValueFrom(p);
450						pnew.annotation = p.annotation;
451					} else {
452						node.params.add(*p).dir = ParamDirection.In;
453					}
454				}
455			});
456		}
457		
458
459		void iterKernelParams(
460				KernelImpl impl,
461				bool wantInputs,
462				void delegate(Param*) sink
463		) {
464			switch (impl.type) {
465				case KernelImpl.Type.Kernel: {
466					foreach (ref p; impl.kernel.func.params) {
467						if (wantInputs == p.isInput) {
468							sink(&p);
469						}
470					}
471				} break;
472
473				case KernelImpl.Type.Graph: {
474					foreach (nodeName, node; GraphDef(impl.graph).nodes) {
475						if ((wantInputs ? "input" : "output") == node.type) {
476							foreach (ref p; node.params) {
477								sink(&p);
478							}
479						}
480					}
481				} break;
482
483				default: assert (false);
484			}
485		}
486
487		void iterKernelInputs(KernelImpl impl, void delegate(Param*) sink) {
488			iterKernelParams(impl, true, sink);
489		}
490
491		void iterKernelOutputs(KernelImpl impl, void delegate(Param*) sink) {
492			iterKernelParams(impl, false, sink);
493		}
494		
495
496		void doKernelSemantics(ref KernelDef k, Allocator allocator, ref Processed[KernelImpl] processed) {
497			if (k.superKernel.length > 0) {
498				auto superKernel = getKernel(k.superKernel);
499				doKernelSemantics(superKernel, allocator, processed);
500				inheritKernel(k, superKernel);
501
502				superKernel.dependentOnThis.add(
503					k.dependentOnThis
504				);
505			}
506		}
507
508
509		void doKernelSemantics(GraphDef graph, Allocator allocator, ref Processed[KernelImpl] processed) {
510			KernelImpl superKernel;
511			
512			if (graph.superKernel.length > 0) {
513				superKernel = getKernel(graph.superKernel);
514				doKernelSemantics(superKernel, allocator, processed);
515
516				superKernel.dependentOnThis.add(
517					graph.dependentOnThis
518				);
519			}
520
521			foreach (nodeName, node; graph.nodes) {
522				switch (node.type) {
523					case "input": {
524						if (!superKernel.isNull) {
525							inheritKernelInputs(node, superKernel);
526						}
527					} break;
528
529					case "output": {
530						if (!superKernel.isNull) {
531							inheritKernelOutputs(node, superKernel);
532						}
533					} break;
534
535					case "kernel": {
536						auto kernelVar = node.getVar("kernel");
537						if (kernelVar is null) {
538							// TODO: err
539							error("No kernel defined for a kernel node.");
540						}
541						if (auto ident = cast(IdentifierValue)kernelVar) {
542							node.kernelImpl = getKernel(ident.value);
543						}
544						else if (auto literal = cast(KernelDefValue)kernelVar) {
545							if (!cast(Function)literal.kernelDef.func) {
546								// TODO: err
547								error(
548									"Graph nodes must use concrete kernel literals."
549								);
550							}
551							
552							doKernelSemantics(literal.kernelDef, allocator, processed);
553							node.kernelImpl = KernelImpl(literal.kernelDef);
554							node.kernelImpl.kernel.func.name = "literal";
555							node.kernelImpl.kernel._module = cast(void*)_curSemModule;
556						}
557						else {
558							error(
559								"The 'kernel' var in a graph node must be"
560								" either an identifier or a concrete kernel literal,"
561								" not a '{}'", kernelVar.classinfo.name
562							);
563						}
564
565						node.kernelImpl.dependentOnThis.add(
566							graph.dependentOnThis
567						);
568					} break;
569
570					default: break;
571				}
572			}
573		}
574
575		void doKernelSemantics(ref KernelImpl k, Allocator allocator, ref Processed[KernelImpl] processed) {
576			if (auto p = k in processed) {
577				switch (*p) {
578					case Processed.InProgress: {
579						char[] list;
580						foreach (ki, p2; processed) {
581							if (Processed.InProgress == p2) {
582								list ~= "  '"~ki.name~"'\n";
583							}
584						}
585
586						// TODO: keep track of the exact eval order
587						error(
588							"Recursive prosessing of a kernel '{}'. From:\n{}",
589							k.name,
590							list
591						);
592					} break;
593					
594					case Processed.Not: break;
595					case Processed.Done: return;
596					
597					default: assert (false);
598				}
599			}
600			
601			processed[k] = Processed.InProgress;
602			scope (success) processed[k] = Processed.Done;
603
604			switch (k.type) {
605				case KernelImpl.Type.Kernel: {
606					doKernelSemantics(k.kernel, allocator, processed);
607				} break;
608
609				case KernelImpl.Type.Graph: {
610					doKernelSemantics(GraphDef(k.graph), allocator, processed);
611				} break;
612
613				default: assert (false);
614			}
615		}
616		
617		// --------------------------------------------------------------------------------------------------------------------------------
618		//
619
620		struct SimpleArray(T) {
621			private {
622				T[]		_arr;
623				size_t	_len;
624			}
625			
626			
627			size_t length() {
628				return _len;
629			}
630			
631			T[] data() {
632				return _arr[0.._len];
633			}
634			
635			void add(T t) {
636				_arr.append(t, &_len);
637			}
638			
639			void dispose() {
640				_arr.free();
641			}
642		}
643		
644		
645		void dispose2dArray(T)(ref SimpleArray!(T)[] arr) {
646			foreach (ref item; arr) {
647				item.dispose();
648			}
649			arr.free();
650		}
651		
652		
653		//
654		// --------------------------------------------------------------------------------------------------------------------------------
655		
656		void dumpInfo(KDefModule mod) {
657			Stdout.formatln("* path: {}", mod.filePath);
658			Stdout.formatln("* kernel impls:");
659			
660			foreach (n, impl; mod.kernels) {
661				dumpInfo(impl);
662			}
663		}
664		
665		
666		void dumpInfo(KernelImpl kimpl) {
667			switch (kimpl.type) {
668				case KernelImpl.Type.Graph:
669					return dumpInfo(GraphDef(kimpl.graph));
670				case KernelImpl.Type.Kernel:
671					return dumpInfo(kimpl.kernel);
672				default: assert (false);
673			}
674		}
675		
676		
677		void dumpInfo(AbstractFunction func) {
678			Stdout.formatln("\tfunc: {} {{", func.name);
679			foreach (param; func.params) {
680				Stdout.format("\t\t{}", param);
681				/+if (param.defaultValue) {
682					Stdout.formatln(" = {}", param.defaultValue);
683				}+/
684				Stdout.newline;
685			}
686			if (auto qf = cast(Function)func) {
687				//Stdout.formatln("{} code:", qf.code.language);
688				Stdout("----").newline;
689				char[] code;
690				qf.code.writeOut((char[] s) {
691					code ~= s;
692				});
693				Stdout(code).newline;
694				Stdout("----").newline;
695			}
696			Stdout("}").newline;
697		}
698		
699		
700		void dumpInfo(GraphDef graph) {
701			Stdout("graph {").newline;
702			Stdout.formatln("file:  {}", (cast(KDefModule)graph._module).filePath);
703			Stdout.formatln("bytes: {}..{}", graph._firstByte, graph._firstByte + graph._lengthBytes);
704			foreach (nodeName, _node; graph.nodes) {
705				Stdout.formatln("\tnode: {}", nodeName);
706			}
707			/+foreach (graphName, subGraph; graph.graphs) {
708				Stdout.formatln("\tsub-graph: ");
709				dumpInfo(subGraph);
710			}+/
711			Stdout("}").newline;
712		}
713		
714		
715		void dumpInfo(KernelDef kernel) {
716			dumpInfo(kernel.func);
717		}
718		
719				
720		void process(Scope sc, Allocator allocator) {
721			gatherArrays!(string, Value)(sc.mem,
722			(void delegate(lazy string, lazy Value) gen) {
723				foreach (stmt_; sc.statements) {
724					if (auto stmt = cast(AssignStatement)stmt_) {
725						gen(stmt.name, stmt.value);
726					}
727				}
728			},
729			(string[] names, Value[] values) {
730				sc.doAssign(names, values);
731			});
732
733			gatherArrays!(string, string)(sc.mem,
734			(void delegate(lazy string, lazy string) gen) {
735				foreach (stmt_; sc.statements) {
736					if (auto stmt = cast(ConnectStatement)stmt_) {
737						if (auto graph = cast(GraphDef)sc) {
738							gen(stmt.from, stmt.to);
739						} else {
740							throw new Exception("connections only allowed at graph scope");
741						}
742					}
743				}
744			},
745			(string[] from, string[] to) {
746				(cast(GraphDef)sc).doConnect(from, to);
747			});
748
749			gatherArrays!(string)(sc.mem,
750			(void delegate(lazy string) gen) {
751				foreach (stmt_; sc.statements) {
752					if (auto stmt = cast(NoAutoFlowStatement)stmt_) {
753						if (auto graph = cast(GraphDef)sc) {
754							gen(stmt.to);
755						} else {
756							error("Can't use noauto outside of graph definitions.");
757						}
758					}
759				}
760			},
761			(string[] to) {
762				(cast(GraphDef)sc).setNoAuto(to);
763			});
764			
765			
766
767			foreach (stmt_; sc.statements) {
768				if (auto stmt = cast(ConnectStatement)stmt_) {
769					// nothing
770				} else if (auto stmt = cast(NoAutoFlowStatement)stmt_) {
771					// nothing
772				} else if (auto stmt = cast(AssignStatement)stmt_) {
773					if (auto scopeValue = cast(IScopeValue)stmt.value) {
774						process(scopeValue.toScope, allocator);
775					}
776					
777					if (auto kernelValue = cast(KernelDefValue)stmt.value) {
778						kernelValue.kernelDef.func.name = stmt.name;
779						if (auto mod = cast(KDefModule)sc) {
780							mod.kernels[stmt.name] = KernelImpl(kernelValue.kernelDef);
781						}
782					}
783					
784					if (auto graphValue = cast(GraphDefValue)stmt.value) {
785						GraphDef(graphValue.graphDef)._name = stmt.name;
786						if (auto mod = cast(KDefModule)sc) {
787							mod.kernels[stmt.name] = KernelImpl(graphValue.graphDef);
788						}
789					}
790					
791					if (auto surfValue = cast(SurfaceDefValue)stmt.value) {
792						surfValue.surface.name = stmt.name;
793						if (auto mod = cast(KDefModule)sc) {
794							mod.surfaces[stmt.name] = surfValue.surface;
795						}
796					}
797
798					if (auto matValue = cast(MaterialDefValue)stmt.value) {
799						matValue.material.name = stmt.name;
800						if (auto mod = cast(KDefModule)sc) {
801							mod.materials[stmt.name] = matValue.material;
802						}
803					}
804
805					if (auto nodeValue = cast(GraphDefNodeValue)stmt.value) {
806						auto node = nodeValue.node;
807
808						switch (node.type) {
809							case "input": 
810							case "data":
811							case "output": {
812								node.params = ParamList(allocator._allocator);
813							}
814							default: break;
815						}
816
817						buildConcreteParams(node, &node.params);
818					}
819
820					if (auto traitValue = cast(TraitDefValue)stmt.value) {
821						traitValue.value.name = stmt.name;
822						if (auto mod = cast(KDefModule)sc) {
823							mod.traitDefs ~= traitValue.value;
824						}
825					}
826				} else if (auto stmt = cast(ImportStatement)stmt_) {
827					auto path = stmt.path;
828					processFile(path);
829					auto names = stmt.what;
830					auto mod = _modules[path];
831					
832					if (names !is null) {
833						assert (false, "TODO: selective imports");
834					} else {
835						sc.doImport((void delegate(Statement) dg) {
836							foreach (st; mod.statements) {
837								dg(st);
838							}
839						});
840					}
841				} else if (auto stmt = cast(ConverterDeclStatement)stmt_) {
842					if (auto mod = cast(KDefModule)sc) {
843						assert (2 == stmt.func.params.length);		// there's also hidden context
844						
845						auto from = stmt.func.params[0];
846						auto to = stmt.func.params[1];
847						
848						/+if ("Cg" == stmt.func.code.language) {
849							if (!from.semantic.hasTrait("domain")) {
850								from.semantic.addTrait("domain", "gpu");
851							}
852
853							if (!to.semantic.hasTrait("domain")) {
854								to.semantic.addTrait("domain", "gpu");
855							}
856						}+/
857						
858						string name = stmt.func.name;
859						if (name is null) {
860							// Will get renamed for overloads by codegen
861							name = "converter";
862						}
863						
864						mod.converters ~= SemanticConverter(stmt.func, stmt.cost);
865					} else {
866						throw new Exception("only can has converters at module scope ktnx");
867					}
868				} else {
869					throw new Exception("Unhandled statement: " ~ stmt_.toString);
870				}
871			}
872		}
873
874
875		IKDefFileParser		fileParser;
876		
877		// indexed by path
878		KDefModule[string]	_modules;
879
880		KDefModule			_curSemModule;
881	}
882}