ProgramNode ParseModule(ModulePath?path, SourceText source, SyntaxContext context) { var msg = path != null ? $" with path '{path}'" : string.Empty; if (!_loading.Add(source.FullPath)) { throw new ModuleLoadException($"Module{msg} could not be loaded due to circular 'use' declarations."); } try { if (context.Parses.ContainsKey(source.FullPath)) { throw new ModuleLoadException($"Module{msg} was already loaded previously."); } var lex = LanguageLexer.Lex(source); var parse = LanguageParser.Parse(lex, SyntaxMode.Normal); context.AddParse(source.FullPath, parse); foreach (var diag in lex.Diagnostics) { context.AddDiagnostic(diag); } foreach (var diag in parse.Diagnostics) { context.AddDiagnostic(diag); } var analysis = LanguageAnalyzer.Analyze(parse, this, context); foreach (var diag in analysis.Diagnostics) { context.AddDiagnostic(diag); } return(analysis.IsSuccess ? (ProgramNode)parse.Tree : throw new ModuleLoadException( $"Module{msg} failed to load due to syntax and/or semantic errors.")); } finally { _ = _loading.Remove(source.FullPath); } }