Module: MilkTea::ImportedBindings::Generator::GeneratorMethodSource
- Included in:
- MilkTea::ImportedBindings::Generator
- Defined in:
- lib/milk_tea/bindings/imported_bindings/method_source.rb
Instance Method Summary collapse
- #index_method_source_declarations(source_ast) ⇒ Object
- #load_method_source(spec) ⇒ Object
- #load_method_sources(method_specs) ⇒ Object
- #method_source_import_specs(method_sources) ⇒ Object
- #method_source_key(spec) ⇒ Object
- #normalize_method_source_param_mode(mode) ⇒ Object
- #plan_method_source_function(declaration, source:) ⇒ Object
- #project_method_source_function_type_param(param, source:) ⇒ Object
- #project_method_source_param(param, source:) ⇒ Object
- #project_method_source_type(type, source:) ⇒ Object
- #project_method_source_type_argument(argument, source:) ⇒ Object
- #project_method_source_type_name(raw_name, source:) ⇒ Object
- #visible_from_method_source?(declaration, module_kind:) ⇒ Boolean
Instance Method Details
#index_method_source_declarations(source_ast) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 48 def index_method_source_declarations(source_ast) types = {} type_order = [] functions = {} function_order = [] source_ast.declarations.each do |declaration| case declaration when AST::TypeAliasDecl, AST::StructDecl, AST::UnionDecl, AST::EnumDecl, AST::FlagsDecl, AST::OpaqueDecl next unless visible_from_method_source?(declaration, module_kind: source_ast.module_kind) types[declaration.name] = declaration type_order << declaration.name when AST::ExternFunctionDecl, AST::ForeignFunctionDecl next unless visible_from_method_source?(declaration, module_kind: source_ast.module_kind) functions[declaration.name] = declaration function_order << declaration.name end end { types:, type_order:, functions:, function_order:, } end |
#load_method_source(spec) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 18 def load_method_source(spec) module_name = spec.fetch(:module_name) module_path = resolve_module_path(module_name) source_ast = ModuleLoader.new(module_roots: @module_roots).load_file(module_path) unless source_ast.module_name&.to_s == module_name raise Error, "expected #{module_path} to define module #{module_name}" end declarations = index_method_source_declarations(source_ast) MethodSource.new( module_name:, module_path:, module_kind: source_ast.module_kind, import_alias: spec.fetch(:module_import_alias), imports_by_alias: source_ast.imports.to_h { |import| [import.alias_name, import.path.parts.join(".")] }, public_type_names: declarations[:types].keys, functions: declarations[:functions], function_order: declarations[:function_order], import_specs: [{ module_name:, alias: spec.fetch(:module_import_alias) }], ) end |
#load_method_sources(method_specs) ⇒ Object
7 8 9 10 11 12 13 14 15 16 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 7 def load_method_sources(method_specs) method_specs.each_with_object({}) do |spec, sources| next unless spec[:module_name] key = method_source_key(spec) next if sources.key?(key) sources[key] = load_method_source(spec) end end |
#method_source_import_specs(method_sources) ⇒ Object
40 41 42 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 40 def method_source_import_specs(method_sources) method_sources.values.flat_map(&:import_specs) end |
#method_source_key(spec) ⇒ Object
44 45 46 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 44 def method_source_key(spec) [spec.fetch(:module_name), spec.fetch(:module_import_alias)] end |
#normalize_method_source_param_mode(mode) ⇒ Object
116 117 118 119 120 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 116 def normalize_method_source_param_mode(mode) return nil if mode == :plain || mode.nil? mode.to_s end |
#plan_method_source_function(declaration, source:) ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 83 def plan_method_source_function(declaration, source:) if declaration.respond_to?(:variadic) && declaration.variadic raise Error, "method generation for #{declaration.name} in #{source.module_path} cannot use variadic functions" end { raw_name: declaration.name, public_name: declaration.name, call_name: "#{source.import_alias}.#{declaration.name}", type_params: raw_type_param_names(declaration), params: declaration.params.map { |param| project_method_source_param(param, source:) }, return_type: project_method_source_type(declaration.return_type, source:), } end |
#project_method_source_function_type_param(param, source:) ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 140 def project_method_source_function_type_param(param, source:) case param when AST::Param "#{param.name}: #{project_method_source_type(param.type, source:)}" when AST::ForeignParam text = +"" text << "#{param.mode} " if param.mode text << "#{param.name}: #{project_method_source_type(param.type, source:)}" if param.boundary_type text << " as #{project_method_source_type(param.boundary_type, source:)}" end text else project_method_source_type(param, source:) end end |
#project_method_source_param(param, source:) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 98 def project_method_source_param(param, source:) case param when AST::ForeignParam { "name" => param.name, "type" => project_method_source_type(param.type, source:), "mode" => normalize_method_source_param_mode(param.mode), } when AST::Param { "name" => param.name, "type" => project_method_source_type(param.type, source:), } else raise Error, "unsupported method source parameter #{param.class.name} in #{source.module_path}" end end |
#project_method_source_type(type, source:) ⇒ Object
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 122 def project_method_source_type(type, source:) case type when AST::TypeRef text = project_method_source_type_name(type.name.to_s, source:) unless type.arguments.empty? rendered_arguments = type.arguments.map { |argument| project_method_source_type_argument(argument.value, source:) } text << "[#{rendered_arguments.join(', ')}]" end text << "?" if type.nullable text when AST::FunctionType params = type.params.map { |param| project_method_source_function_type_param(param, source:) }.join(', ') "fn(#{params}) -> #{project_method_source_type(type.return_type, source:)}" else raise Error, "unsupported method source type node #{type.class.name} in #{source.module_path}" end end |
#project_method_source_type_argument(argument, source:) ⇒ Object
157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 157 def project_method_source_type_argument(argument, source:) case argument when AST::TypeRef, AST::FunctionType project_method_source_type(argument, source:) when AST::IntegerLiteral argument.lexeme when AST::Identifier argument.name else raise Error, "unsupported method source type argument #{argument.class.name} in #{source.module_path}" end end |
#project_method_source_type_name(raw_name, source:) ⇒ Object
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 170 def project_method_source_type_name(raw_name, source:) parts = raw_name.split(".") if parts.length > 1 import_alias = parts.first imported_name = parts[1..].join(".") imported_module_name = source.imports_by_alias[import_alias] return rendered_type_name(imported_name) if imported_module_name == @raw_module_name return imported_name if imported_module_name == @module_name return raw_name if imported_module_name end return "#{source.import_alias}.#{raw_name}" if source.public_type_names.include?(raw_name) rendered_type_name(raw_name) end |
#visible_from_method_source?(declaration, module_kind:) ⇒ Boolean
77 78 79 80 81 |
# File 'lib/milk_tea/bindings/imported_bindings/method_source.rb', line 77 def visible_from_method_source?(declaration, module_kind:) return true if module_kind == :raw_module declaration.respond_to?(:visibility) && declaration.visibility == :public end |