Skip to content

Commit 98c066b

Browse files
authored
Merge pull request #1230 from SciML/expression_utils_improvement
Improve expression parser function
2 parents d69f4d7 + ca9a274 commit 98c066b

File tree

3 files changed

+42
-46
lines changed

3 files changed

+42
-46
lines changed

src/chemistry_functionality.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ function make_compound(expr)
9999
# - Any ivs attached to it (ivs, e.g. `[]` or `[t,x]`).
100100
# - The expression which creates the compound (species_expr, e.g. `CO2 = 1.0, [metadata=true]`).
101101
species_expr = expr.args[2]
102-
species_name, ivs, _, _ = find_varinfo_in_declaration(expr.args[2])
102+
species_name, ivs, _, _, _ = find_varinfo_in_declaration(expr.args[2])
103103

104104
# If no ivs were given, inserts an expression which evaluates to the union of the ivs
105105
# for the species the compound depends on.

src/dsl.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ end
734734
# Searches an expression `expr` and returns true if it has any subexpression `D(...)` (where `...` can be anything).
735735
# Used to determine whether the default differential D has been used in any equation provided to `@equations`.
736736
function find_D_call(expr)
737-
return if Base.isexpr(expr, :call) && expr.args[1] == :D
737+
return if Meta.isexpr(expr, :call) && expr.args[1] == :D
738738
true
739739
elseif expr isa Expr
740740
any(find_D_call, expr.args)
@@ -757,7 +757,7 @@ function read_observables_option(options, all_ivs, us_declared, all_syms; requir
757757

758758
for (idx, obs_eq) in enumerate(obs_eqs.args)
759759
# Extract the observable, checks for errors.
760-
obs_name, ivs, defaults, metadata = find_varinfo_in_declaration(obs_eq.args[2])
760+
obs_name, ivs, _, defaults, metadata = find_varinfo_in_declaration(obs_eq.args[2])
761761

762762
# Error checks.
763763
(requiredec && !in(obs_name, us_declared)) &&

src/expression_utils.jl

Lines changed: 39 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ end
1818

1919
# Checks if an expression is an escaped expression (e.g. on the form `$(Expr(:escape, :Y))`)
2020
function is_escaped_expr(expr)
21-
return (expr isa Expr) && (expr.head == :escape) && (length(expr.args) == 1)
21+
return Meta.isexpr(expr, :escape) && (length(expr.args) == 1)
2222
end
2323

2424
### Parameters/Species/Variables Symbols Correctness Checking ###
@@ -52,52 +52,48 @@ function option_block_form(expr)
5252
return Expr(:block, expr)
5353
end
5454

55-
# In variable/species/parameters on the forms like:
55+
# In variable/species/parameters on the forms like (examples, 16 alternatives in total):
5656
# X
57-
# X = 1.0
58-
# X, [metadata=true]
59-
# X = 1.0, [metadata=true]
60-
# X(t)
61-
# X(t) = 1.0
62-
# X(t), [metadata=true]
63-
# X(t) = 1.0, [metadata=true]
64-
# Finds the: Variable name (X), Independent variable name(s) ([t]), default value (2.0), and metadata (:([metadata=true])).
65-
# If a field does not exist (e.g. independent variable in `X, [metadata=true]`), gives nothing.
66-
# The independent variables are given as a vector (empty if none given).
67-
# Does not support e.g. "X [metadata=true]" (when metadata does not have a comma before).
68-
function find_varinfo_in_declaration(expr)
69-
# Handles the $(Expr(:escape, :Y)) case:
70-
is_escaped_expr(expr) && (return find_varinfo_in_declaration(expr.args[1]))
57+
# X = 1.0, [misc=5]
58+
# X(t)[1:2]
59+
# X(t) = 1.0, [misc=5]
60+
# X(t)[1:2] = 1.0, [misc = 5]
61+
# Finds the: Variable name (X), Independent variable name(s) ([t]), indexes (1:2),
62+
# default value (1.0), and metadata (:([metadata=true])).
63+
# Information that does not exist (e.g. independent variable in `X, [metadata=true]`), is
64+
# returned as `nothing`.
65+
# The independent variables are returned as a vector (empty if none given).
66+
function find_varinfo_in_declaration(expr::ExprValues)
67+
# Initialises values. Step by step, reads one and scales it away from the expression
68+
metadata = default = idxs = ivs = nothing
7169

72-
# Case: X
73-
(expr isa Symbol) && (return expr, [], nothing, nothing)
74-
# Case: X(t)
75-
(expr.head == :call) && (return expr.args[1], expr.args[2:end], nothing, nothing)
76-
if expr.head == :(=)
77-
# Case: X = 1.0
78-
(expr.args[1] isa Symbol) && (return expr.args[1], [], expr.args[2], nothing)
79-
# Case: X(t) = 1.0
80-
(expr.args[1].head == :call) &&
81-
(return expr.args[1].args[1], expr.args[1].args[2:end], expr.args[2].args[1],
82-
nothing)
70+
# Reads and removes metadata (e.g. `[misc = 5]` in `:(X(t)[1:2] = 1.0, [misc = 5])`).
71+
if Meta.isexpr(expr, :tuple)
72+
metadata = expr.args[2]
73+
expr = expr.args[1]
8374
end
84-
if expr.head == :tuple
85-
# Case: X, [metadata=true]
86-
(expr.args[1] isa Symbol) && (return expr.args[1], [], nothing, expr.args[2])
87-
# Case: X(t), [metadata=true]
88-
(expr.args[1].head == :call) &&
89-
(return expr.args[1].args[1], expr.args[1].args[2:end], nothing, expr.args[2])
90-
if expr.args[1].head == :(=)
91-
# Case: X = 1.0, [metadata=true]
92-
(expr.args[1].args[1] isa Symbol) &&
93-
(return expr.args[1].args[1], [], expr.args[1].args[2], expr.args[2])
94-
# Case: X(t) = 1.0, [metadata=true]
95-
(expr.args[1].args[1].head == :call) &&
96-
(return expr.args[1].args[1].args[1], expr.args[1].args[1].args[2:end],
97-
expr.args[1].args[2].args[1], expr.args[2])
98-
end
75+
# Reads and removes metadata (e.g. `1.0` in `:(X(t)[1:2] = 1.0)`).
76+
if Meta.isexpr(expr, :(=))
77+
default = expr.args[2]
78+
expr = expr.args[1]
9979
end
100-
error("Unable to detect the variable declared in expression: $expr.")
80+
# Reads and removes indexes (e.g. `[1:2]` in `:(X(t)[1:2])`).
81+
if Meta.isexpr(expr, :ref)
82+
idxs = expr.args[2]
83+
expr = expr.args[1]
84+
end
85+
# Reads and removes independent variables (e.g. `t` in `:(X(t))`).
86+
if Meta.isexpr(expr, :call)
87+
ivs = expr.args[2:end]
88+
expr = expr.args[1]
89+
end
90+
isnothing(ivs) && (ivs = [])
91+
92+
# If escaped expression, extract symbol. Checks that the expression is a symbol (e.g. `X` in `:(X(t))`).
93+
Meta.isexpr(expr, :escape) && (expr = expr.args[1])
94+
(expr isa Symbol) ||
95+
error("Erroneous expression encountered in `find_varinfo_in_declaration` (got `$expr` after processing, this should be a symbol).")
96+
return (;sym = expr, ivs, idxs, default, metadata)
10197
end
10298

10399
# Converts an expression of the forms:

0 commit comments

Comments
 (0)