<commit_before>// Copyright (c) 2020 <NAME>
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT

namespace Farkle.Builder

open Farkle
open Farkle.Builder
open Farkle.Grammar
open System
open System.ComponentModel
open System.Reflection
open System.Runtime.CompilerServices
open System.Threading

/// This exception gets thrown when Farkle fails to load a precompiled grammar.
/// Such exceptions indicate bugs and should they ever occur, opening an issue
/// on GitHub would be very helpful.
type PrecompilerLoaderException(msg, innerExn) = inherit FarkleException(msg, innerExn)

/// An object that represents a precompiled grammar inside an assembly.
type PrecompiledGrammar private(asm, grammarName, resourceName) =
    static let precompiledGrammarResourceSuffix = ".precompiled.egtn"
    static let assemblyCache = ConditionalWeakTable()
    static let getAllPrecompiledGrammars = ConditionalWeakTable.CreateValueCallback<Assembly,_>(fun asm ->
        asm.GetManifestResourceNames()
        |> Seq.filter (fun name -> name.EndsWith(precompiledGrammarResourceSuffix, StringComparison.Ordinal))
        |> Seq.map (fun name ->
            let grammarName = name.Substring(0, name.Length - precompiledGrammarResourceSuffix.Length)
            grammarName, PrecompiledGrammar(asm, grammarName, name))
        |> readOnlyDict
    )

    static let newPrecompilerLoaderException innerExn =
        PrecompilerLoaderException("Failed to load a precompiled grammar. Try rebuilding \
the assembly with the latest version of Farkle and Farkle.Tools.MSBuild. If the problem persists, \
please open an issue on GitHub", innerExn)

    let grammarThunk = lazy(
        // The stream will definitely be not null.
        use stream = asm.GetManifestResourceStream resourceName
        try
            EGT.ofStreamEx GrammarSource.Precompiled stream
        with<commit_msg>Accept precompiled grammars only in embedded resources on the same assembly.<commit_after>// Copyright (c) 2020 <NAME>
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT

namespace Farkle.Builder

open Farkle
open Farkle.Builder
open Farkle.Grammar
open System
open System.ComponentModel
open System.Reflection
open System.Runtime.CompilerServices
open System.Threading

/// This exception gets thrown when Farkle fails to load a precompiled grammar.
/// Such exceptions indicate bugs and should they ever occur, opening an issue
/// on GitHub would be very helpful.
type PrecompilerLoaderException(msg, innerExn) = inherit FarkleException(msg, innerExn)

/// An object that represents a precompiled grammar inside an assembly.
type PrecompiledGrammar private(asm, grammarName, resourceName) =
    static let precompiledGrammarResourceSuffix = ".precompiled.egtn"
    static let assemblyCache = ConditionalWeakTable()
    static let isValidResourceLocation x =
        // We want to accept only embedded resources. These get Embedded | ContainedInManifestFile always
        // (checked in both MetadataLoadContext and the CoreCLR). But let's be more flexible with the flags.
        // We want the resource to be embedded, and don't want it to be in another assembly.
        x &&& (ResourceLocation.ContainedInAnotherAssembly ||| ResourceLocation.Embedded) = ResourceLocation.Embedded
    static let getAllPrecompiledGrammars = ConditionalWeakTable.CreateValueCallback<Assembly,_>(fun asm ->
        asm.GetManifestResourceNames()
        |> Seq.filter (fun name ->
            name.EndsWith(precompiledGrammarResourceSuffix, StringComparison.Ordinal)
            && (
                let mri = asm.GetManifestResourceInfo(name)
                not (isNull mri) && isValidResourceLocation mri.ResourceLocation))
        |> Seq.map (fun name ->
            let grammarName = name.Substring(0, name.Length - precompiledGrammarResourceSuffix.Length)
            grammarName, PrecompiledGrammar(asm, grammarName, name))
        |> readOnlyDict
    )

    static let newPrecompilerLoaderException innerExn =
        PrecompilerLoaderException("Failed to load a precompiled grammar. Try rebuilding \
the assembly with the latest version of Farkle and Farkle.Tools.MSBuild. If the problem persists, \
please open an issue on GitHub", innerExn)

    let grammarThunk = lazy(
        // The stream will definitely be not null.
        use stream = asm.GetManifestResourceStream resourceName
        try
            EGT.ofStreamEx GrammarSource.Precompiled stream
        with
{'fraction_non_alphanumeric': 0.06882053551670723, 'fraction_numerical': 0.002212878955521133, 'mean_word_length': 3.6122448979591835, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 19, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2878432', 'n_tokens_mistral': 1230, 'n_tokens_neox': 1163, 'n_words': 402}