|
9 | 9 | About
|
10 | 10 | =============
|
11 | 11 |
|
12 |
| -The `solve` function will solve the scopes of a given AST, |
13 |
| -and then replace |
14 |
| - |
15 |
| -- all variable symbols with `ScopedVar(::Scope, ::Symbol)`, |
16 |
| -- all function definitions with `ScopedFunc(::Scope, ::Expr)`, |
17 |
| -- all generators with `ScopedGenerator(::Scope, ::Expr)` |
18 |
| - |
19 |
| -For more details, check the implementation of [NameResolution.jl](https://github.com/thautwarm/NameResolution.jl). |
20 |
| - |
21 |
| - |
22 |
| -**ATTENTION!!!** : |
| 12 | +The `solve` function will solve the scopes of a **simplified** Julia expression. |
| 13 | + |
| 14 | +- The variables(`Symbol`) are transformed to `Var`: |
| 15 | + ```julia |
| 16 | + struct Var |
| 17 | + name :: Symbol |
| 18 | + is_mutable :: Bool |
| 19 | + is_shared :: Bool |
| 20 | + is_global :: Bool |
| 21 | + end |
| 22 | + ``` |
| 23 | +- Some expressions will be wrapped within `Expr(:scoped, (bounds=..., freevars=..., bound_inits=...), inner_expression)`. |
23 | 24 |
|
24 |
| -`solve` will give up analysing when meeting `macrocall` expressions. You can expand them before using |
25 |
| -`solve`. |
| 25 | +Example |
| 26 | +============== |
26 | 27 |
|
27 |
| -Usage |
28 |
| -========== |
| 28 | +`solve` & `solve_from_local` |
| 29 | +----------------------------- |
29 | 30 |
|
30 | 31 | ```julia
|
31 |
| -using JuliaVariables |
32 |
| -rmlines = JuliaVariables.rmlines |
33 |
| -func = solve(:(function f(x) |
34 |
| - let y = x + 1 |
35 |
| - y |
| 32 | +julia> using MLStyle |
| 33 | +
|
| 34 | +julia> unwrap_scoped(ex) = |
| 35 | + @match ex begin |
| 36 | + Expr(:scoped, _, a) => unwrap_scoped(a) |
| 37 | + Expr(head, args...) => Expr(head, map(unwrap_scoped, args)...) |
| 38 | + a => a |
| 39 | + end |
| 40 | +unwrap_scoped (generic function with 1 method) |
| 41 | +
|
| 42 | +julia> quote |
| 43 | + x = 1 |
| 44 | + function (a) |
| 45 | + x = 1 |
| 46 | + end |
| 47 | + end |> solve_from_local |> rmlines |> unwrap_scoped |
| 48 | +quote |
| 49 | + mut @shared x = 1 |
| 50 | + function (a,) |
| 51 | + mut @shared x = 1 |
36 | 52 | end
|
37 |
| -end)) |
38 |
| -println(func |> rmlines) |
39 |
| - |
40 |
| -func = solve(:(function f(x) |
41 |
| - y = x + 1 |
42 |
| - z -> z + y |
43 |
| -end)) |
| 53 | +end |
44 | 54 |
|
45 |
| -println(func |> rmlines) |
46 | 55 |
|
47 |
| -func = solve(:(function f(x) |
48 |
| - y = x + 1 |
49 |
| - let y = y + 1 |
50 |
| - (x + y + z for z in 1:10) |
| 56 | +julia> quote |
| 57 | + x = 1 |
| 58 | + function () |
| 59 | + x = 1 |
| 60 | + end |
| 61 | + end |> solve |> rmlines |
| 62 | +:($(Expr(:scoped, (bounds = Var[], freevars = Var[], bound_inits = Symbol[]), quote |
| 63 | + @global x = 1 |
| 64 | + function () |
| 65 | + $(Expr(:scoped, (bounds = Var[@local x], freevars = Var[], bound_inits = Symbol[]), quote |
| 66 | + @local x = 1 |
| 67 | +end)) |
51 | 68 | end
|
| 69 | +end))) |
| 70 | +
|
| 71 | +
|
| 72 | +julia> quote |
| 73 | + x = 1 |
| 74 | + function () |
| 75 | + x = 1 |
| 76 | + end |
| 77 | + end |> solve_from_local |> rmlines |
| 78 | +:($(Expr(:scoped, (bounds = Var[mut @shared x], freevars = Var[], bound_inits = Symbol[]), quote |
| 79 | + mut @shared x = 1 |
| 80 | + function () |
| 81 | + $(Expr(:scoped, (bounds = Var[], freevars = Var[mut @shared x], bound_inits = Symbol[]), quote |
| 82 | + mut @shared x = 1 |
52 | 83 | end))
|
53 |
| -println(func |> rmlines) |
| 84 | + end |
| 85 | +end))) |
| 86 | +``` |
| 87 | + |
| 88 | +`simplify_ex` |
| 89 | +------------------- |
54 | 90 |
|
| 91 | +Not all expressions can be accepted as the input of `solve` or `solve_from_local`, thus we provide such a |
| 92 | +handy API to apply conversions from almost arbitrary |
| 93 | +expressions to the *simplified* expressions. |
55 | 94 |
|
56 |
| -func = solve( |
57 |
| - macroexpand(@__MODULE__,:( |
58 |
| - @inline function f(x) |
59 |
| - y = x + 1 |
60 |
| - let y = y + 1 |
61 |
| - (x + y + z for z in 1:10) |
| 95 | +```julia |
| 96 | +julia> quote |
| 97 | + function f(x) |
| 98 | + for i in I, j in J |
| 99 | + let x = 1, y |
| 100 | + () -> 2 |
| 101 | + end |
| 102 | + end |
| 103 | + f(x) = 2 |
| 104 | + end |
| 105 | + end |> rmlines |> simplify_ex |
| 106 | +quote |
| 107 | + function f(x) |
| 108 | + for i = I |
| 109 | + for j = J |
| 110 | + let x = 1 |
| 111 | + let y |
| 112 | + function () |
| 113 | + 2 |
| 114 | + end |
| 115 | + end |
| 116 | + end |
| 117 | + end |
| 118 | + end |
| 119 | + function f(x) |
| 120 | + 2 |
62 | 121 | end
|
63 | 122 | end
|
64 |
| -))) |
65 |
| -println(func |> rmlines) |
| 123 | +end |
66 | 124 | ```
|
67 | 125 |
|
68 |
| -=> |
| 126 | +The reason why we don't couple this API with `solve` is, we need to let user aware that there exists destructive operations for expressing the scope information, for instance, it's impossible to inject |
| 127 | +scope information to `for i in I, j in J; body end`, because |
| 128 | +the AST shape of it is |
69 | 129 |
|
70 | 130 | ```julia
|
71 |
| -[]function (f)(@x) |
72 |
| - let @y = (@global +)(@x, 1) |
73 |
| - @y |
74 |
| - end |
75 |
| -end |
| 131 | +Expr(:for, |
| 132 | + Expr(:block, |
| 133 | + :(i = I), |
| 134 | + :(j = J), |
| 135 | + ), |
| 136 | + Expr(:block, body) |
| 137 | +) |
| 138 | +``` |
76 | 139 |
|
77 |
| -[]function (f)(@x) |
78 |
| - @cell y = (@global +)(@x, 1) |
79 |
| - [cell y]@z->begin |
80 |
| - (@global +)(@z, @cell y) |
81 |
| - end |
82 |
| -end |
| 140 | +`Expr(:block, body)` is actually in the sub-scope of |
| 141 | +that of `:(j = J)`, and `:(j=J)`'s scope in inherited from that of `:(i=I)`, which ruins the handy use(especially the top-down tree visiting) of scoped expressions. |
83 | 142 |
|
84 |
| -[]function (f)(@cell x) |
85 |
| - @y = (@global +)(@cell x, 1) |
86 |
| - let @cell y = (@global +)(@cell y, 1) |
87 |
| - [cell y,cell x]((@global +)(@cell x, @cell y, @z) for @z = (@global :)(1, 10)) |
88 |
| - end |
89 |
| -end |
| 143 | +Not only due to the uselessness of scoping the messy ASTs like `for i in I, j in J; body end`, the analyses for them are also much more ugly to implement than those of the *simplified* expressions. Finally, I give up doing this. |
90 | 144 |
|
91 |
| -[]function (f)(@cell x) |
92 |
| - $(Expr(:meta, @global inline)) |
93 |
| - @y = (@global +)(@cell x, 1) |
94 |
| - let @cell y = (@global +)(@cell y, 1) |
95 |
| - [cell y,cell x]((@global +)(@cell x, @cell y, @z) for @z = (@global :)(1, 10)) |
96 |
| - end |
97 |
| -end |
| 145 | +If you have understand the above concerns and made |
| 146 | +sure it's safe to return a restructured expression after injecting scope information, you can compose |
| 147 | +`simplify_ex` and `solve` to gain a more handy API: |
98 | 148 |
|
99 |
| -``` |
| 149 | +```julia |
| 150 | +mysolve = solve ∘ simplify_ex |
| 151 | +mysolve_from_local = solve_from_local ∘ simplify_ex |
| 152 | +``` |
0 commit comments