Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions src/GslCore/AlleleSwaps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/// Support for introducing mutations into genes
///
open Amyris.Bio
open Amyris.ErrorHandling
open Amyris.Dna
open System
open constants
Expand All @@ -17,7 +18,7 @@ open IO.CodonUsage
open utils
open biolib
open primercore
open ryse // for getrabit
open FetchPart

open PluginTypes

Expand Down Expand Up @@ -121,16 +122,9 @@ let selectMutCodonRight = selectMutCodonBase diffRight
/// expand a simple mutation inline with a part
let expandSimpleMut (asAACheck:bool) (_:GenomeDef) (g:PartIdLegacy) (m:Mutation) : GslSourceCode =

// Get part sequence
if not (g.id.StartsWith("R")) then
failwithf
"ERROR: part %s should start with 'R'. Non rabit part mutation not supported."
g.id

let hr = getRabit (int(g.id.[1..]))

let rabit = hr.RabitSpecs.[0]
let dna = rabit.DnaElementSpecs.[0].DnaSequence.ToUpper()
let dna =
let part = fetchPart g.id |> returnOrFail
part.dna
// Now split by type of mutation and check the original base/amino acid is legit
match m.mType with
| NT ->
Expand Down Expand Up @@ -158,7 +152,7 @@ let expandSimpleMut (asAACheck:bool) (_:GenomeDef) (g:PartIdLegacy) (m:Mutation)
"ERROR: mutation position %d outside range of rabit %s amino acids"
m.loc g.id

let currentCodon = (dna.[(m.loc-1)*3..(m.loc-1)*3+2]).ToCharArray()
let currentCodon = (dna.[(m.loc-1)*3..(m.loc-1)*3+2]).arr

// Ensure we are in the right place in the gene
if (codon2aa currentCodon <> m.f) && asAACheck then
Expand Down
13 changes: 7 additions & 6 deletions src/GslCore/AstExpansion.fs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ open commonTypes
open resolveExtPart
open LexAndParse
open PluginTypes
open FetchPart

// ==================
// phase 1 of AST reduction
Expand Down Expand Up @@ -879,12 +880,12 @@ let private expandHB
// External part variation
// ===============================================

match fetchFullPartSequence(verbose) (Map.empty) pid1 with
| EXT_FAIL(msg) -> failwithf "Fail fetching %s %s" pid1.id msg
| EXT_FETCH_OK(part1) ->
match fetchFullPartSequence verbose Map.empty pid4 with
| EXT_FAIL(msg) -> failwithf "Fail fetching %s %s" pid1.id msg
| EXT_FETCH_OK(part4) ->
match fetchPart pid1.id with
| Bad msgs -> failwithf "Fail fetching %s %s" pid1.id (msgs |> String.concat " ")
| Ok(part1, _) ->
match fetchPart pid4.id with
| Bad msgs -> failwithf "Fail fetching %s %s" pid1.id (msgs |> String.concat " ")
| Ok(part4, _) ->
let s1= getExtPartSlice verbose pid1
let s4= getExtPartSlice verbose pid4

Expand Down
2 changes: 1 addition & 1 deletion src/GslCore/DnaCreation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ let expandAssembly
yield markerProvider.CreateDna(task)

| PARTID(partId) ->
yield resolveExtPart.fetchSequence verbose library ppp partId
yield resolveExtPart.fetchSequence verbose ppp partId
| INLINEDNA(dna) ->
yield expandInlineDna dnaSource ppp dna
| INLINEPROT(_) ->
Expand Down
46 changes: 46 additions & 0 deletions src/GslCore/FetchPart.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/// Plugin-based retrieval of parts from external catalogs.
module FetchPart

open PluginTypes
open Amyris.ErrorHandling
open Amyris.Dna

// In an ideal world, this collection of plugins would be injected from the top, but at the time of this writing the
// compiler uses part retrieval functions in a large number of places, requiring a frustrating quantity of refactoring.
// Thus, this module-bound global structure.

let mutable private partProviders: IPartProvider array = Array.empty

/// Set the available part providers.
/// This should be called once at program initialization.
let setPartProviders providers = partProviders <- providers

type ExternalPart = {
/// Persistent identifier.
id: string
/// Human-readable name.
name: string
/// DNA sequence of this part.
dna: Dna
/// Optional RYSE linker specification (5' link code, 3' link code).
linkers: (string*string) option
/// Name of the part provider that provided this part.
source: string
}

/// Use the available part providers to try to fetch a part based on its ID.
let fetchPart partId : Result<ExternalPart, string> =
match partProviders |> Array.filter (fun p -> p.Accept(partId)) with
| [||] -> fail <| sprintf "No external part provider found for part ID \"%s\"." partId
| [|provider|] ->
provider.Retrieve(partId)
>>= (fun fetched ->
ok {
id = partId
source = provider.Name
name = fetched.name
linkers = fetched.linkers
dna = fetched.dna})
| tooMany ->
let names = tooMany |> Array.map (fun p -> p.Name) |> String.concat ", "
fail <| sprintf "More than one part provider service found for part ID \"%s\": %s" partId names
20 changes: 11 additions & 9 deletions src/GslCore/GslCore.fsproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>GslCore</RootNamespace>
Expand All @@ -9,12 +8,8 @@
</PropertyGroup>
<Import Project="..\..\packages\FsLexYacc\build\FsLexYacc.targets" />
<ItemGroup>
<FsYacc Include=".\GslParser.fsy">
<OtherFlags>--module GslParser -o GslParser.fs</OtherFlags>
</FsYacc>
<FsLex Include=".\GslLexer.fsl">
<OtherFlags>--unicode -o GslLexer.fs</OtherFlags>
</FsLex>
<FsLex Include="GslLexer.fsl" />
<FsYacc Include="GslParser.fsy" />
<Compile Include="Constants.fs" />

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checking on this change - this removed the params to the lexer / yacc which is perhaps unintended?

<Compile Include="Utils.fs" />
<Compile Include="PcrParamParse.fs" />
Expand All @@ -39,6 +34,7 @@
<Compile Include="PrimerDump.fs" />
<Compile Include="DumpFlat.fs" />
<Compile Include="PluginTypes.fs" />
<Compile Include="FetchPart.fs" />
<Compile Include="BasicCodonProvider.fs" />
<Compile Include="RycodExample.fs" />
<Compile Include="SbolExample.fs" />
Expand All @@ -60,7 +56,13 @@
<Compile Include="GslcProcess.fs" />
<Compile Include="SeamlessPlugin.fs" />
<Compile Include="Gslc.fs" />
<Compile Include="AssemblyInfo.fs" />
<FsLex Include=".\GslLexer.fsl">
<OtherFlags>--unicode -o GslLexer.fs</OtherFlags>
</FsLex>
<FsYacc Include=".\GslParser.fsy">
<OtherFlags>--module GslParser -o GslParser.fs</OtherFlags>
</FsYacc>
<Compile Include="LibraryPartProvider.fs" />
</ItemGroup>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, see them here - I think they probably need to be deleted above then, or else they are there twice? Sorry if I'm just misreading the diff

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dunno what's up with this, not sure why these changed. I'll revert them next week.

<Import Project="..\..\.paket\Paket.Restore.targets" />
</Project>
30 changes: 30 additions & 0 deletions src/GslCore/LibraryPartProvider.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/// Support for reusable part retrieval based on a FASTA file.
module LibraryPartProvider
open System.IO
open commonTypes
open PluginTypes
open Amyris.Dna
open Amyris.ErrorHandling

type LibraryPartProvider() =

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like this! - have been wanting to just get rid of this legacy concept but this is probably a more responsible approach. Not sure if that feature is in use at Amyris. I don't think we are using it at Demetrix.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's in use at Amyris beyond regression tests. I think as a plugin is provides a relatively easy feature for anyone who wants to use the compiler to provide a library of components (just need a fasta file), and serves as a simple template for others to implement part providers.

let mutable library: SequenceLibrary = Map.empty
do
()
with
interface IPartProvider with
member __.ProvidedArgs() = []
member x.Configure(_) = x :> IPartProvider
/// Load the sequence library from the GSLC lib directory, if it exists.
member x.ConfigureFromOptions(opts) =
let libFile = Path.Combine(opts.libDir, "lib.fa")
if File.Exists libFile then
let lib =
Amyris.Bio.biolib.readReference libFile
|> Seq.map (fun kv -> (kv.Key.ToUpper(), Dna(kv.Value) ))
|> Map.ofSeq
library <- lib

x :> IPartProvider
member x.Name = "library"
member x.Accept(partId) = library |> Map.containsKey partId
member x.Retrieve(partId) = ok {name = partId; dna = library.[partId]; linkers = None}
32 changes: 32 additions & 0 deletions src/GslCore/PluginTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,30 @@ type L2Provider = {
implicitLocusProvider:L2DesignParams-> GslSourceCode
}

// ==================================================
// plugin for retrieving an existing part
// ==================================================

type ExtFetchSeq = {
/// Human-readable name.
name: string
/// DNA sequence of this part.
dna: Dna
/// Optional RYSE linker specification (5' link code, 3' link code).
linkers: (string*string) option
}

type IPartProvider =
/// Allow part providers to add command line args and be configurable.
inherit IConfigurable<IPartProvider>
/// The name of this part provider service.
abstract member Name: string
/// Return true if this provider thinks it recognizes the provided identifier.
abstract member Accept: string -> bool
/// Call the service to retrieve this part.
/// Implementors may assume that this method will only be called if Accept has returned true.
abstract member Retrieve: string -> Result<ExtFetchSeq, string>

// ======================
// plugin behavior definition for output assembly transformations
// ======================
Expand Down Expand Up @@ -208,13 +232,15 @@ type PluginBehavior =
| L2KOTitration of L2Provider
| OutputFormat of IOutputFormat
| AssemblyTransform of IAssemblyTransform
| PartProvider of IPartProvider
| CodonProvider of ICodonProvider
| MarkerProvider of IMarkerProvider
with
member b.ProvidedArgs() =
match b with
| OutputFormat(f) -> f.ProvidedArgs()
| AssemblyTransform(a) -> a.ProvidedArgs()
| PartProvider(p) -> p.ProvidedArgs()
| CodonProvider(c) -> c.ProvidedArgs()
| _ -> []

Expand All @@ -236,6 +262,7 @@ let configureBehavior arg b =
match b.behavior with
| OutputFormat(f) -> {b with behavior = OutputFormat(f.Configure(arg))}
| AssemblyTransform(a) -> {b with behavior = AssemblyTransform(a.Configure(arg))}
| PartProvider(p) -> {b with behavior = PartProvider(p.Configure(arg))}
| CodonProvider(c) -> {b with behavior = CodonProvider(c.Configure(arg))}
| MarkerProvider(m) -> {b with behavior = MarkerProvider(m.Configure(arg))}
| AlleleSwapAA _
Expand All @@ -245,6 +272,7 @@ let configureBehaviorFromOpts opts b =
match b.behavior with
| OutputFormat(f) -> {b with behavior = OutputFormat(f.ConfigureFromOptions(opts))}
| AssemblyTransform(a) -> {b with behavior = AssemblyTransform(a.ConfigureFromOptions(opts))}
| PartProvider(p) -> {b with behavior = PartProvider(p.ConfigureFromOptions(opts))}
| CodonProvider(c) -> {b with behavior = CodonProvider(c.ConfigureFromOptions(opts))}
| MarkerProvider(c) -> {b with behavior = MarkerProvider(c.ConfigureFromOptions(opts))}
| AlleleSwapAA _
Expand Down Expand Up @@ -330,6 +358,10 @@ let getAssemblyTransformers (plugin: Plugin) =
plugin.behaviors
|> List.choose (fun b -> match b.behavior with | AssemblyTransform(a) -> Some(a.TransformAssembly) | _ -> None)

let getPartProviders (plugin: Plugin) =
plugin.behaviors
|> List.choose (fun b -> match b.behavior with | PartProvider(a) -> Some(a) | _ -> None)

let getOutputProviders (plugin: Plugin) =
plugin.behaviors
|> List.choose (fun b -> match b.behavior with | OutputFormat(a) -> Some(a) | _ -> None)
Expand Down
Loading