/// <summary>
    /// 增加 脚本和 using 引用到构建器中
    /// </summary>
    /// <param name="script">代码脚本</param>
    /// <param name="usings">using 引用</param>
    /// <returns></returns>
    public NatashaException Add(string script, HashSet <string> usings = default)
    {
#if DEBUG
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
#endif
        var tree = Syntax.ConvertToTree(script);
#if DEBUG
        Console.WriteLine();
        stopwatch.StopAndShowCategoreInfo("[SyntaxTree]", "语法树转换耗时", 2);
        stopwatch.Restart();
#endif
        var exception = NatashaExceptionAnalyzer.GetSyntaxException(tree);
#if DEBUG
        stopwatch.StopAndShowCategoreInfo("[SyntaxTree]", "语法树判错耗时", 2);
        stopwatch.Restart();
#endif
        if (!exception.HasError || SyntaxErrorBehavior == ExceptionBehavior.Ignore)
        {
            Syntax.AddTreeToCache(tree);
            Syntax.ReferenceCache[exception.Formatter] = usings;
        }
        else
        {
            HandlerErrors(exception);
        }
#if DEBUG
        stopwatch.StopAndShowCategoreInfo("[SyntaxTree]", "语法树错误处理耗时", 2);
#endif
        return(exception);
    }
 /// <summary>
 /// 拿到异常之后进行后处理,如果处理后可以重编译,将再次编译
 /// </summary>
 /// <param name="errors"></param>
 /// <returns></returns>
 private bool CanRetryCompile(ImmutableArray <Diagnostic> errors)
 {
     if (CanRetry)
     {
         _retryCount += 1;
         if (_retryCount < RetryLimit)
         {
             return(true);
         }
     }
     Exceptions = NatashaExceptionAnalyzer.GetCompileException(Compiler.AssemblyName, errors);
     return(false);
 }
    /// <summary>
    /// 增加 脚本和 using 引用到构建器中
    /// </summary>
    /// <param name="script">代码脚本</param>
    /// <param name="usings">using 引用</param>
    /// <returns></returns>
    public NatashaException Add(string script, HashSet <string> usings = default)
    {
        var tree      = Syntax.ConvertToTree(script);
        var exception = NatashaExceptionAnalyzer.GetSyntaxException(tree);

        if (!exception.HasError || SyntaxErrorBehavior == ExceptionBehavior.Ignore)
        {
            Syntax.AddTreeToCache(tree);
            Syntax.ReferenceCache[exception.Formatter] = usings;
        }
        else
        {
            HandlerErrors(exception);
        }
        return(exception);
    }
Exemple #4
0
    /// <summary>
    /// 添加语法树
    /// </summary>
    /// <param name="tree"></param>
    public AssemblyCSharpBuilder Add(SyntaxTree tree)
    {
        tree = NatashaCSharpSyntax.FormartTree(tree, _options);
        var exception = NatashaExceptionAnalyzer.GetSyntaxException(tree);

        if (exception != null)
        {
            throw exception;
        }
        else
        {
            lock (SyntaxTrees)
            {
                SyntaxTrees.Add(tree);
            }
        }
        return(this);
    }
Exemple #5
0
    /// <summary>
    /// 添加脚本
    /// </summary>
    /// <param name="script"></param>
    public AssemblyCSharpBuilder Add(string script)
    {
        var tree      = NatashaCSharpSyntax.ParseTree(script, _options);
        var exception = NatashaExceptionAnalyzer.GetSyntaxException(tree);

        if (exception != null)
        {
            throw exception;
        }
        else
        {
            lock (SyntaxTrees)
            {
                SyntaxTrees.Add(tree);
            }
        }
        return(this);
    }
Exemple #6
0
    /// <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 !);
    }