|
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