private static (ImmutableArray <Diagnostic>, string) GetGeneratedOutput(string source) { var syntaxTree = CSharpSyntaxTree.ParseText(source); var references = new List <MetadataReference>(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { if (!assembly.IsDynamic) { references.Add(MetadataReference.CreateFromFile(assembly.Location)); } } var compilation = CSharpCompilation.Create("foo", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); // TODO: Uncomment these lines if you want to return immediately if the injected program isn't valid _before_ running generators // // ImmutableArray<Diagnostic> compilationDiagnostics = compilation.GetDiagnostics(); // // if (diagnostics.Any()) // { // return (diagnostics, ""); // } var generator = new Generator(); var driver = CSharpGeneratorDriver.Create(generator); driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generateDiagnostics); return(generateDiagnostics, outputCompilation.SyntaxTrees.Last().ToString()); }
private static (ImmutableArray <Diagnostic>, string) GetGeneratedOutput(string source) { var syntaxTree = CSharpSyntaxTree.ParseText(source); var references = new List <MetadataReference>(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { if (!assembly.IsDynamic) { references.Add(MetadataReference.CreateFromFile(assembly.Location)); } } var compilation = CSharpCompilation.Create("foo", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); ImmutableArray <Diagnostic> diagnostics = compilation.GetDiagnostics(); if (diagnostics.Any()) { return(diagnostics, ""); } ISourceGenerator generator = new Generator(); var driver = CSharpGeneratorDriver.Create(generator); driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out diagnostics); return(diagnostics, outputCompilation.SyntaxTrees.Last().ToString()); }
public EvaluationResult Evaluate(Dictionary <VariableSymbol, object> variables) { var parseDiagnostics = SyntaxTrees.SelectMany(st => st.Diagnostics); var diagnostics = parseDiagnostics.Concat(GlobalScope.Diagnostics).ToImmutableArray(); if (diagnostics.Any()) { return(new EvaluationResult(diagnostics, null)); } var program = GetProgram(); // var appPath = Environment.GetCommandLineArgs()[0]; // var appDirectory = Path.GetDirectoryName(appPath); // var cfgPath = Path.Combine(appDirectory, "cfg.dot"); // var cfgStatement = !program.Statement.Statements.Any() && program.Functions.Any() // ? program.Functions.Last().Value // : program.Statement; // var cfg = ControlFlowGraph.Create(cfgStatement); // using (var streamWriter = new StreamWriter(cfgPath)) // cfg.WriteTo(streamWriter); if (program.Diagnostics.Any()) { return(new EvaluationResult(program.Diagnostics.ToImmutableArray(), null)); } var evaluator = new Evaluator(program, variables); var value = evaluator.Evaluate(); return(new EvaluationResult(ImmutableArray <Diagnostic> .Empty, value)); }
// TODO: References should be part of the compilation, not arguments for Emit public ImmutableArray <Diagnostic> Emit(string moduleName, string[] references, string outputPath) { var parseDiagnostics = SyntaxTrees.SelectMany(st => st.Diagnostics); var diagnostics = parseDiagnostics.Concat(GlobalScope.Diagnostics).ToImmutableArray(); if (diagnostics.HasErrors()) { return(diagnostics); } var program = GetProgram(); return(Emitter.Emit(program, moduleName, references, outputPath)); }
// TODO: References should be part of the compilation, not arguments for Emit public ImmutableArray <Diagnostic> Emit(string moduleName, string[] references, string outputPath) { var parseDiagnostics = SyntaxTrees.SelectMany(st => st.Diagnostics); var diagnostics = parseDiagnostics.Concat(GlobalScope.Diagnostics).ToImmutableArray(); if (diagnostics.HasErrors()) { return(diagnostics); } // TODO: implement warning system if (diagnostics.HasWarnings()) { Console.Out.WriteLine(diagnostics); } var program = GetProgram(); return(ILEmitter.Emit(program, moduleName, references, outputPath)); }
public EvaluationResult Evaluate(Dictionary <VariableSymbol, object> variables) { var parseDiagnostics = SyntaxTrees.SelectMany(st => st.Diagnostics); var diagnostics = parseDiagnostics.Concat(GlobalScope.Diagnostics).ToImmutableArray(); if (diagnostics.Any()) { return(new EvaluationResult(diagnostics, null)); } var program = GetProgram(); if (program.Diagnostics.Any()) { return(new EvaluationResult(program.Diagnostics.ToImmutableArray(), null)); } var evaluator = new Evaluator(program, variables); var value = evaluator.Evaluate(); return(new EvaluationResult(ImmutableArray <Diagnostic> .Empty, value)); }
public override void Init(LoggerProvider p, bool reInit = false) { if (this.Initialized && !reInit) { return; } this.Logger = p; this.Types = new List <NamedTypeBase>(); this.symbols = new List <ISymbol>(); this.SemanticModels = new Dictionary <ISymbol, SemanticModel>(); this.TreeModels = new Dictionary <SyntaxTree, SemanticModel>(); this.SyntaxTrees = new Dictionary <ISymbol, SyntaxTree>(); List <Tuple <ISymbol, SemanticModel> > tempSymbols = new List <Tuple <ISymbol, SemanticModel> >(); using (ProfilerService.Current.Section("Getting symbols")) { for (int i = 0; i < Compilations.Count; i++) { var comp = Compilations[i]; var compTrees = comp.SyntaxTrees.ToList(); for (int j = 0; j < compTrees.Count; j++) { tempSymbols.AddRange(GetSymbols(compTrees[j], comp)); } } } using (ProfilerService.Current.Section("Building symbol info")) { this.symbols = tempSymbols.Select(t => t.Item1).ToList(); for (int i = 0; i < tempSymbols.Count; i++) { if (tempSymbols[i].Item1.Locations.Length > 0 && tempSymbols[i].Item1.Locations[0].IsInSource) { var sTree = tempSymbols[i].Item1.Locations[0].SourceTree; if (!this.SemanticModels.ContainsKey(tempSymbols[i].Item1)) { SyntaxTrees.Add(tempSymbols[i].Item1, sTree); } var sComp = Compilations.SingleOrDefault(c => c.SyntaxTrees.Contains(sTree)); if (sComp == null) { Logger.WriteToLog(string.Format("Cannot find compilation for tree {0}", sTree.FilePath)); } else { if (!this.SemanticModels.ContainsKey(tempSymbols[i].Item1)) { this.SemanticModels.Add(tempSymbols[i].Item1, sComp.GetSemanticModel(sTree)); } if (!this.TreeModels.ContainsKey(sTree)) { this.TreeModels.Add(sTree, sComp.GetSemanticModel(sTree)); } } } else { if (!this.SemanticModels.ContainsKey(tempSymbols[i].Item1)) { this.SemanticModels.Add(tempSymbols[i].Item1, tempSymbols[i].Item2); } } } } CSharpModelBuilder.InitLogger(p); using (ProfilerService.Current.Method("BuildTypeList")) { CSharpModelBuilder.BuildTypeList(Types, symbols.Where(s => s.Kind == SymbolKind.NamedType).Distinct().Cast <INamedTypeSymbol>()); } this.Types = this.Types.Distinct(new TypeComparer()).ToList(); using (ProfilerService.Current.Method("BuildArrayTypeList")) { CSharpModelBuilder.BuildArrayTypeList(Types, symbols.Where(s => s.Kind == SymbolKind.ArrayType).Distinct().Cast <IArrayTypeSymbol>()); } using (ProfilerService.Current.Method("BuildMethodList")) { CSharpModelBuilder.BuildMethodList(Types, symbols.Where(s => s.Kind == SymbolKind.Method).Distinct().Cast <IMethodSymbol>() .Where(s => s.MethodKind == MethodKind.Ordinary || s.MethodKind == MethodKind.Constructor || s.MethodKind == MethodKind.PropertyGet || s.MethodKind == MethodKind.PropertySet), this.SemanticModels); } using (ProfilerService.Current.Method("BuildFieldList")) { CSharpModelBuilder.BuildFieldList(Types, symbols.Where(s => s.Kind == SymbolKind.Field).Distinct().Cast <IFieldSymbol>(), symbols.Where(s => s.Kind == SymbolKind.Property).Cast <IPropertySymbol>(), this.SemanticModels); } using (ProfilerService.Current.Method("BuildCallGraph")) { this.CallGraph = CSharpModelBuilder.BuildCallGraph(this.TreeModels, this.Types, this.Logger); } this.Initialized = true; using (var fs = File.Create(string.Join(".", this.Name, "bin"))) { BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(fs, this.Types); } }
/// <summary> /// 将 SyntaxTrees 中的语法树编译到程序集.如果不成功会抛出 NatashaException. /// </summary> /// <remarks> /// <example> /// <code> /// /// //程序集的域加载行为, 该行为决定了编译后的程序集随着依赖加载到域中的处理结果. /// //和加载插件原理相同. /// builder.CompileWithAssemblyLoadBehavior(enum); /// /// //编译单元的引用加载行为, 遇到同名不同版本的引用该如何处理. /// builder.CompileWithReferenceLoadBehavior(enum); /// builder.CompileWithReferencesFilter(func); /// /// </code> /// </example> /// </remarks> public Assembly GetAssembly() { #if DEBUG Stopwatch stopwatch = new(); stopwatch.Start(); #endif //Mark : 26ms if (_compileReferenceBehavior == LoadBehaviorEnum.None) { _compilerOptions.SetSupersedeLowerVersions(true); } var options = _compilerOptions.GetCompilationOptions(); var references = Domain.GetReferences(_compileReferenceBehavior, _referencePickFunc); var compilation = CSharpCompilation.Create(AssemblyName, SyntaxTrees, references, options); #if DEBUG stopwatch.RestartAndShowCategoreInfo("[Compiler]", "获取编译单元", 2); #endif if (EnableSemanticHandler) { foreach (var item in _semanticAnalysistor) { compilation = item(this, compilation); } lock (SyntaxTrees) { SyntaxTrees.Clear(); SyntaxTrees.AddRange(compilation.SyntaxTrees); } } #if DEBUG stopwatch.RestartAndShowCategoreInfo("[Semantic]", "语义处理", 2); #endif Stream dllStream; Stream pdbStream; Stream?xmlStream = null; if (DllFilePath != string.Empty) { dllStream = File.Create(DllFilePath); } else { dllStream = new MemoryStream(); } if (PdbFilePath != string.Empty) { pdbStream = File.Create(PdbFilePath); } else { pdbStream = new MemoryStream(); } if (XmlFilePath != string.Empty) { xmlStream = File.Create(XmlFilePath); } var compileResult = compilation.Emit( dllStream, pdbStream: pdbStream, xmlDocumentationStream: xmlStream, options: new EmitOptions(pdbFilePath: PdbFilePath == string.Empty ? null : PdbFilePath, debugInformationFormat: DebugInformationFormat.PortablePdb)); LogCompilationEvent?.Invoke(compilation.GetNatashaLog()); Assembly?assembly = null; if (compileResult.Success) { dllStream.Seek(0, SeekOrigin.Begin); pdbStream?.Seek(0, SeekOrigin.Begin); Domain.SetAssemblyLoadBehavior(_compileAssemblyBehavior); assembly = Domain.LoadAssemblyFromStream(dllStream, pdbStream); CompileSucceedEvent?.Invoke(compilation, assembly !); } dllStream.Dispose(); pdbStream?.Dispose(); xmlStream?.Dispose(); #if DEBUG stopwatch.StopAndShowCategoreInfo("[ Emit ]", "编译时长", 2); #endif if (!compileResult.Success) { CompileFailedEvent?.Invoke(compilation, compileResult.Diagnostics); throw NatashaExceptionAnalyzer.GetCompileException(compilation, compileResult.Diagnostics); } return(assembly !); }