Module: Jade::Codegen::Transforms::FoldShape
- Included in:
- FoldShape
- Defined in:
- lib/jade/codegen/transforms/fold_shape.rb
Constant Summary collapse
- ACC_NAME =
'__fold_acc__'
Constants included from Helpers
Instance Method Summary collapse
-
#generate_body(shape, registry) ⇒ Object
Emits ‘xs.reverse.reduce(BASE) { |acc, head| COMBINE’ }‘.
-
#shape_for(body, self_sym, param_names, registry) ⇒ Object
The right-fold shape:.
Methods included from Helpers
data_define, dict_constraints, dict_synthetic_name, fn_constraints, fn_impl_synthetic_name, generate_many, generate_node, impl_synthetic_name, param_synthetic_name, resolve_callee_symbol, ruby_classes_for_type, to_qualified
Instance Method Details
#generate_body(shape, registry) ⇒ Object
Emits ‘xs.reverse.reduce(BASE) { |acc, head| COMBINE’ }‘. The `reverse` gives right-associative combine order regardless of the combiner’s algebraic properties. Task effects are unaffected by build order — only the final Task chain shape determines run-time behavior.
64 65 66 67 68 69 70 71 72 73 |
# File 'lib/jade/codegen/transforms/fold_shape.rb', line 64 def generate_body(shape, registry) shape => { list_arg:, base:, head_name:, combine:, self_call: } base_code = generate_node(base, registry) combine_code = substitute(combine, self_call) .then { generate_node(it, registry) } "#{list_arg}.reverse.reduce(#{base_code}) " \ "{ |#{ACC_NAME}, #{head_name}| #{combine_code} }" end |
#shape_for(body, self_sym, param_names, registry) ⇒ Object
The right-fold shape:
def f(xs) ->
case xs
of [] -> BASE (no self-call)
of [h | rest] -> COMBINE (exactly one f(rest), strict)
Returns a shape hash, or nil if the body doesn’t match.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/jade/codegen/transforms/fold_shape.rb', line 18 def shape_for(body, self_sym, param_names, registry) return nil unless param_names.size == 1 sig = [self_sym, 1] expr = unwrap_body(body) return nil unless expr.is_a?(AST::CaseOf) return nil unless expr.branches.size == 2 list_arg = param_names.first return nil unless subject_is_arg?(expr.expression, list_arg) empty_branch = expr.branches.find { empty_list_pattern?(it.pattern) } cons_branch = expr.branches.find { cons_pattern?(it.pattern) } return nil unless empty_branch && cons_branch return nil if SelfCall.contains_self_call?( empty_branch.body, sig, registry ) head_name = head_binding_name(cons_branch.pattern) rest_name = rest_binding_name(cons_branch.pattern) return nil unless head_name && rest_name calls = strict_self_calls(cons_branch.body, sig, registry) return nil unless calls&.size == 1 call = calls.first return nil unless call.args.size == 1 arg = call.args.first return nil unless arg in AST::VariableReference(name: ^rest_name) return nil unless rest_used_only?(cons_branch.body, rest_name, call) { list_arg: list_arg, base: empty_branch.body, head_name: head_name, combine: cons_branch.body, self_call: call, } end |