Module: Jade::Codegen::Transforms::FoldShape

Extended by:
Helpers, FoldShape
Included in:
FoldShape
Defined in:
lib/jade/codegen/transforms/fold_shape.rb

Constant Summary collapse

ACC_NAME =
'__fold_acc__'

Constants included from Helpers

Helpers::NATIVE_RUBY_CLASSES

Instance Method Summary collapse

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