|
5 | 5 |
|
6 | 6 | import WDL |
7 | 7 | from wdl2cwl.errors import WDLSourceLine, ConversionException |
8 | | -from wdl2cwl.util import get_input, nice_quote, get_mem_in_bytes, ConversionContext |
| 8 | +from wdl2cwl.util import get_input, nice_quote, ConversionContext |
9 | 9 |
|
10 | 10 |
|
11 | 11 | def get_expr_ifthenelse( |
@@ -140,204 +140,61 @@ def get_expr(wdl_expr: WDL.Expr.Base, ctx: ConversionContext) -> str: |
140 | 140 | f"The expression '{wdl_expr}' is not handled yet." |
141 | 141 | ) |
142 | 142 |
|
| 143 | +_BINARY_OPS = { |
| 144 | + "_gt": ">", |
| 145 | + "_lor": "||", |
| 146 | + "_neq": "!==", |
| 147 | + "_lt": "<", |
| 148 | + "_mul": "*", |
| 149 | + "_eqeq": "===", |
| 150 | + "_div": "/", |
| 151 | + "_sub": "-", |
| 152 | +} |
| 153 | + |
| 154 | +_SINGLE_ARG_FN = { # implemented elsewhere, just return the argument |
| 155 | + "read_string", |
| 156 | + "read_float", |
| 157 | + "glob", |
| 158 | + "read_int", |
| 159 | + "read_boolean", |
| 160 | + "read_tsv", |
| 161 | + "read_lines", |
| 162 | +} |
| 163 | + |
| 164 | + |
143 | 165 | def get_expr_apply(wdl_apply_expr: WDL.Expr.Apply, ctx: ConversionContext) -> str: |
144 | 166 | """Translate WDL Apply Expressions.""" |
145 | | - binary_ops = { |
146 | | - "_gt": ">", |
147 | | - "_lor": "||", |
148 | | - "_neq": "!==", |
149 | | - "_lt": "<", |
150 | | - "_mul": "*", |
151 | | - "_eqeq": "===", |
152 | | - "_div": "/", |
153 | | - "_sub": "-", |
154 | | - } |
155 | | - single_arg_fn = { # implemented elsewhere, just return the argument |
156 | | - "read_string", |
157 | | - "read_float", |
158 | | - "glob", |
159 | | - "read_int", |
160 | | - "read_boolean", |
161 | | - "read_tsv", |
162 | | - "read_lines", |
163 | | - } |
| 167 | + # N.B: This import here avoids circular dependency error when loading the modules. |
| 168 | + from wdl2cwl import functions |
| 169 | + |
164 | 170 | function_name = wdl_apply_expr.function_name |
165 | 171 | arguments = wdl_apply_expr.arguments |
166 | 172 | if not arguments: |
167 | 173 | raise WDLSourceLine(wdl_apply_expr, ConversionException).makeError( |
168 | 174 | f"The '{wdl_apply_expr}' expression has no arguments." |
169 | 175 | ) |
170 | 176 | treat_as_optional = wdl_apply_expr.type.optional |
171 | | - if function_name == "_add": |
172 | | - add_left_operand = arguments[0] |
173 | | - add_right_operand = get_expr(arguments[1], ctx) |
174 | | - add_left_operand_value = get_expr(add_left_operand, ctx) |
175 | | - if getattr(add_left_operand, "function_name", None) == "basename": |
176 | | - referer = wdl_apply_expr.parent.name # type: ignore[attr-defined] |
177 | | - treat_as_optional = True if referer in ctx.non_static_values else False |
178 | | - return ( |
179 | | - f"{add_left_operand_value} + {add_right_operand}" |
180 | | - if not treat_as_optional |
181 | | - else f"{get_input(referer)} === null ? {add_left_operand_value} + {add_right_operand} : {get_input(referer)}" |
182 | | - ) |
183 | | - elif function_name == "basename": |
184 | | - if len(arguments) == 1: |
185 | | - only_operand = arguments[0] |
186 | | - is_file = isinstance(only_operand.type, WDL.Type.File) |
187 | | - if isinstance(only_operand, WDL.Expr.Get) and isinstance( |
188 | | - only_operand.expr, WDL.Expr.Ident |
189 | | - ): |
190 | | - only_operand_name = get_expr_name(only_operand.expr) |
191 | | - else: |
192 | | - only_operand_name = get_expr(only_operand, ctx) |
193 | | - return ( |
194 | | - f"{only_operand_name}.basename" |
195 | | - if is_file |
196 | | - else f"{only_operand_name}.split('/').reverse()[0]" |
197 | | - ) |
198 | | - else: |
199 | | - basename_target, suffix = arguments |
200 | | - is_file = isinstance(basename_target.type, WDL.Type.File) |
201 | | - if isinstance(basename_target, WDL.Expr.Get): |
202 | | - basename_target_name = get_expr_name(basename_target.expr) # type: ignore[arg-type] |
203 | | - elif isinstance(basename_target, WDL.Expr.Apply): |
204 | | - basename_target_name = get_expr(basename_target, ctx) |
205 | | - suffix_str = str(get_literal_value(suffix)) |
206 | | - regex_str = re.escape(suffix_str) |
207 | | - return ( |
208 | | - f"{basename_target_name}.basename.replace(/{regex_str}$/, '') " |
209 | | - if is_file |
210 | | - else f"{basename_target_name}.split('/').reverse()[0].replace(/{regex_str}$/, '')" |
211 | | - ) |
212 | | - elif function_name == "defined": |
213 | | - only_operand = arguments[0] |
214 | | - assert isinstance(only_operand, WDL.Expr.Get) and isinstance( |
215 | | - only_operand.expr, WDL.Expr.Ident |
216 | | - ) |
217 | | - return f"{get_expr_name(only_operand.expr)} !== null" |
218 | | - elif function_name == "_interpolation_add": |
219 | | - arg_value, arg_name = arguments |
220 | | - if isinstance(arg_name, WDL.Expr.String) and isinstance( |
221 | | - arg_value, (WDL.Expr.Apply, WDL.Expr.String) |
222 | | - ): |
223 | | - return f"{get_expr(arg_value, ctx)} + {get_expr(arg_name, ctx)}" |
224 | | - if isinstance(arg_name, (WDL.Expr.Placeholder, WDL.Expr.Get)): |
225 | | - just_arg_name = get_expr_name(arg_name.expr) # type: ignore[arg-type] |
226 | | - arg_name_with_file_check = get_expr_name_with_is_file_check( |
227 | | - arg_name.expr # type: ignore |
228 | | - ) |
229 | | - elif isinstance(arg_value, (WDL.Expr.Placeholder, WDL.Expr.Get)): |
230 | | - just_arg_name = get_expr_name(arg_value.expr) # type: ignore[arg-type] |
231 | | - arg_name_with_file_check = get_expr_name_with_is_file_check( |
232 | | - arg_value.expr # type: ignore |
233 | | - ) |
234 | | - arg_value = arg_name |
235 | | - with WDLSourceLine(arg_value, ConversionException): |
236 | | - arg_value_str = get_expr(arg_value, ctx) |
237 | | - return ( |
238 | | - f'{just_arg_name} === null ? "" : {arg_value_str} + {arg_name_with_file_check}' |
239 | | - if treat_as_optional |
240 | | - else f"{arg_value_str} + {arg_name_with_file_check}" |
241 | | - ) |
242 | | - elif function_name == "sub": |
243 | | - wdl_apply, arg_string, arg_sub = arguments |
244 | | - sub_expr = get_expr(wdl_apply, ctx) |
245 | | - arg_string_expr = get_expr(arg_string, ctx) |
246 | | - arg_sub_expr = get_expr(arg_sub, ctx) |
247 | | - return f"{sub_expr}.replace({arg_string_expr}, {arg_sub_expr}) " |
248 | | - |
249 | | - elif function_name == "_at": |
250 | | - iterable_object, index = arguments |
251 | | - iterable_object_expr = get_expr(iterable_object, ctx) |
252 | | - index_expr = get_expr(index, ctx) |
253 | | - return f"{iterable_object_expr}[{index_expr}]" |
254 | | - elif function_name in binary_ops: |
| 177 | + |
| 178 | + if function_name in _BINARY_OPS: |
255 | 179 | left_operand, right_operand = arguments |
256 | 180 | left_operand_expr = get_expr(left_operand, ctx) |
257 | 181 | right_operand_expr = get_expr(right_operand, ctx) |
258 | 182 | return ( |
259 | | - f"{left_operand_expr} {binary_ops[function_name]} {right_operand_expr}" |
| 183 | + f"{left_operand_expr} {_BINARY_OPS[function_name]} {right_operand_expr}" |
260 | 184 | ) |
261 | | - elif function_name == "length": |
262 | | - only_arg_expr = get_expr_get(arguments[0]) # type: ignore |
263 | | - return f"{only_arg_expr}.length" |
264 | | - elif function_name == "round": |
265 | | - only_arg_expr = get_expr(arguments[0], ctx) |
266 | | - return f"Math.round({only_arg_expr})" |
267 | | - elif function_name in single_arg_fn: |
| 185 | + elif function_name in _SINGLE_ARG_FN: |
268 | 186 | only_arg = arguments[0] |
269 | 187 | return get_expr(only_arg, ctx) |
270 | | - elif function_name == "select_first": |
271 | | - array_obj = cast(WDL.Expr.Array, arguments[0]) |
272 | | - array_items = [str(get_expr(item, ctx)) for item in array_obj.items] |
273 | | - items_str = ", ".join(array_items) |
274 | | - return ( |
275 | | - f"[{items_str}].find(function(element) {{ return element !== null }}) " |
| 188 | + elif hasattr(functions, function_name): |
| 189 | + # Call the function if we have it in our wdl2cwl.functions module |
| 190 | + kwargs = { |
| 191 | + "treat_as_optional": treat_as_optional, |
| 192 | + "wdl_apply_expr": wdl_apply_expr, |
| 193 | + } |
| 194 | + return cast( |
| 195 | + str, |
| 196 | + getattr(functions, function_name)(arguments, ctx, **kwargs), |
276 | 197 | ) |
277 | | - elif function_name == "select_all": |
278 | | - array_obj = cast(WDL.Expr.Array, arguments[0]) |
279 | | - array_items = [str(get_expr(item, ctx)) for item in array_obj.items] |
280 | | - items_str = ", ".join(array_items) |
281 | | - return f"[{items_str}].filter(function(element) {{ return element !== null }}) " |
282 | | - elif function_name == "ceil": |
283 | | - only_arg = get_expr(arguments[0], ctx) # type: ignore |
284 | | - return f"Math.ceil({only_arg}) " |
285 | | - elif function_name == "size": |
286 | | - if len(arguments) == 1: |
287 | | - left_operand = arguments[0] |
288 | | - unit_value = "1" |
289 | | - else: |
290 | | - left_operand, right_operand = arguments |
291 | | - right_value = str(get_literal_value(right_operand)) |
292 | | - unit_base, unit_exponent = get_mem_in_bytes(right_value) |
293 | | - unit_value = f"{unit_base}^{unit_exponent}" |
294 | | - if isinstance(left_operand, WDL.Expr.Array): |
295 | | - array_items = [get_expr(item, ctx) for item in left_operand.items] |
296 | | - left = ", ".join(array_items) |
297 | | - left_str = f"[{left}]" |
298 | | - else: |
299 | | - left_str = get_expr(left_operand, ctx) |
300 | | - return ( |
301 | | - "(function(size_of=0)" |
302 | | - + "{" |
303 | | - + f"{left_str}.forEach(function(element)" |
304 | | - + "{ if (element) {" |
305 | | - + "size_of += element.size" |
306 | | - + "}})}" |
307 | | - + f") / {unit_value}" |
308 | | - ) |
309 | | - elif function_name == "flatten": |
310 | | - flatten_array = arguments[0] |
311 | | - with WDLSourceLine(flatten_array, ConversionException): |
312 | | - items_str = get_expr(flatten_array, ctx) |
313 | | - result = ( |
314 | | - "(function () {var new_array = []; " |
315 | | - + items_str |
316 | | - + ".forEach(function(value, index, obj) " |
317 | | - "{value.forEach(function(sub_value, sub_index, sub_obj) " |
318 | | - "{new_array.push(sub_value);});}); return new_array;})()" |
319 | | - ) |
320 | | - return result |
321 | | - elif function_name == "sep": |
322 | | - sep, array = arguments |
323 | | - if isinstance(array, WDL.Expr.Get) and isinstance( |
324 | | - array.type, WDL.Type.Array |
325 | | - ): |
326 | | - item_type = array.type.item_type |
327 | | - else: |
328 | | - raise WDLSourceLine(array, ConversionException).makeError( |
329 | | - f"Unhandled sep array type: {type(array)}: {array}." |
330 | | - ) |
331 | | - sep_str = get_literal_value(sep) or "" |
332 | | - if isinstance(item_type, WDL.Type.File): |
333 | | - return ( |
334 | | - f"{get_expr(array, ctx)}.map(" |
335 | | - + 'function(el) {return el.path}).join("' |
336 | | - + sep_str |
337 | | - + '")' |
338 | | - ) |
339 | | - else: |
340 | | - return f'{get_expr(array, ctx)}.join("{sep_str}")' |
341 | 198 | raise WDLSourceLine(wdl_apply_expr, ConversionException).makeError( |
342 | 199 | f"Function name '{function_name}' not yet handled." |
343 | 200 | ) |
@@ -429,7 +286,7 @@ def get_step_input_expr( |
429 | 286 | id_name = wf_expr.expr.name |
430 | 287 | referee = wf_expr.expr.referee |
431 | 288 | if referee and isinstance(referee, WDL.Tree.Scatter): |
432 | | - scatter_name, value_from = get_step_input_expr(referee.expr, ctx) # type: ignore [arg-type] |
| 289 | + scatter_name, value_from = get_step_input_expr(referee.expr, ctx) # type: ignore[arg-type] |
433 | 290 | ctx.scatter_names.append(scatter_name) |
434 | 291 | return scatter_name, value_from |
435 | 292 | return id_name, None |
|
0 commit comments