Skip to content

Commit c10a152

Browse files
committed
Move code to functions module
1 parent 9c354fb commit c10a152

File tree

5 files changed

+284
-195
lines changed

5 files changed

+284
-195
lines changed

wdl2cwl/expr.py

Lines changed: 40 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import WDL
77
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
99

1010

1111
def get_expr_ifthenelse(
@@ -140,204 +140,61 @@ def get_expr(wdl_expr: WDL.Expr.Base, ctx: ConversionContext) -> str:
140140
f"The expression '{wdl_expr}' is not handled yet."
141141
)
142142

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+
143165
def get_expr_apply(wdl_apply_expr: WDL.Expr.Apply, ctx: ConversionContext) -> str:
144166
"""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+
164170
function_name = wdl_apply_expr.function_name
165171
arguments = wdl_apply_expr.arguments
166172
if not arguments:
167173
raise WDLSourceLine(wdl_apply_expr, ConversionException).makeError(
168174
f"The '{wdl_apply_expr}' expression has no arguments."
169175
)
170176
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:
255179
left_operand, right_operand = arguments
256180
left_operand_expr = get_expr(left_operand, ctx)
257181
right_operand_expr = get_expr(right_operand, ctx)
258182
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}"
260184
)
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:
268186
only_arg = arguments[0]
269187
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),
276197
)
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}")'
341198
raise WDLSourceLine(wdl_apply_expr, ConversionException).makeError(
342199
f"Function name '{function_name}' not yet handled."
343200
)
@@ -429,7 +286,7 @@ def get_step_input_expr(
429286
id_name = wf_expr.expr.name
430287
referee = wf_expr.expr.referee
431288
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]
433290
ctx.scatter_names.append(scatter_name)
434291
return scatter_name, value_from
435292
return id_name, None

0 commit comments

Comments
 (0)