Skip to content

Commit 3b5f6f5

Browse files
committed
init
1 parent ab266f9 commit 3b5f6f5

File tree

2 files changed

+63
-45
lines changed

2 files changed

+63
-45
lines changed

src/dsl.jl

Lines changed: 1 addition & 1 deletion
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)

src/expression_utils.jl

Lines changed: 62 additions & 44 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,70 @@ 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]))
71-
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)
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
69+
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]
79+
end
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]
9989
end
100-
error("Unable to detect the variable declared in expression: $expr.")
90+
91+
(expr isa Symbol) ||
92+
error("Erroneous expression encountered in `find_varinfo_in_declaration` (got `$expr` after processing, this should be a symbol).")
93+
return (;ivs, idxs, default, metadata)
94+
end
95+
96+
# Sometimes (when declared on a single line, e.g. `@variables X [misc = 4] Y [misc = 5]`)
97+
# the symbolic variable are metadata never form a single expression, but are simply separate
98+
# (but adjacent) expressions in a longer expression array. This dispatch extracts the same
99+
# information, but from this case. The input is the vector of all expressions, and the index
100+
# of the symbolic variable which information we wish to extract.
101+
function find_varinfo_in_declaration(exprs::Vector, idx::Integer)
102+
if (idx != length(exprs)) && Meta.isexpr(exprs[idx + 1], :vect)
103+
expr, (ivs, idxs, default, metadata) = find_varinfo_in_declaration(exprs[idx])
104+
return expr => (ivs, idxs, default, exprs[idx + 1])
105+
end
106+
return find_varinfo_in_declaration(exprs[idx])
107+
end
108+
109+
# Checks an expression that declares several symbolic variables (either using `@variables ...`
110+
# or using `@variables begin ... end`). Returns a dictionary with each information, using the
111+
# form used in find_varinfo_in_declaration.
112+
function find_all_varinfo_in_declaration(exprs)
113+
# (1)) Removes the macro call (2) Handles the `@variables begin .. end` case
114+
# (3) Find all indexes with variables (4) Extract their information.
115+
exprs = exprs.args[3:end]
116+
_head_equisexpral(exprs[1], :block) && (exprs = exprs[1].args)
117+
var_idxs = findall(!Meta.isexpr(expr, :vect) for expr in exprs)
118+
return Dict([find_varinfo_in_declaration(exprs, var_idx) for var_idx in var_idxs])
101119
end
102120

103121
# Converts an expression of the forms:

0 commit comments

Comments
 (0)