|
18 | 18 |
|
19 | 19 | # Checks if an expression is an escaped expression (e.g. on the form `$(Expr(:escape, :Y))`)
|
20 | 20 | 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) |
22 | 22 | end
|
23 | 23 |
|
24 | 24 | ### Parameters/Species/Variables Symbols Correctness Checking ###
|
@@ -52,52 +52,70 @@ function option_block_form(expr)
|
52 | 52 | return Expr(:block, expr)
|
53 | 53 | end
|
54 | 54 |
|
55 |
| -# In variable/species/parameters on the forms like: |
| 55 | +# In variable/species/parameters on the forms like (examples, 16 alternatives in total): |
56 | 56 | # 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] |
83 | 74 | 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] |
99 | 89 | 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]) |
101 | 119 | end
|
102 | 120 |
|
103 | 121 | # Converts an expression of the forms:
|
|
0 commit comments