anchor.diff:  namespace Farkle.Tools
   
   open Farkle.Grammar
  +open Farkle.Monads.Either
   open System
   open System.IO
   open Serilog
  
positive.code: 
                      Log.Information("You can explicitly choose the precompiled grammar you \
      want by appending {CompositePathSuffixHint} to the input file.", "'::<grammar-name>'")
                      Error()
              | Some grammarName ->
                  match loader.Grammars.TryGetValue(grammarName) with
                  | true, grammar -> grammar.GetGrammar() |> Ok
                  | false, _ ->
                      Log.Error("The assembly of {Path} doesn't have a precompiled grammar named {GrammarName}.", grammarName)
  
                      Log.Information("Hint: Run {CommandHint} to list all precompiled grammars of a project's assembly.", "farkle list")
                      Error()
          elif isGrammarExtension ext then
              EGT.ofFile filePath |> Ok
          else
              Log.Error("Unsupported file name: {FilePath}", filePath)
              Error()
  
      let private findDefaultProject currentDir =
          Directory.EnumerateFiles(currentDir, "*.??proj", SearchOption.TopDirectoryOnly)
  
negative.code: /// omitted if the file has only one precompiled grammar. The file in the first path can
  /// be either an assembly or a project file. If it is ommitted, a suitable project file
  /// will be searched in the current directory.
  type CompositePath = CompositePath of filePath: string option * grammarName: string option
  with
      static member Separator = "::"
  
  module CompositePath =
  
      let private defaultCompositePath = CompositePath(None, None)
  
      let private checkForWhitespace (x: string) =
          if String.IsNullOrWhiteSpace(x) then
              None
          else
              Some x
  
      let create path =
          let sep = CompositePath.Separator
          match path with
          | None -> defaultCompositePath
          | Some path when
              String.IsNullOrWhiteSpace(path)
              || path.AsSpan().Trim().Equals(sep.AsSpan(), StringComparison.Ordinal) -> defaultCompositePath
          | Some path ->
              match path.IndexOf(sep) with
              | -1 -> CompositePath(Some path, None)
              | doubleColonPos ->
                  let filePath =
                      path.Substring(0, doubleColonPos)
                      |> checkForWhitespace
                  let grammarName =
                      path.Substring(doubleColonPos + sep.Length)
                      |> Some
                  CompositePath(filePath, grammarName)
  
      let private resolveGrammar grammarName (filePath: string) = either {
          let! _ = assertFileExists filePath
          let ext = Path.GetExtension(filePath.AsSpan())
          if isProjectExtension ext then
              Log.Error("Opening projects is not currently supported")
              return! Error()
          elif isAssemblyExtension ext then
              use loader = new PrecompiledAssemblyFileLoader(filePath)
              match grammarName with
  