Module: Jade::Codegen::Helpers

Constant Summary collapse

NATIVE_RUBY_CLASSES =

Ruby classes that back primitive Jade types. Mirrors stdlib’s ‘native_type` declarations so user impls on primitives register under the right Ruby class. (Lifting this onto Symbol::Union itself is tracked in plans/lift-native-types-into-symbol-table.md.)

{
  'Basics.Int' => ['Integer'],
  'Basics.Float' => ['Float'],
  'Basics.Bool' => ['TrueClass', 'FalseClass'],
  'String.String' => ['String'],
  'Char.Char' => ['String'],
}.freeze

Instance Method Summary collapse

Instance Method Details

#data_define(fields) ⇒ Object



19
20
21
22
23
# File 'lib/jade/codegen/helpers.rb', line 19

def data_define(fields)
  return "Data.define" if fields.empty?

  "Data.define(#{fields.map { ":#{it}" }.join(', ')})"
end

#dict_constraints(fn_symbol, registry) ⇒ Object

Subset of fn_constraints that need a runtime dict param: those whose type is a bare Type::Var. Other constraints (e.g. Eq(Maybe(α)) where α is unbound but the outer constructor is concrete) are resolved at finalize via the impl table — no dict threaded for them.



66
67
68
# File 'lib/jade/codegen/helpers.rb', line 66

def dict_constraints(fn_symbol, registry)
  fn_constraints(fn_symbol, registry).select { |c| c.type.is_a?(Type::Var) }
end

#dict_synthetic_name(index) ⇒ Object



45
46
47
# File 'lib/jade/codegen/helpers.rb', line 45

def dict_synthetic_name(index)
  "__dict#{index}__"
end

#fn_constraints(fn_symbol, registry) ⇒ Object



53
54
55
56
57
58
59
60
# File 'lib/jade/codegen/helpers.rb', line 53

def fn_constraints(fn_symbol, registry)
  env = registry.get(fn_symbol.module_name).env

  env
    .bindings[fn_symbol.qualified_name]
    .constraints
    .map { env.substitution.apply(it) }
end

#fn_impl_synthetic_name(name) ⇒ Object



49
50
51
# File 'lib/jade/codegen/helpers.rb', line 49

def fn_impl_synthetic_name(name)
  "__#{name}__impl__"
end

#generate_many(nodes, registry, sep = ", ") ⇒ Object



6
7
8
9
10
11
12
# File 'lib/jade/codegen/helpers.rb', line 6

def generate_many(nodes, registry, sep = ", ")
  nodes.map do
    next yield(it) if block_given?

    generate_node(it, registry)
  end.join(sep)
end

#generate_node(node, registry) ⇒ Object



25
26
27
# File 'lib/jade/codegen/helpers.rb', line 25

def generate_node(node, registry)
  Codegen.generate(node, registry)
end

#impl_synthetic_name(interface, type_name, fn_name) ⇒ Object



40
41
42
43
# File 'lib/jade/codegen/helpers.rb', line 40

def impl_synthetic_name(interface, type_name, fn_name)
  sanitized = fn_name.gsub(/[^a-zA-Z0-9_]/) { |c| "x#{c.ord.to_s(16)}" }
  "__impl_#{interface}_#{type_name}_#{sanitized}__"
end

#param_synthetic_name(index) ⇒ Object



36
37
38
# File 'lib/jade/codegen/helpers.rb', line 36

def param_synthetic_name(index)
  "__p#{index}__"
end

#resolve_callee_symbol(callee, registry) ⇒ Object



29
30
31
32
33
34
# File 'lib/jade/codegen/helpers.rb', line 29

def resolve_callee_symbol(callee, registry)
  case callee.symbol
  in Symbol::ValueRef => ref then registry.lookup(ref)
  in symbol then symbol
  end
end

#ruby_classes_for_type(type_ref, registry) ⇒ Object

Returns the Ruby class names that values of ‘type_ref` may have at runtime. Strings here go straight into emitted Ruby. Returns [] for types that have no concrete runtime representation (interfaces).



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/jade/codegen/helpers.rb', line 85

def ruby_classes_for_type(type_ref, registry)
  qname = type_ref.qualified_name
  return NATIVE_RUBY_CLASSES[qname] if NATIVE_RUBY_CLASSES.key?(qname)

  case registry.lookup(type_ref)
  in Symbol::Union(variants:)
    variants.map { "::#{to_qualified(it.qualified_name)}" }

  in Symbol::Struct
    ["::#{to_qualified(qname)}"]

  in Symbol::Interface
    []
  end
end

#to_qualified(module_name) ⇒ Object



14
15
16
17
# File 'lib/jade/codegen/helpers.rb', line 14

def to_qualified(module_name)
  base = module_name.gsub('.', '::')
  Stdlib.stdlib_name?(module_name) ? "Jade::#{base}" : base
end