|
| 1 | +eval_impl(::Type{T}, code, globals, locals=nothing, extrakeys::Tuple{Vararg{Any,N}}=(), extravals::Tuple{Vararg{Any,N}}=()) where {T,N} = GC.@preserve code globals locals begin |
| 2 | + # get pointers to inputs |
| 3 | + cptr = checknull(pyptr(code)) |
| 4 | + ensurehasbuiltins!(globals) |
| 5 | + gptr = checknull(pyptr(globals)) |
| 6 | + lptr = checknull(locals === nothing ? C.PyDict_New() : pyptr(locals)) |
| 7 | + # insert extras into locals |
| 8 | + for (k, v) in zip(extrakeys, extravals) |
| 9 | + vo = C.PyObject_From(v) |
| 10 | + isnull(vo) && @goto error |
| 11 | + err = C.PyObject_SetItem(lptr, k, vo) |
| 12 | + C.Py_DecRef(vo) |
| 13 | + ism1(err) && @goto error |
| 14 | + end |
| 15 | + # eval |
| 16 | + rptr = C.PyEval_EvalCode(cptr, gptr, lptr) |
| 17 | + isnull(rptr) && @goto error |
| 18 | + # convert the result |
| 19 | + err = C.PyObject_Convert(rptr, T) |
| 20 | + C.Py_DecRef(rptr) |
| 21 | + ism1(err) && @goto error |
| 22 | + locals === nothing && C.Py_DecRef(lptr) |
| 23 | + return takeresult(T) |
| 24 | + |
| 25 | + @label error |
| 26 | + locals === nothing && C.Py_DecRef(lptr) |
| 27 | + pythrow() |
| 28 | +end |
| 29 | + |
| 30 | +exec_impl(f, code, globals, locals=nothing, extrakeys::Tuple{Vararg{Any,N}}=(), extravals::Tuple{Vararg{Any,N}}=()) where {N} = GC.@preserve code globals locals begin |
| 31 | + # get pointers to inputs |
| 32 | + cptr = checknull(pyptr(code)) |
| 33 | + ensurehasbuiltins!(globals) |
| 34 | + gptr = checknull(pyptr(globals)) |
| 35 | + lptr = checknull(locals === nothing ? C.PyDict_New() : pyptr(locals)) |
| 36 | + # insert extras into locals |
| 37 | + for (k, v) in zip(extrakeys, extravals) |
| 38 | + vo = C.PyObject_From(v) |
| 39 | + isnull(vo) && @goto error |
| 40 | + err = C.PyObject_SetItem(lptr, k, vo) |
| 41 | + C.Py_DecRef(vo) |
| 42 | + ism1(err) && @goto error |
| 43 | + end |
| 44 | + # eval |
| 45 | + rptr = C.PyEval_EvalCode(cptr, gptr, lptr) |
| 46 | + isnull(rptr) && @goto error |
| 47 | + C.Py_DecRef(rptr) |
| 48 | + # extract the result |
| 49 | + return f(lptr, locals===nothing) |
| 50 | + |
| 51 | + @label error |
| 52 | + locals === nothing && C.Py_DecRef(lptr) |
| 53 | + pythrow() |
| 54 | +end |
| 55 | + |
1 | 56 | pyeval_filename(src) =
|
2 | 57 | isfile(string(src.file)) ? "$(src.file):$(src.line)" : "julia:$(src.file):$(src.line)"
|
3 | 58 |
|
@@ -77,118 +132,69 @@ pyeval_macro(filename, mode, codearg, args...) = begin
|
77 | 132 | end
|
78 | 133 | # make the code be a function body
|
79 | 134 | if mode == :execr
|
80 |
| - newcode = "def _jl_tmp_ans_func_($(join(intvars, ", "))):\n" * join(map(line->" "*line, split(newcode, "\n")), "\n") * "\n\nans = _jl_tmp_ans_func_($(join(intvars, ", ")))" |
| 135 | + newcode = "def _jl_tmp_ans_func_($(join(intvars, ", "))):\n" * join(map(line->" "*line, split(newcode, "\n")), "\n") * "\n\n_jl_tmp_ans_ = _jl_tmp_ans_func_($(join(intvars, ", ")))" |
81 | 136 | end
|
82 | 137 | # make the code object
|
83 | 138 | co = PyCode(newcode, filename, mode == :eval ? :eval : :exec)
|
| 139 | + # make the keys to interpolate |
| 140 | + extrakeys = Tuple(PyInternedString(string(k)) for (k,_) in kvs) |
| 141 | + extravals = :(($([esc(v) for (k,v) in kvs]...),)) |
| 142 | + args = (co, esc(:pyglobals), esc(locals), extrakeys, extravals) |
| 143 | + mkgetvar(jv, pv, t) = quote |
| 144 | + ro = C.PyObject_GetItem(lptr, $(PyInternedString(string(pv)))) |
| 145 | + isnull(ro) && (decref && C.Py_DecRef(lptr); pythrow()) |
| 146 | + err = C.PyObject_Convert(ro, $t) |
| 147 | + ism1(err) && (decref && C.Py_DecRef(lptr); pythrow()) |
| 148 | + $(Symbol(jv)) = takeresult($t) |
| 149 | + end |
84 | 150 | # go
|
85 |
| - freelocals = |
86 |
| - locals === nothing ? :(C.Py_DecRef(lptr)) : :(GC.@preserve locals nothing) |
87 |
| - ret = quote |
88 |
| - let |
89 |
| - # evaluate the inputs (so any errors are thrown before we have object references) |
90 |
| - $([:($(Symbol(:input, i)) = $(esc(v))) for (i, (k, v)) in enumerate(kvs)]...) |
91 |
| - # get the code pointer |
92 |
| - cptr = checknull(pyptr($co)) |
93 |
| - # get the globals pointer |
94 |
| - globals = $(esc(:pyglobals)) |
95 |
| - gptr = checknull(pyptr(globals)) |
96 |
| - # ensure globals includes builtins |
97 |
| - if globals isa PyDict && !globals.hasbuiltins |
98 |
| - if C.PyMapping_HasKeyString(gptr, "__builtins__") == 0 |
99 |
| - err = C.PyMapping_SetItemString( |
100 |
| - gptr, |
101 |
| - "__builtins__", |
102 |
| - C.PyEval_GetBuiltins(), |
103 |
| - ) |
104 |
| - ism1(err) && pythrow() |
| 151 | + if mode == :eval |
| 152 | + :(eval_impl($(esc(rettypearg)), $(args...))) |
| 153 | + elseif mode == :exec |
| 154 | + if length(outkvts) == 0 |
| 155 | + quote |
| 156 | + exec_impl($(args...),) do lptr::CPyPtr, decref::Bool |
| 157 | + decref && C.Py_DecRef(lptr) |
| 158 | + nothing |
105 | 159 | end
|
106 |
| - globals.hasbuiltins = true |
107 | 160 | end
|
108 |
| - # get locals (ALLOCATES lptr if locals===nothing) |
109 |
| - $( |
110 |
| - locals === nothing ? :(lptr = checknull(C.PyDict_New())) : |
111 |
| - :(locals = $(esc(locals)); lptr = checknull(pyptr(locals))) |
112 |
| - ) |
113 |
| - # insert extra locals |
114 |
| - $( |
115 |
| - [ |
116 |
| - :( |
117 |
| - let |
118 |
| - vo = C.PyObject_From($(Symbol(:input, i))) |
119 |
| - isnull(vo) && ($freelocals; pythrow()) |
120 |
| - err = C.PyObject_SetItem( |
121 |
| - lptr, |
122 |
| - $(PyInternedString(string(k))), |
123 |
| - vo, |
124 |
| - ) |
125 |
| - C.Py_DecRef(vo) |
126 |
| - ism1(err) && ($freelocals; pythrow()) |
127 |
| - end |
128 |
| - ) for (i, (k, v)) in enumerate(kvs) |
129 |
| - ]... |
130 |
| - ) |
131 |
| - # Call eval (ALLOCATES rptr) |
132 |
| - rptr = GC.@preserve globals C.PyEval_EvalCode(cptr, gptr, lptr) |
133 |
| - isnull(rptr) && ($freelocals; pythrow()) |
134 |
| - # extract values |
135 |
| - $( |
136 |
| - if mode == :eval |
137 |
| - quote |
138 |
| - $freelocals |
139 |
| - res = C.PyObject_Convert(rptr, $(esc(rettypearg))) |
140 |
| - C.Py_DecRef(rptr) |
141 |
| - ism1(res) && pythrow() |
142 |
| - C.takeresult($(esc(rettypearg))) |
143 |
| - end |
144 |
| - elseif mode in (:execa, :execr) |
145 |
| - quote |
146 |
| - C.Py_DecRef(rptr) |
147 |
| - xo = C.PyObject_GetItem(lptr, $(PyInternedString("ans"))) |
148 |
| - isnull(xo) && ($freelocals; pythrow()) |
149 |
| - res = C.PyObject_Convert(xo, $(esc(rettypearg))) |
150 |
| - C.Py_DecRef(xo) |
151 |
| - $freelocals |
152 |
| - ism1(res) && pythrow() |
153 |
| - C.takeresult($(esc(rettypearg))) |
154 |
| - end |
155 |
| - elseif mode == :exec |
156 |
| - quote |
157 |
| - C.Py_DecRef(rptr) |
158 |
| - $( |
159 |
| - ( |
160 |
| - quote |
161 |
| - $(Symbol(:output, i)) = |
162 |
| - let |
163 |
| - xo = C.PyObject_GetItem( |
164 |
| - lptr, |
165 |
| - $(PyInternedString(v)), |
166 |
| - ) |
167 |
| - isnull(xo) && ($freelocals; pythrow()) |
168 |
| - res = C.PyObject_Convert(xo, $t) |
169 |
| - C.Py_DecRef(xo) |
170 |
| - ism1(res) && ($freelocals; pythrow()) |
171 |
| - C.takeresult($t) |
172 |
| - end |
173 |
| - end for (i, (_, v, t)) in enumerate(outkvts) |
174 |
| - )... |
175 |
| - ) |
176 |
| - $freelocals |
177 |
| - ($((Symbol(:output, i) for i = 1:length(outkvts))...),) |
178 |
| - end |
179 |
| - else |
180 |
| - error() |
| 161 | + elseif length(outkvts) == 1 |
| 162 | + k, v, t = outkvts[1] |
| 163 | + quote |
| 164 | + $k = exec_impl($(args...),) do lptr::CPyPtr, decref::Bool |
| 165 | + $(mkgetvar("r", v, t)) |
| 166 | + decref && C.Py_DecRef(lptr) |
| 167 | + return r |
181 | 168 | end
|
182 |
| - ) |
| 169 | + end |
| 170 | + else |
| 171 | + quote |
| 172 | + ($([k for (k,_,_) in outkvts]...),) = exec_impl($(args...),) do lptr::CPyPtr, decref::Bool |
| 173 | + $([mkgetvar("r$i", v, t) for (i,(k,v,t)) in enumerate(outkvts)]...) |
| 174 | + decref && C.Py_DecRef(lptr) |
| 175 | + return ($([Symbol("r$i") for i in 1:length(outkvts)]...),) |
| 176 | + end |
| 177 | + end |
183 | 178 | end
|
184 |
| - end |
185 |
| - if mode == :exec |
186 |
| - ret = quote |
187 |
| - ($((k for (k, _, _) in outkvts)...),) = $ret |
188 |
| - nothing |
| 179 | + elseif mode == :execr |
| 180 | + quote |
| 181 | + exec_impl($(args...),) do lptr::CPyPtr, decref::Bool |
| 182 | + $(mkgetvar("r", "_jl_tmp_ans_", esc(rettypearg))) |
| 183 | + decref && C.Py_DecRef(lptr) |
| 184 | + return r |
| 185 | + end |
| 186 | + end |
| 187 | + elseif mode == :execa |
| 188 | + quote |
| 189 | + exec_impl($(args...),) do lptr, decref |
| 190 | + $(mkgetvar("r", "ans", esc(rettypearg))) |
| 191 | + decref && C.Py_DecRef(lptr) |
| 192 | + return r |
| 193 | + end |
189 | 194 | end
|
| 195 | + else |
| 196 | + @assert false |
190 | 197 | end
|
191 |
| - ret |
192 | 198 | end
|
193 | 199 |
|
194 | 200 | """
|
|
0 commit comments