@@ -285,7 +285,7 @@ function make_reaction_system(ex::Expr, name)
285285 ps_declared = extract_syms (options, :parameters )
286286 vs_declared = extract_syms (options, :variables )
287287 tiv, sivs, ivs, ivsexpr = read_ivs_option (options)
288- cmpexpr_init, cmps_declared = read_compound_option (options)
288+ cmpexpr_init, cmps_declared = read_compounds_option (options)
289289 diffsexpr, diffs_declared = read_differentials_option (options)
290290 syms_declared = collect (Iterators. flatten ((cmps_declared, sps_declared, ps_declared,
291291 vs_declared, ivs, diffs_declared)))
@@ -303,7 +303,7 @@ function make_reaction_system(ex::Expr, name)
303303 ps_inferred = setdiff (ps_pre_inferred, vs_inferred, diffs_inferred)
304304 syms_inferred = union (sps_inferred, ps_inferred, vs_inferred, diffs_inferred)
305305 all_syms = union (syms_declared, syms_inferred)
306- obsexpr, obs_eqs, obs_syms = read_observed_option (options, ivs,
306+ obsexpr, obs_eqs, obs_syms = read_observables_option (options, ivs,
307307 union (sps_declared, vs_declared), all_syms; requiredec)
308308
309309 # Read options not related to the declaration or inference of symbols.
508508
509509# ## DSL Output Expression Builders ###
510510
511+ # Given the parameters that were extracted from the reactions, and the options dictionary,
512+ # creates the `@parameters ...` expression for the macro output.
513+ function get_psexpr (parameters_extracted, options)
514+ pexprs = if haskey (options, :parameters )
515+ options[:parameters ]
516+ elseif isempty (parameters_extracted)
517+ :()
518+ else
519+ :(@parameters )
520+ end
521+ foreach (p -> push! (pexprs. args, p), parameters_extracted)
522+ pexprs
523+ end
524+
511525# Given the extracted species (or variables) and the option dictionary, create the
512526# `@species ...` (or `@variables ..`) expression which would declare these.
513527# If `key = :variables`, does this for variables (and not species).
@@ -525,20 +539,6 @@ function get_usexpr(us_extracted, options, key = :species; ivs = (DEFAULT_IV_SYM
525539 usexpr
526540end
527541
528- # Given the parameters that were extracted from the reactions, and the options dictionary,
529- # creates the `@parameters ...` expression for the macro output.
530- function get_psexpr (parameters_extracted, options)
531- pexprs = if haskey (options, :parameters )
532- options[:parameters ]
533- elseif isempty (parameters_extracted)
534- :()
535- else
536- :(@parameters )
537- end
538- foreach (p -> push! (pexprs. args, p), parameters_extracted)
539- pexprs
540- end
541-
542542# From the system reactions (as `DSLReaction`s) and equations (as expressions),
543543# creates the expression that evaluates to the reaction (+ equations) vector.
544544function get_rxexprs (reactions, equations, all_syms)
@@ -614,24 +614,28 @@ end
614614
615615# ## DSL Option Handling ###
616616
617- # Returns the `default_reaction_metadata` output. Technically Catalyst's code could have been made
618- # more generic to account for other default reaction metadata. Practically, this will likely
619- # be the only relevant reaction metadata to have a default value via the DSL. If another becomes
620- # relevant, the code can be rewritten to take this into account .
621- # Checks if the `@default_noise_scaling` option is used. If so, use it as the default value of
622- # the `default_noise_scaling` reaction metadata, otherwise, returns an empty vector.
623- function read_default_noise_scaling_option (options)
624- if haskey (options, :default_noise_scaling )
625- ( length (options[ :default_noise_scaling ] . args) != 3 ) &&
626- error ( " @default_noise_scaling should only have a single expression as its input, this appears not to be the case: \" $(options[ :default_noise_scaling ]) \" " )
627- return :([ :noise_scaling => $ (options[ :default_noise_scaling ] . args[ 3 ])] )
617+ # Finds the time independent variable, and any potential spatial independent variables.
618+ # Returns these (individually and combined), as well as an expression for declaring them.
619+ function read_ivs_option (options)
620+ # Creates the independent variables expressions (depends on whether the `ivs` option was used) .
621+ if haskey (options, :ivs )
622+ ivs = Tuple ( extract_syms (options, :ivs ))
623+ ivsexpr = copy (options[ :ivs ] )
624+ ivsexpr . args[ 1 ] = Symbol ( " @ " , " independent_variables " )
625+ else
626+ ivs = (DEFAULT_IV_SYM, )
627+ ivsexpr = :( $ (DEFAULT_IV_SYM) = default_t () )
628628 end
629- return :([])
629+
630+ # Extracts the independent variables symbols (time and spatial), and returns the output.
631+ tiv = ivs[1 ]
632+ sivs = (length (ivs) > 1 ) ? Expr (:vect , ivs[2 : end ]. .. ) : nothing
633+ return tiv, sivs, ivs, ivsexpr
630634end
631635
632636# When compound species are declared using the "@compound begin ... end" option, get a list
633637# of the compound species, and also the expression that creates them.
634- function read_compound_option (options)
638+ function read_compounds_option (options)
635639 # If the compound option is used, retrieve a list of compound species and the option line
636640 # that creates them (used to declare them as compounds at the end). Due to some expression
637641 # handling, in the case of a single compound we must change to the `@compound` macro.
@@ -648,38 +652,30 @@ function read_compound_option(options)
648652 return cmpexpr_init, cmps_declared
649653end
650654
651- # Read the events (continuous or discrete) provided as options to the DSL. Returns an expression which evaluates to these.
652- function read_events_option (options, event_type:: Symbol )
653- # Prepares the events, if required to, converts them to block form.
654- if event_type ∉ [:continuous_events , :discrete_events ]
655- error (" Trying to read an unsupported event type." )
656- end
657- events_input = haskey (options, event_type) ? get_block_option (options[event_type]) :
658- striplines (:(begin end ))
659- events_input = option_block_form (events_input)
660-
661- # Goes through the events, checks for errors, and adds them to the output vector.
662- events_expr = :([])
663- for arg in events_input. args
664- # Formatting error checks.
665- # NOTE: Maybe we should move these deeper into the system (rather than the DSL), throwing errors more generally?
666- if (arg isa Expr) && (arg. head != :call ) || (arg. args[1 ] != :(=> )) ||
667- (length (arg. args) != 3 )
668- error (" Events should be on form `condition => affect`, separated by a `=>`. This appears not to be the case for: $(arg) ." )
669- end
670- if (arg isa Expr) && (arg. args[2 ] isa Expr) && (arg. args[2 ]. head != :vect ) &&
671- (event_type == :continuous_events )
672- error (" The condition part of continuous events (the left-hand side) must be a vector. This is not the case for: $(arg) ." )
673- end
674- if (arg isa Expr) && (arg. args[3 ] isa Expr) && (arg. args[3 ]. head != :vect )
675- error (" The affect part of all events (the right-hand side) must be a vector. This is not the case for: $(arg) ." )
676- end
655+ # Creates an expression declaring differentials. Here, `tiv` is the time independent variables,
656+ # which is used by the default differential (if it is used).
657+ function read_differentials_option (options)
658+ # Creates the differential expression.
659+ # If differentials were provided as options, this is used as the initial expression.
660+ # If the default differential (D(...)) was used in equations, this is added to the expression.
661+ diffsexpr = (haskey (options, :differentials ) ?
662+ get_block_option (options[:differentials ]) : striplines (:(begin end )))
663+ diffsexpr = option_block_form (diffsexpr)
677664
678- # Adds the correctly formatted event to the event creation expression.
679- push! (events_expr. args, arg)
665+ # Goes through all differentials, checking that they are correctly formatted. Adds their
666+ # symbol to the list of declared differential symbols.
667+ diffs_declared = Union{Symbol, Expr}[]
668+ for dexpr in diffsexpr. args
669+ (dexpr. head != :(= )) &&
670+ error (" Differential declaration must have form like D = Differential(t), instead \" $(dexpr) \" was given." )
671+ (dexpr. args[1 ] isa Symbol) ||
672+ error (" Differential left-hand side must be a single symbol, instead \" $(dexpr. args[1 ]) \" was given." )
673+ in (dexpr. args[1 ], forbidden_symbols_error) &&
674+ error (" A forbidden symbol ($(dexpr. args[1 ]) ) was used as a differential name." )
675+ push! (diffs_declared, dexpr. args[1 ])
680676 end
681677
682- return events_expr
678+ return diffsexpr, diffs_declared
683679end
684680
685681# Reads the variables options. Outputs a list of the variables inferred from the equations,
@@ -740,36 +736,10 @@ function find_D_call(expr)
740736 end
741737end
742738
743- # Creates an expression declaring differentials. Here, `tiv` is the time independent variables,
744- # which is used by the default differential (if it is used).
745- function read_differentials_option (options)
746- # Creates the differential expression.
747- # If differentials were provided as options, this is used as the initial expression.
748- # If the default differential (D(...)) was used in equations, this is added to the expression.
749- diffsexpr = (haskey (options, :differentials ) ?
750- get_block_option (options[:differentials ]) : striplines (:(begin end )))
751- diffsexpr = option_block_form (diffsexpr)
752-
753- # Goes through all differentials, checking that they are correctly formatted. Adds their
754- # symbol to the list of declared differential symbols.
755- diffs_declared = Union{Symbol, Expr}[]
756- for dexpr in diffsexpr. args
757- (dexpr. head != :(= )) &&
758- error (" Differential declaration must have form like D = Differential(t), instead \" $(dexpr) \" was given." )
759- (dexpr. args[1 ] isa Symbol) ||
760- error (" Differential left-hand side must be a single symbol, instead \" $(dexpr. args[1 ]) \" was given." )
761- in (dexpr. args[1 ], forbidden_symbols_error) &&
762- error (" A forbidden symbol ($(dexpr. args[1 ]) ) was used as a differential name." )
763- push! (diffs_declared, dexpr. args[1 ])
764- end
765-
766- return diffsexpr, diffs_declared
767- end
768-
769739# Reads the observables options. Outputs an expression for creating the observable variables,
770740# a vector containing the observable equations, and a list of all observable symbols (this
771741# list contains both those declared separately or inferred from the `@observables` option` input`).
772- function read_observed_option (options, all_ivs, us_declared, all_syms; requiredec = false )
742+ function read_observables_option (options, all_ivs, us_declared, all_syms; requiredec = false )
773743 syms_unavailable = setdiff (all_syms, us_declared)
774744 if haskey (options, :observables )
775745 # Gets list of observable equations and prepares variable declaration expression.
@@ -849,32 +819,62 @@ function make_obs_eqs(observables_expr)
849819 return obs_eqs
850820end
851821
822+ # Read the events (continuous or discrete) provided as options to the DSL. Returns an expression which evaluates to these.
823+ function read_events_option (options, event_type:: Symbol )
824+ # Prepares the events, if required to, converts them to block form.
825+ if event_type ∉ [:continuous_events , :discrete_events ]
826+ error (" Trying to read an unsupported event type." )
827+ end
828+ events_input = haskey (options, event_type) ? get_block_option (options[event_type]) :
829+ striplines (:(begin end ))
830+ events_input = option_block_form (events_input)
831+
832+ # Goes through the events, checks for errors, and adds them to the output vector.
833+ events_expr = :([])
834+ for arg in events_input. args
835+ # Formatting error checks.
836+ # NOTE: Maybe we should move these deeper into the system (rather than the DSL), throwing errors more generally?
837+ if (arg isa Expr) && (arg. head != :call ) || (arg. args[1 ] != :(=> )) ||
838+ (length (arg. args) != 3 )
839+ error (" Events should be on form `condition => affect`, separated by a `=>`. This appears not to be the case for: $(arg) ." )
840+ end
841+ if (arg isa Expr) && (arg. args[2 ] isa Expr) && (arg. args[2 ]. head != :vect ) &&
842+ (event_type == :continuous_events )
843+ error (" The condition part of continuous events (the left-hand side) must be a vector. This is not the case for: $(arg) ." )
844+ end
845+ if (arg isa Expr) && (arg. args[3 ] isa Expr) && (arg. args[3 ]. head != :vect )
846+ error (" The affect part of all events (the right-hand side) must be a vector. This is not the case for: $(arg) ." )
847+ end
848+
849+ # Adds the correctly formatted event to the event creation expression.
850+ push! (events_expr. args, arg)
851+ end
852+
853+ return events_expr
854+ end
855+
856+ # Returns the `default_reaction_metadata` output. Technically Catalyst's code could have been made
857+ # more generic to account for other default reaction metadata. Practically, this will likely
858+ # be the only relevant reaction metadata to have a default value via the DSL. If another becomes
859+ # relevant, the code can be rewritten to take this into account.
860+ # Checks if the `@default_noise_scaling` option is used. If so, use it as the default value of
861+ # the `default_noise_scaling` reaction metadata, otherwise, returns an empty vector.
862+ function read_default_noise_scaling_option (options)
863+ if haskey (options, :default_noise_scaling )
864+ (length (options[:default_noise_scaling ]. args) != 3 ) &&
865+ error (" @default_noise_scaling should only have a single expression as its input, this appears not to be the case: \" $(options[:default_noise_scaling ]) \" " )
866+ return :([:noise_scaling => $ (options[:default_noise_scaling ]. args[3 ])])
867+ end
868+ return :([])
869+ end
870+
852871# Reads the combinatorial ratelaw options, which determines if a combinatorial rate law should
853872# be used or not. If not provided, use the default (true).
854873function read_combinatoric_ratelaws_option (options)
855874 return haskey (options, :combinatoric_ratelaws ) ?
856875 get_block_option (options[:combinatoric_ratelaws ]) : true
857876end
858877
859- # Finds the time independent variable, and any potential spatial independent variables.
860- # Returns these (individually and combined), as well as an expression for declaring them.
861- function read_ivs_option (options)
862- # Creates the independent variables expressions (depends on whether the `ivs` option was used).
863- if haskey (options, :ivs )
864- ivs = Tuple (extract_syms (options, :ivs ))
865- ivsexpr = copy (options[:ivs ])
866- ivsexpr. args[1 ] = Symbol (" @" , " independent_variables" )
867- else
868- ivs = (DEFAULT_IV_SYM,)
869- ivsexpr = :($ (DEFAULT_IV_SYM) = default_t ())
870- end
871-
872- # Extracts the independent variables symbols (time and spatial), and returns the output.
873- tiv = ivs[1 ]
874- sivs = (length (ivs) > 1 ) ? Expr (:vect , ivs[2 : end ]. .. ) : nothing
875- return tiv, sivs, ivs, ivsexpr
876- end
877-
878878# ## `@reaction` Macro & its Internals ###
879879
880880"""
0 commit comments