jade-lang 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +23 -0
- data/LICENSE +21 -0
- data/README.md +386 -0
- data/exe/jade +6 -0
- data/lib/jade/ast/node.rb +44 -0
- data/lib/jade/ast/nodes.rb +35 -0
- data/lib/jade/ast/pretty_printer.rb +50 -0
- data/lib/jade/ast.rb +723 -0
- data/lib/jade/calendar/runtime.rb +15 -0
- data/lib/jade/cli/fmt.rb +96 -0
- data/lib/jade/cli/lsp.rb +13 -0
- data/lib/jade/cli/q.rb +113 -0
- data/lib/jade/cli.rb +43 -0
- data/lib/jade/clock/runtime.rb +13 -0
- data/lib/jade/codegen/boundary/cache.rb +94 -0
- data/lib/jade/codegen/boundary/specialized/list.rb +65 -0
- data/lib/jade/codegen/boundary/specialized/maybe.rb +40 -0
- data/lib/jade/codegen/boundary/specialized/record.rb +165 -0
- data/lib/jade/codegen/boundary/specialized/scalar.rb +67 -0
- data/lib/jade/codegen/boundary/specialized.rb +106 -0
- data/lib/jade/codegen/boundary.rb +189 -0
- data/lib/jade/codegen/constructor_reference.rb +18 -0
- data/lib/jade/codegen/context.rb +96 -0
- data/lib/jade/codegen/emitter.rb +81 -0
- data/lib/jade/codegen/function_call.rb +367 -0
- data/lib/jade/codegen/function_declaration.rb +199 -0
- data/lib/jade/codegen/helpers.rb +103 -0
- data/lib/jade/codegen/implementation.rb +178 -0
- data/lib/jade/codegen/inline.rb +89 -0
- data/lib/jade/codegen/inlines.rb +326 -0
- data/lib/jade/codegen/method_names.rb +54 -0
- data/lib/jade/codegen/pattern/constructor.rb +57 -0
- data/lib/jade/codegen/port_decoder.rb +77 -0
- data/lib/jade/codegen/pretty.rb +53 -0
- data/lib/jade/codegen/transforms/fold_shape.rb +222 -0
- data/lib/jade/codegen/transforms/self_call.rb +80 -0
- data/lib/jade/codegen/transforms/tail_call.rb +120 -0
- data/lib/jade/codegen/variant_declaration.rb +41 -0
- data/lib/jade/codegen.rb +400 -0
- data/lib/jade/compiler.rb +69 -0
- data/lib/jade/decode.rb +320 -0
- data/lib/jade/diagnostics/renderer.rb +121 -0
- data/lib/jade/diagnostics.rb +77 -0
- data/lib/jade/did_you_mean.rb +16 -0
- data/lib/jade/entry.rb +177 -0
- data/lib/jade/error.rb +72 -0
- data/lib/jade/formatter/accesses.rb +37 -0
- data/lib/jade/formatter/bindings.rb +29 -0
- data/lib/jade/formatter/body.rb +50 -0
- data/lib/jade/formatter/calls.rb +51 -0
- data/lib/jade/formatter/case_of.rb +31 -0
- data/lib/jade/formatter/case_of_branch.rb +59 -0
- data/lib/jade/formatter/collections.rb +78 -0
- data/lib/jade/formatter/declarations.rb +178 -0
- data/lib/jade/formatter/exposing.rb +48 -0
- data/lib/jade/formatter/function_declaration.rb +72 -0
- data/lib/jade/formatter/helper.rb +122 -0
- data/lib/jade/formatter/if_then_else.rb +64 -0
- data/lib/jade/formatter/infix_application.rb +69 -0
- data/lib/jade/formatter/lambda.rb +50 -0
- data/lib/jade/formatter/leaves.rb +111 -0
- data/lib/jade/formatter/module_node.rb +26 -0
- data/lib/jade/formatter/pattern.rb +61 -0
- data/lib/jade/formatter/type.rb +67 -0
- data/lib/jade/formatter.rb +38 -0
- data/lib/jade/frontend/comment_attacher.rb +121 -0
- data/lib/jade/frontend/desugaring/placeholder.rb +39 -0
- data/lib/jade/frontend/desugaring/resolved.rb +63 -0
- data/lib/jade/frontend/desugaring.rb +217 -0
- data/lib/jade/frontend/fixity_fixer.rb +209 -0
- data/lib/jade/frontend/forward_declaration/body.rb +30 -0
- data/lib/jade/frontend/forward_declaration/error/bad_import.rb +19 -0
- data/lib/jade/frontend/forward_declaration/error/exposed_type_not_found.rb +18 -0
- data/lib/jade/frontend/forward_declaration/error/exposed_value_not_found.rb +18 -0
- data/lib/jade/frontend/forward_declaration/error/module_not_found.rb +18 -0
- data/lib/jade/frontend/forward_declaration/error/private_type_expansion.rb +19 -0
- data/lib/jade/frontend/forward_declaration/error/tuple_arity_overflow.rb +25 -0
- data/lib/jade/frontend/forward_declaration/error/type_not_found.rb +29 -0
- data/lib/jade/frontend/forward_declaration/error/type_not_lowerable.rb +16 -0
- data/lib/jade/frontend/forward_declaration/error/unknown_extends_interface.rb +18 -0
- data/lib/jade/frontend/forward_declaration/error.rb +11 -0
- data/lib/jade/frontend/forward_declaration/function_declaration.rb +32 -0
- data/lib/jade/frontend/forward_declaration/helper.rb +91 -0
- data/lib/jade/frontend/forward_declaration/implementation.rb +63 -0
- data/lib/jade/frontend/forward_declaration/implementation_function.rb +39 -0
- data/lib/jade/frontend/forward_declaration/import_declaration.rb +115 -0
- data/lib/jade/frontend/forward_declaration/interface_declaration.rb +66 -0
- data/lib/jade/frontend/forward_declaration/interop_import_declaration.rb +99 -0
- data/lib/jade/frontend/forward_declaration/module.rb +98 -0
- data/lib/jade/frontend/forward_declaration/struct_declaration.rb +42 -0
- data/lib/jade/frontend/forward_declaration/type_declaration.rb +42 -0
- data/lib/jade/frontend/forward_declaration.rb +71 -0
- data/lib/jade/frontend/pattern_analysis/exhaustiveness.rb +65 -0
- data/lib/jade/frontend/pattern_analysis/matrix.rb +235 -0
- data/lib/jade/frontend/pattern_analysis.rb +40 -0
- data/lib/jade/frontend/semantic_analysis/assign.rb +20 -0
- data/lib/jade/frontend/semantic_analysis/body.rb +33 -0
- data/lib/jade/frontend/semantic_analysis/case_of.rb +19 -0
- data/lib/jade/frontend/semantic_analysis/case_of_branch.rb +20 -0
- data/lib/jade/frontend/semantic_analysis/char_literal.rb +14 -0
- data/lib/jade/frontend/semantic_analysis/constructor_reference.rb +64 -0
- data/lib/jade/frontend/semantic_analysis/error/circular_extends.rb +19 -0
- data/lib/jade/frontend/semantic_analysis/error/constant_not_callable.rb +24 -0
- data/lib/jade/frontend/semantic_analysis/error/constructor_not_found.rb +34 -0
- data/lib/jade/frontend/semantic_analysis/error/constructor_pattern_arity_mismatch.rb +24 -0
- data/lib/jade/frontend/semantic_analysis/error/duplicate_field.rb +18 -0
- data/lib/jade/frontend/semantic_analysis/error/duplicate_function_declaration.rb +25 -0
- data/lib/jade/frontend/semantic_analysis/error/duplicate_record_field.rb +19 -0
- data/lib/jade/frontend/semantic_analysis/error/invalid_list_rest_pattern.rb +21 -0
- data/lib/jade/frontend/semantic_analysis/error/kwargs_on_non_constructor.rb +17 -0
- data/lib/jade/frontend/semantic_analysis/error/missing_exposing_clause.rb +17 -0
- data/lib/jade/frontend/semantic_analysis/error/missing_extends_implementation.rb +21 -0
- data/lib/jade/frontend/semantic_analysis/error/missing_field.rb +20 -0
- data/lib/jade/frontend/semantic_analysis/error/missing_implementation_function.rb +19 -0
- data/lib/jade/frontend/semantic_analysis/error/module_not_found.rb +22 -0
- data/lib/jade/frontend/semantic_analysis/error/nested_task_port.rb +19 -0
- data/lib/jade/frontend/semantic_analysis/error/non_task_port.rb +22 -0
- data/lib/jade/frontend/semantic_analysis/error/orphan_implementation.rb +20 -0
- data/lib/jade/frontend/semantic_analysis/error/predicate_must_return_bool.rb +22 -0
- data/lib/jade/frontend/semantic_analysis/error/predicate_name_not_allowed.rb +25 -0
- data/lib/jade/frontend/semantic_analysis/error/shadowing_error.rb +22 -0
- data/lib/jade/frontend/semantic_analysis/error/type_args_mismatch.rb +25 -0
- data/lib/jade/frontend/semantic_analysis/error/type_param_required.rb +19 -0
- data/lib/jade/frontend/semantic_analysis/error/unbound_type_variable.rb +22 -0
- data/lib/jade/frontend/semantic_analysis/error/undefined_variable.rb +29 -0
- data/lib/jade/frontend/semantic_analysis/error/unknown_field.rb +20 -0
- data/lib/jade/frontend/semantic_analysis/error/unknown_implementation_function.rb +19 -0
- data/lib/jade/frontend/semantic_analysis/error/unused_interface_type_param.rb +24 -0
- data/lib/jade/frontend/semantic_analysis/error/value_not_exposed.rb +23 -0
- data/lib/jade/frontend/semantic_analysis/error/variable_not_found.rb +25 -0
- data/lib/jade/frontend/semantic_analysis/error.rb +40 -0
- data/lib/jade/frontend/semantic_analysis/function_call.rb +60 -0
- data/lib/jade/frontend/semantic_analysis/function_declaration.rb +58 -0
- data/lib/jade/frontend/semantic_analysis/grouping.rb +17 -0
- data/lib/jade/frontend/semantic_analysis/helper.rb +152 -0
- data/lib/jade/frontend/semantic_analysis/if_then_else.rb +20 -0
- data/lib/jade/frontend/semantic_analysis/implementation.rb +143 -0
- data/lib/jade/frontend/semantic_analysis/implementation_function.rb +16 -0
- data/lib/jade/frontend/semantic_analysis/import_declaration.rb +14 -0
- data/lib/jade/frontend/semantic_analysis/interface_declaration.rb +45 -0
- data/lib/jade/frontend/semantic_analysis/interop_import_declaration.rb +69 -0
- data/lib/jade/frontend/semantic_analysis/keyed_call/validation.rb +109 -0
- data/lib/jade/frontend/semantic_analysis/keyed_call.rb +88 -0
- data/lib/jade/frontend/semantic_analysis/lambda.rb +23 -0
- data/lib/jade/frontend/semantic_analysis/list.rb +17 -0
- data/lib/jade/frontend/semantic_analysis/literal.rb +23 -0
- data/lib/jade/frontend/semantic_analysis/member_access.rb +87 -0
- data/lib/jade/frontend/semantic_analysis/module_node.rb +27 -0
- data/lib/jade/frontend/semantic_analysis/pattern_binding.rb +27 -0
- data/lib/jade/frontend/semantic_analysis/pattern_constructor.rb +47 -0
- data/lib/jade/frontend/semantic_analysis/pattern_list.rb +33 -0
- data/lib/jade/frontend/semantic_analysis/pattern_literal.rb +17 -0
- data/lib/jade/frontend/semantic_analysis/pattern_record.rb +25 -0
- data/lib/jade/frontend/semantic_analysis/pattern_wildcard.rb +14 -0
- data/lib/jade/frontend/semantic_analysis/qualified_access.rb +14 -0
- data/lib/jade/frontend/semantic_analysis/record_access.rb +14 -0
- data/lib/jade/frontend/semantic_analysis/record_field.rb +17 -0
- data/lib/jade/frontend/semantic_analysis/record_literal.rb +21 -0
- data/lib/jade/frontend/semantic_analysis/record_update.rb +21 -0
- data/lib/jade/frontend/semantic_analysis/struct_declaration.rb +44 -0
- data/lib/jade/frontend/semantic_analysis/tuple.rb +17 -0
- data/lib/jade/frontend/semantic_analysis/type_declaration.rb +69 -0
- data/lib/jade/frontend/semantic_analysis/variable_reference.rb +27 -0
- data/lib/jade/frontend/semantic_analysis/variant_declaration.rb +18 -0
- data/lib/jade/frontend/semantic_analysis.rb +161 -0
- data/lib/jade/frontend/type_checking/canonicalize.rb +97 -0
- data/lib/jade/frontend/type_checking/constraints/deriving/decodable.rb +144 -0
- data/lib/jade/frontend/type_checking/constraints/deriving/encodable.rb +144 -0
- data/lib/jade/frontend/type_checking/constraints/deriving/eq.rb +265 -0
- data/lib/jade/frontend/type_checking/constraints/deriving/helpers.rb +59 -0
- data/lib/jade/frontend/type_checking/constraints/deriving.rb +28 -0
- data/lib/jade/frontend/type_checking/constraints.rb +101 -0
- data/lib/jade/frontend/type_checking/definition.rb +71 -0
- data/lib/jade/frontend/type_checking/env.rb +79 -0
- data/lib/jade/frontend/type_checking/error/case_of_branches_type_mismatch.rb +19 -0
- data/lib/jade/frontend/type_checking/error/derivation_failed.rb +21 -0
- data/lib/jade/frontend/type_checking/error/function_body_type_mismatch.rb +23 -0
- data/lib/jade/frontend/type_checking/error/function_call_type_mismatch.rb +37 -0
- data/lib/jade/frontend/type_checking/error/if_branch_type_mismatch.rb +19 -0
- data/lib/jade/frontend/type_checking/error/if_branches_type_mismatch.rb +18 -0
- data/lib/jade/frontend/type_checking/error/if_condition_type_mismatch.rb +17 -0
- data/lib/jade/frontend/type_checking/error/implementation_type_mismatch.rb +20 -0
- data/lib/jade/frontend/type_checking/error/list_item_type_mismatch.rb +19 -0
- data/lib/jade/frontend/type_checking/error/missing_implementation.rb +20 -0
- data/lib/jade/frontend/type_checking/error/missing_patterns.rb +26 -0
- data/lib/jade/frontend/type_checking/error/pattern_type_mismatch.rb +13 -0
- data/lib/jade/frontend/type_checking/error/port_not_decodable.rb +38 -0
- data/lib/jade/frontend/type_checking/error/record_access_type_mismatch.rb +14 -0
- data/lib/jade/frontend/type_checking/error/type_mismatch.rb +23 -0
- data/lib/jade/frontend/type_checking/error/unresolved_constraint.rb +20 -0
- data/lib/jade/frontend/type_checking/error.rb +18 -0
- data/lib/jade/frontend/type_checking/expected.rb +23 -0
- data/lib/jade/frontend/type_checking/generalization.rb +17 -0
- data/lib/jade/frontend/type_checking/generalizer.rb +38 -0
- data/lib/jade/frontend/type_checking/inference/assign.rb +58 -0
- data/lib/jade/frontend/type_checking/inference/body.rb +45 -0
- data/lib/jade/frontend/type_checking/inference/case_of.rb +102 -0
- data/lib/jade/frontend/type_checking/inference/constructor_reference.rb +21 -0
- data/lib/jade/frontend/type_checking/inference/function_call.rb +132 -0
- data/lib/jade/frontend/type_checking/inference/function_declaration.rb +70 -0
- data/lib/jade/frontend/type_checking/inference/grouping.rb +18 -0
- data/lib/jade/frontend/type_checking/inference/helpers.rb +34 -0
- data/lib/jade/frontend/type_checking/inference/if_then_else.rb +46 -0
- data/lib/jade/frontend/type_checking/inference/implementation.rb +150 -0
- data/lib/jade/frontend/type_checking/inference/import_declaration.rb +19 -0
- data/lib/jade/frontend/type_checking/inference/interface_declaration.rb +18 -0
- data/lib/jade/frontend/type_checking/inference/interop_import_declaration.rb +18 -0
- data/lib/jade/frontend/type_checking/inference/lambda.rb +87 -0
- data/lib/jade/frontend/type_checking/inference/list.rb +52 -0
- data/lib/jade/frontend/type_checking/inference/literal.rb +24 -0
- data/lib/jade/frontend/type_checking/inference/module.rb +18 -0
- data/lib/jade/frontend/type_checking/inference/pattern.rb +135 -0
- data/lib/jade/frontend/type_checking/inference/qualified_access.rb +23 -0
- data/lib/jade/frontend/type_checking/inference/record_access.rb +35 -0
- data/lib/jade/frontend/type_checking/inference/record_field.rb +19 -0
- data/lib/jade/frontend/type_checking/inference/record_literal.rb +24 -0
- data/lib/jade/frontend/type_checking/inference/record_update.rb +37 -0
- data/lib/jade/frontend/type_checking/inference/struct_declaration.rb +18 -0
- data/lib/jade/frontend/type_checking/inference/type_declaration.rb +18 -0
- data/lib/jade/frontend/type_checking/inference/variable_reference.rb +27 -0
- data/lib/jade/frontend/type_checking/inference.rb +27 -0
- data/lib/jade/frontend/type_checking/instantiation.rb +24 -0
- data/lib/jade/frontend/type_checking/loader.rb +80 -0
- data/lib/jade/frontend/type_checking/placeholder.rb +12 -0
- data/lib/jade/frontend/type_checking/port_resolution.rb +123 -0
- data/lib/jade/frontend/type_checking/result.rb +41 -0
- data/lib/jade/frontend/type_checking/scheme.rb +20 -0
- data/lib/jade/frontend/type_checking/state.rb +52 -0
- data/lib/jade/frontend/type_checking/substitution.rb +93 -0
- data/lib/jade/frontend/type_checking/unification.rb +282 -0
- data/lib/jade/frontend/type_checking/var_gen.rb +33 -0
- data/lib/jade/frontend/type_checking.rb +129 -0
- data/lib/jade/frontend/unused_analysis.rb +41 -0
- data/lib/jade/frontend/usage_analysis/reference_index.rb +53 -0
- data/lib/jade/frontend/usage_analysis.rb +195 -0
- data/lib/jade/frontend.rb +101 -0
- data/lib/jade/interop/boundary.rb +68 -0
- data/lib/jade/interop/error.rb +84 -0
- data/lib/jade/interop/lowering/error.rb +32 -0
- data/lib/jade/interop/lowering.rb +53 -0
- data/lib/jade/interop/runtime.rb +24 -0
- data/lib/jade/interop.rb +1 -0
- data/lib/jade/lexer.rb +189 -0
- data/lib/jade/lsp/converters.rb +542 -0
- data/lib/jade/lsp/handlers.rb +340 -0
- data/lib/jade/lsp/server.rb +63 -0
- data/lib/jade/lsp/snippets.rb +100 -0
- data/lib/jade/lsp/state.rb +25 -0
- data/lib/jade/lsp.rb +16 -0
- data/lib/jade/module_loader/cache.rb +56 -0
- data/lib/jade/module_loader/dependency_graph.rb +23 -0
- data/lib/jade/module_loader/dependency_resolver.rb +48 -0
- data/lib/jade/module_loader/normalize.rb +34 -0
- data/lib/jade/module_loader/topological_sort.rb +41 -0
- data/lib/jade/module_loader.rb +127 -0
- data/lib/jade/parsing/combinators.rb +291 -0
- data/lib/jade/parsing/error.rb +154 -0
- data/lib/jade/parsing/token.rb +12 -0
- data/lib/jade/parsing/type.rb +92 -0
- data/lib/jade/parsing.rb +674 -0
- data/lib/jade/port.rb +1 -0
- data/lib/jade/registry.rb +79 -0
- data/lib/jade/result.rb +121 -0
- data/lib/jade/runtime.rb +127 -0
- data/lib/jade/source.rb +62 -0
- data/lib/jade/stdlib/basics.rb +214 -0
- data/lib/jade/stdlib/bytes.rb +70 -0
- data/lib/jade/stdlib/calendar.rb +405 -0
- data/lib/jade/stdlib/char.rb +27 -0
- data/lib/jade/stdlib/clock.rb +342 -0
- data/lib/jade/stdlib/compiled.rb +48 -0
- data/lib/jade/stdlib/decode/params.rb +154 -0
- data/lib/jade/stdlib/decode.rb +315 -0
- data/lib/jade/stdlib/dict.rb +134 -0
- data/lib/jade/stdlib/encode.rb +143 -0
- data/lib/jade/stdlib/intrinsics.rb +280 -0
- data/lib/jade/stdlib/list.rb +214 -0
- data/lib/jade/stdlib/maybe.rb +73 -0
- data/lib/jade/stdlib/result.rb +131 -0
- data/lib/jade/stdlib/set.rb +123 -0
- data/lib/jade/stdlib/string.rb +65 -0
- data/lib/jade/stdlib/task.rb +55 -0
- data/lib/jade/stdlib/tuple.rb +21 -0
- data/lib/jade/stdlib.rb +112 -0
- data/lib/jade/symbol/anonymous_record.rb +7 -0
- data/lib/jade/symbol/base.rb +15 -0
- data/lib/jade/symbol/constructor.rb +11 -0
- data/lib/jade/symbol/derived_function.rb +5 -0
- data/lib/jade/symbol/function.rb +15 -0
- data/lib/jade/symbol/function_type.rb +7 -0
- data/lib/jade/symbol/implementation.rb +17 -0
- data/lib/jade/symbol/implementation_template.rb +13 -0
- data/lib/jade/symbol/interface.rb +11 -0
- data/lib/jade/symbol/interface_function.rb +18 -0
- data/lib/jade/symbol/interop_function.rb +22 -0
- data/lib/jade/symbol/lambda.rb +7 -0
- data/lib/jade/symbol/parser.rb +79 -0
- data/lib/jade/symbol/partial_application.rb +7 -0
- data/lib/jade/symbol/record_type.rb +8 -0
- data/lib/jade/symbol/stdlib_function.rb +15 -0
- data/lib/jade/symbol/stdlib_implementation.rb +7 -0
- data/lib/jade/symbol/struct.rb +15 -0
- data/lib/jade/symbol/type_application.rb +8 -0
- data/lib/jade/symbol/type_ref.rb +11 -0
- data/lib/jade/symbol/union.rb +15 -0
- data/lib/jade/symbol/value_ref.rb +15 -0
- data/lib/jade/symbol/variable.rb +7 -0
- data/lib/jade/symbol/variant.rb +11 -0
- data/lib/jade/symbol.rb +162 -0
- data/lib/jade/task.rb +103 -0
- data/lib/jade/tasks/rspec.rb +266 -0
- data/lib/jade/tasks.rb +70 -0
- data/lib/jade/type/anonymous_record.rb +33 -0
- data/lib/jade/type/application.rb +21 -0
- data/lib/jade/type/base.rb +9 -0
- data/lib/jade/type/constraint.rb +17 -0
- data/lib/jade/type/constructor.rb +19 -0
- data/lib/jade/type/function.rb +18 -0
- data/lib/jade/type/partial_application.rb +17 -0
- data/lib/jade/type/unit.rb +15 -0
- data/lib/jade/type/var.rb +21 -0
- data/lib/jade/type.rb +259 -0
- data/lib/jade/version.rb +3 -0
- data/lib/jade.rb +55 -0
- metadata +387 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Frontend
|
|
3
|
+
module SemanticAnalysis
|
|
4
|
+
module RecordUpdate
|
|
5
|
+
extend self
|
|
6
|
+
extend Helper
|
|
7
|
+
|
|
8
|
+
def analyze(node, registry, scope, entry)
|
|
9
|
+
node => AST::RecordUpdate(base:, fields:)
|
|
10
|
+
|
|
11
|
+
Result
|
|
12
|
+
.combine(node, scope:,
|
|
13
|
+
base: analyze_node(base, registry, scope, entry),
|
|
14
|
+
fields: analyze_in_parallel(fields, registry, scope, entry),
|
|
15
|
+
)
|
|
16
|
+
.add_errors(analyze_duplicate_fields(fields, entry))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Frontend
|
|
3
|
+
module SemanticAnalysis
|
|
4
|
+
module StructDeclaration
|
|
5
|
+
extend self
|
|
6
|
+
extend Helper
|
|
7
|
+
|
|
8
|
+
def analyze(node, registry, scope, entry)
|
|
9
|
+
node => AST::StructDeclaration(name:)
|
|
10
|
+
|
|
11
|
+
symbol_ref = entry.lookup_type(name).to_ref
|
|
12
|
+
|
|
13
|
+
Result
|
|
14
|
+
.init(node.with(symbol: symbol_ref), scope)
|
|
15
|
+
.add_errors(validate_no_unbound_vars(symbol_ref, registry, entry))
|
|
16
|
+
.add_errors(validate_type_symbol(symbol_ref, registry, entry))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def validate_no_unbound_vars(symbol, registry, entry)
|
|
22
|
+
actual_symbol = registry.lookup(symbol)
|
|
23
|
+
|
|
24
|
+
missing_vars = collect_vars(actual_symbol.record_type, registry)
|
|
25
|
+
.group_by(&:name)
|
|
26
|
+
.reject { |(k, _)| actual_symbol.type_params.map(&:name).include? k }
|
|
27
|
+
.values
|
|
28
|
+
.flatten
|
|
29
|
+
|
|
30
|
+
return [] if missing_vars.empty?
|
|
31
|
+
|
|
32
|
+
[
|
|
33
|
+
Error::UnboundTypeVariable.new(
|
|
34
|
+
entry.name,
|
|
35
|
+
missing_vars.size == 1 ? missing_vars.first.decl_span : actual_symbol.decl_span,
|
|
36
|
+
type_name: symbol.name,
|
|
37
|
+
variables: missing_vars.map(&:name),
|
|
38
|
+
)
|
|
39
|
+
]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Frontend
|
|
3
|
+
module SemanticAnalysis
|
|
4
|
+
module Tuple
|
|
5
|
+
extend self
|
|
6
|
+
extend Helper
|
|
7
|
+
|
|
8
|
+
def analyze(node, registry, scope, entry)
|
|
9
|
+
node => AST::Tuple(items:)
|
|
10
|
+
|
|
11
|
+
analyze_in_sequence(items, registry, scope, entry)
|
|
12
|
+
.with(scope:)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Frontend
|
|
3
|
+
module SemanticAnalysis
|
|
4
|
+
module TypeDeclaration
|
|
5
|
+
extend self
|
|
6
|
+
extend Helper
|
|
7
|
+
|
|
8
|
+
def analyze(node, registry, scope, entry)
|
|
9
|
+
node => AST::TypeDeclaration(name:, variants:)
|
|
10
|
+
|
|
11
|
+
symbol_ref = entry.lookup_type(name).to_ref
|
|
12
|
+
|
|
13
|
+
analyze_in_parallel(variants, registry, scope, entry)
|
|
14
|
+
.then { Result.combine(node, scope:, variants: it) }
|
|
15
|
+
.map_node { it.with(symbol: symbol_ref) }
|
|
16
|
+
.add_errors(validate_no_unbound_vars(symbol_ref, registry, entry))
|
|
17
|
+
.add_errors(validate_type_symbol(symbol_ref, registry, entry))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def validate_no_unbound_vars(symbol, registry, entry)
|
|
23
|
+
actual_symbol = registry.lookup(symbol)
|
|
24
|
+
|
|
25
|
+
vars = actual_symbol
|
|
26
|
+
.variants
|
|
27
|
+
.flat_map { collect_vars(it, registry) }
|
|
28
|
+
.group_by(&:name)
|
|
29
|
+
|
|
30
|
+
missing_vars = vars
|
|
31
|
+
.reject { |(k, _)| actual_symbol.type_params.map(&:name).include? k }
|
|
32
|
+
.values
|
|
33
|
+
.flatten
|
|
34
|
+
|
|
35
|
+
return [] if missing_vars.empty?
|
|
36
|
+
|
|
37
|
+
[
|
|
38
|
+
Error::UnboundTypeVariable.new(
|
|
39
|
+
entry.name,
|
|
40
|
+
missing_vars.size == 1 ? missing_vars.first.decl_span : actual_symbol.decl_span,
|
|
41
|
+
type_name: symbol.name,
|
|
42
|
+
variables: missing_vars.map(&:name),
|
|
43
|
+
)
|
|
44
|
+
]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def collect_vars(symbol, registry)
|
|
48
|
+
case symbol
|
|
49
|
+
in Symbol::TypeRef | Symbol::ValueRef
|
|
50
|
+
registry.lookup(symbol)
|
|
51
|
+
.then { collect_vars(it, registry) }
|
|
52
|
+
|
|
53
|
+
in Symbol::Constructor(args:)
|
|
54
|
+
args.flat_map { collect_vars(it, registry) }
|
|
55
|
+
|
|
56
|
+
in Symbol::Variable
|
|
57
|
+
[symbol]
|
|
58
|
+
|
|
59
|
+
in Symbol::TypeApplication(args:)
|
|
60
|
+
args.flat_map { collect_vars(it, registry) }
|
|
61
|
+
|
|
62
|
+
in Symbol::RecordType(row_var:)
|
|
63
|
+
row_var.nil? ? [] : [row_var]
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Frontend
|
|
3
|
+
module SemanticAnalysis
|
|
4
|
+
module VariableReference
|
|
5
|
+
extend self
|
|
6
|
+
extend Helper
|
|
7
|
+
|
|
8
|
+
def analyze(node, _registry, scope, entry)
|
|
9
|
+
node => AST::VariableReference(name:)
|
|
10
|
+
|
|
11
|
+
case scope.lookup(name)
|
|
12
|
+
in nil
|
|
13
|
+
Result
|
|
14
|
+
.init(node.with(symbol: Symbol.var(name, node.range)), scope)
|
|
15
|
+
.add_errors([Error::UndefinedVariable.new(
|
|
16
|
+
entry.name, node.range, var_ref: name,
|
|
17
|
+
candidates: scope.bindings.keys,
|
|
18
|
+
)])
|
|
19
|
+
|
|
20
|
+
in symbol
|
|
21
|
+
Result.init(node.with(symbol:), scope)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Frontend
|
|
3
|
+
module SemanticAnalysis
|
|
4
|
+
module VariantDeclaration
|
|
5
|
+
extend self
|
|
6
|
+
extend Helper
|
|
7
|
+
|
|
8
|
+
def analyze(node, _registry, scope, entry)
|
|
9
|
+
node => AST::VariantDeclaration(name:)
|
|
10
|
+
|
|
11
|
+
node
|
|
12
|
+
.with(symbol: entry.lookup_value(name).to_ref)
|
|
13
|
+
.then { Result.init(it, scope) }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
require 'jade/frontend/semantic_analysis/error'
|
|
2
|
+
|
|
3
|
+
require 'jade/frontend/semantic_analysis/helper'
|
|
4
|
+
require 'jade/frontend/semantic_analysis/module_node'
|
|
5
|
+
require 'jade/frontend/semantic_analysis/import_declaration'
|
|
6
|
+
require 'jade/frontend/semantic_analysis/literal'
|
|
7
|
+
require 'jade/frontend/semantic_analysis/char_literal'
|
|
8
|
+
require 'jade/frontend/semantic_analysis/assign'
|
|
9
|
+
require 'jade/frontend/semantic_analysis/variable_reference'
|
|
10
|
+
require 'jade/frontend/semantic_analysis/constructor_reference'
|
|
11
|
+
require 'jade/frontend/semantic_analysis/body'
|
|
12
|
+
require 'jade/frontend/semantic_analysis/function_declaration'
|
|
13
|
+
require 'jade/frontend/semantic_analysis/function_call'
|
|
14
|
+
require 'jade/frontend/semantic_analysis/keyed_call/validation'
|
|
15
|
+
require 'jade/frontend/semantic_analysis/keyed_call'
|
|
16
|
+
require 'jade/frontend/semantic_analysis/type_declaration'
|
|
17
|
+
require 'jade/frontend/semantic_analysis/variant_declaration'
|
|
18
|
+
require 'jade/frontend/semantic_analysis/interop_import_declaration'
|
|
19
|
+
require 'jade/frontend/semantic_analysis/implementation'
|
|
20
|
+
require 'jade/frontend/semantic_analysis/implementation_function'
|
|
21
|
+
require 'jade/frontend/semantic_analysis/struct_declaration'
|
|
22
|
+
require 'jade/frontend/semantic_analysis/interface_declaration'
|
|
23
|
+
require 'jade/frontend/semantic_analysis/if_then_else'
|
|
24
|
+
require 'jade/frontend/semantic_analysis/member_access'
|
|
25
|
+
require 'jade/frontend/semantic_analysis/qualified_access'
|
|
26
|
+
require 'jade/frontend/semantic_analysis/record_access'
|
|
27
|
+
require 'jade/frontend/semantic_analysis/case_of'
|
|
28
|
+
require 'jade/frontend/semantic_analysis/case_of_branch'
|
|
29
|
+
require 'jade/frontend/semantic_analysis/pattern_wildcard'
|
|
30
|
+
require 'jade/frontend/semantic_analysis/pattern_literal'
|
|
31
|
+
require 'jade/frontend/semantic_analysis/pattern_binding'
|
|
32
|
+
require 'jade/frontend/semantic_analysis/pattern_constructor'
|
|
33
|
+
require 'jade/frontend/semantic_analysis/pattern_record'
|
|
34
|
+
require 'jade/frontend/semantic_analysis/pattern_list'
|
|
35
|
+
require 'jade/frontend/semantic_analysis/lambda'
|
|
36
|
+
require 'jade/frontend/semantic_analysis/grouping'
|
|
37
|
+
require 'jade/frontend/semantic_analysis/list'
|
|
38
|
+
require 'jade/frontend/semantic_analysis/record_literal'
|
|
39
|
+
require 'jade/frontend/semantic_analysis/record_update'
|
|
40
|
+
require 'jade/frontend/semantic_analysis/record_field'
|
|
41
|
+
|
|
42
|
+
module Jade
|
|
43
|
+
module Frontend
|
|
44
|
+
module SemanticAnalysis
|
|
45
|
+
extend self
|
|
46
|
+
|
|
47
|
+
def analyze(entry, registry)
|
|
48
|
+
initialize_scope(entry)
|
|
49
|
+
.then { analyze_node(entry.ast, registry, it, entry) }
|
|
50
|
+
.then { it.errors.any? ? Err[it.errors] : Ok[entry.with(ast: it.node)] }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def analyze_repl(ast, registry, scope, entry)
|
|
54
|
+
analyze_node(ast, registry, scope, entry)
|
|
55
|
+
.then { it.errors.any? ? Err[it.errors] : Ok[[it.node, it.scope]] }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def analyze_entry(entry, registry)
|
|
59
|
+
analyze(entry, registry)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def initialize_scope(entry)
|
|
65
|
+
entry
|
|
66
|
+
.values
|
|
67
|
+
.reduce(Scope.new) { |acc, (unq_name, sym)| acc.bind(unq_name, sym) }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def analyze_node(ast, registry, scope, entry)
|
|
71
|
+
case ast
|
|
72
|
+
in AST::Module then ModuleNode
|
|
73
|
+
in AST::ImportDeclaration then ImportDeclaration
|
|
74
|
+
in AST::InteropImportDeclaration then InteropImportDeclaration
|
|
75
|
+
in AST::Literal then Literal
|
|
76
|
+
in AST::CharLiteral then CharLiteral
|
|
77
|
+
in AST::Assign then Assign
|
|
78
|
+
in AST::VariableReference then VariableReference
|
|
79
|
+
in AST::ConstructorReference then ConstructorReference
|
|
80
|
+
in AST::Body then Body
|
|
81
|
+
in AST::FunctionDeclaration then FunctionDeclaration
|
|
82
|
+
in AST::FunctionCall then FunctionCall
|
|
83
|
+
in AST::KeyedCall then KeyedCall
|
|
84
|
+
in AST::TypeDeclaration then TypeDeclaration
|
|
85
|
+
in AST::VariantDeclaration then VariantDeclaration
|
|
86
|
+
in AST::Implementation then Implementation
|
|
87
|
+
in AST::ImplementationFunction then ImplementationFunction
|
|
88
|
+
in AST::StructDeclaration then StructDeclaration
|
|
89
|
+
in AST::InterfaceDeclaration then InterfaceDeclaration
|
|
90
|
+
in AST::IfThenElse then IfThenElse
|
|
91
|
+
in AST::MemberAccess then MemberAccess
|
|
92
|
+
in AST::QualifiedAccess then QualifiedAccess
|
|
93
|
+
in AST::RecordAccess then RecordAccess
|
|
94
|
+
in AST::CaseOf then CaseOf
|
|
95
|
+
in AST::CaseOfBranch then CaseOfBranch
|
|
96
|
+
in AST::Pattern::Wildcard then PatternWildcard
|
|
97
|
+
in AST::Pattern::Literal then PatternLiteral
|
|
98
|
+
in AST::Pattern::Binding then PatternBinding
|
|
99
|
+
in AST::Pattern::Constructor then PatternConstructor
|
|
100
|
+
in AST::Pattern::Record then PatternRecord
|
|
101
|
+
in AST::Pattern::List then PatternList
|
|
102
|
+
in AST::Lambda then Lambda
|
|
103
|
+
in AST::Grouping then Grouping
|
|
104
|
+
in AST::List then List
|
|
105
|
+
in AST::RecordLiteral then RecordLiteral
|
|
106
|
+
in AST::RecordUpdate then RecordUpdate
|
|
107
|
+
in AST::RecordField then RecordField
|
|
108
|
+
end
|
|
109
|
+
.analyze(ast, registry, scope, entry)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
Result = Data.define(:node, :errors, :scope) do
|
|
113
|
+
def self.init(node, scope)
|
|
114
|
+
new(node:, errors: [], scope:)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Combine a fixed set of child Results into a parent Result.
|
|
118
|
+
# `children` keys must match the parent node's `with` field
|
|
119
|
+
# names. Errors are unioned; the parent's `scope:` is whatever
|
|
120
|
+
# the caller decides (usually the input scope or a child's).
|
|
121
|
+
def self.combine(node, scope:, **children)
|
|
122
|
+
new(
|
|
123
|
+
node: node.with(**children.transform_values(&:node)),
|
|
124
|
+
errors: children.values.flat_map(&:errors),
|
|
125
|
+
scope:,
|
|
126
|
+
)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def add_errors(more)
|
|
130
|
+
with(errors: errors + more)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def map_node
|
|
134
|
+
with(node: yield(node))
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def with_scope(s)
|
|
138
|
+
with(scope: s)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def to_result
|
|
142
|
+
errors.any? ? Err[errors] : Ok[node]
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
Scope = Data.define(:bindings) do
|
|
147
|
+
def initialize(bindings: {})
|
|
148
|
+
super
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def bind(name, symbol)
|
|
152
|
+
with(bindings: bindings.merge(name => symbol))
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def lookup(name)
|
|
156
|
+
bindings[name]
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Frontend
|
|
3
|
+
module TypeChecking
|
|
4
|
+
# Finalize-time pass that rewrites attached dictionary markers in place
|
|
5
|
+
# through the final substitution. Codegen then reads marker.type.id
|
|
6
|
+
# directly — dict_env keys (built from scheme.constraints) and marker
|
|
7
|
+
# ids both pass through the same final substitution, so they match.
|
|
8
|
+
#
|
|
9
|
+
# We do NOT pre-substitute scheme.type/constraints: substitution can map
|
|
10
|
+
# one quantified var to another (e.g. `b → c'` via body unification),
|
|
11
|
+
# which would leave the scheme's `quantified` list and type out of sync
|
|
12
|
+
# for downstream instantiations.
|
|
13
|
+
module Canonicalize
|
|
14
|
+
extend self
|
|
15
|
+
|
|
16
|
+
def run(ast, env, registry)
|
|
17
|
+
walk(ast, env.substitution, registry, env.entry_name)
|
|
18
|
+
env
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def walk(node, sub, registry, entry_name)
|
|
24
|
+
case node
|
|
25
|
+
in AST::FunctionCall(callee:, args:)
|
|
26
|
+
canonicalize_dictionaries(node, sub, registry, entry_name)
|
|
27
|
+
walk(callee, sub, registry, entry_name)
|
|
28
|
+
args.each { walk(it, sub, registry, entry_name) }
|
|
29
|
+
|
|
30
|
+
in AST::QualifiedAccess | AST::VariableReference
|
|
31
|
+
canonicalize_dictionaries(node, sub, registry, entry_name)
|
|
32
|
+
|
|
33
|
+
in AST::Module(body:) then walk(body, sub, registry, entry_name)
|
|
34
|
+
in AST::Body(expressions:) then expressions.each { walk(it, sub, registry, entry_name) }
|
|
35
|
+
in AST::FunctionDeclaration(body:) then walk(body, sub, registry, entry_name)
|
|
36
|
+
in AST::Implementation(functions:) then functions.each { walk(it, sub, registry, entry_name) }
|
|
37
|
+
in AST::ImplementationFunction(fn:) then walk(fn, sub, registry, entry_name)
|
|
38
|
+
in AST::Assign(expression:) then walk(expression, sub, registry, entry_name)
|
|
39
|
+
in AST::Lambda(body:) then walk(body, sub, registry, entry_name)
|
|
40
|
+
in AST::Grouping(expression:) then walk(expression, sub, registry, entry_name)
|
|
41
|
+
in AST::List(items:) then items.each { walk(it, sub, registry, entry_name) }
|
|
42
|
+
in AST::RecordLiteral(fields:) then fields.each { walk(it, sub, registry, entry_name) }
|
|
43
|
+
in AST::RecordField(value:) then walk(value, sub, registry, entry_name)
|
|
44
|
+
in AST::RecordUpdate(base:, fields:)
|
|
45
|
+
walk(base, sub, registry, entry_name)
|
|
46
|
+
fields.each { walk(it, sub, registry, entry_name) }
|
|
47
|
+
in AST::RecordAccess(target:) then walk(target, sub, registry, entry_name)
|
|
48
|
+
in AST::IfThenElse(condition:, if_branch:, else_branch:)
|
|
49
|
+
walk(condition, sub, registry, entry_name)
|
|
50
|
+
walk(if_branch, sub, registry, entry_name)
|
|
51
|
+
walk(else_branch, sub, registry, entry_name)
|
|
52
|
+
in AST::CaseOf(expression:, branches:)
|
|
53
|
+
walk(expression, sub, registry, entry_name)
|
|
54
|
+
branches.each { walk(it, sub, registry, entry_name) }
|
|
55
|
+
in AST::CaseOfBranch(body:) then walk(body, sub, registry, entry_name)
|
|
56
|
+
|
|
57
|
+
# Leaves: cannot contain a FunctionCall. Listed explicitly so
|
|
58
|
+
# adding a new node type forces a decision here rather than
|
|
59
|
+
# silently skipping a subtree.
|
|
60
|
+
in AST::Literal |
|
|
61
|
+
AST::CharLiteral |
|
|
62
|
+
AST::ConstructorReference |
|
|
63
|
+
AST::ImportDeclaration |
|
|
64
|
+
AST::InteropImportDeclaration |
|
|
65
|
+
AST::TypeDeclaration |
|
|
66
|
+
AST::StructDeclaration |
|
|
67
|
+
AST::InterfaceDeclaration |
|
|
68
|
+
AST::Placeholder
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Rewrite var-typed dictionary markers through the final substitution.
|
|
74
|
+
# If the var resolved to a concrete type (e.g. `Decodable α` where a
|
|
75
|
+
# pattern-binding unified α with Int), resolve the impl now so codegen
|
|
76
|
+
# can dispatch directly — previously this only handled var-stayed-var
|
|
77
|
+
# and the substituted-to-concrete case crashed codegen's dict lookup.
|
|
78
|
+
def canonicalize_dictionaries(node, sub, registry, entry_name)
|
|
79
|
+
node.dictionaries.each_with_index do |entry, i|
|
|
80
|
+
next unless entry.is_a?(Type::Constraint)
|
|
81
|
+
|
|
82
|
+
applied = sub.apply(entry.type)
|
|
83
|
+
resolved = entry.with(type: applied)
|
|
84
|
+
|
|
85
|
+
if applied.is_a?(Type::Var)
|
|
86
|
+
node.dictionaries[i] = resolved
|
|
87
|
+
else
|
|
88
|
+
Constraints
|
|
89
|
+
.resolve(resolved, registry, entry_name)
|
|
90
|
+
.map { node.dictionaries[i] = it }
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Frontend
|
|
3
|
+
module TypeChecking
|
|
4
|
+
module Constraints
|
|
5
|
+
module Deriving
|
|
6
|
+
module Decodable
|
|
7
|
+
extend self
|
|
8
|
+
include Helpers
|
|
9
|
+
|
|
10
|
+
INTERFACE = 'Decode.Decodable'
|
|
11
|
+
|
|
12
|
+
def supports?(interface) = interface == INTERFACE
|
|
13
|
+
|
|
14
|
+
def derive(constraint, registry, entry_name, &lookup)
|
|
15
|
+
case constraint.type
|
|
16
|
+
in Type::Application(constructor: Type::Constructor(name: 'List.List'), args: [inner])
|
|
17
|
+
derive_unary(constraint, inner, 'Decode.list', lookup, entry_name)
|
|
18
|
+
|
|
19
|
+
in Type::Application(constructor: Type::Constructor(name: 'Maybe.Maybe'), args: [inner])
|
|
20
|
+
derive_unary(constraint, inner, 'Decode.nullable', lookup, entry_name)
|
|
21
|
+
|
|
22
|
+
in Type::Application(constructor: Type::Constructor(name:), args:)
|
|
23
|
+
resolved_sym = Symbol
|
|
24
|
+
.type_ref_from_qualified_name(name)
|
|
25
|
+
.then { registry.lookup(it) }
|
|
26
|
+
|
|
27
|
+
case resolved_sym
|
|
28
|
+
in Symbol::Struct
|
|
29
|
+
derive_struct(constraint, resolved_sym, args, registry, lookup, entry_name)
|
|
30
|
+
|
|
31
|
+
else
|
|
32
|
+
failed(constraint, entry_name)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
in Type::AnonymousRecord(fields:)
|
|
36
|
+
derive_anonymous_record(constraint, fields, lookup, entry_name)
|
|
37
|
+
|
|
38
|
+
else
|
|
39
|
+
failed(constraint, entry_name)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def failed(constraint, entry_name)
|
|
46
|
+
Err[
|
|
47
|
+
Error::DerivationFailed.new(
|
|
48
|
+
entry_name,
|
|
49
|
+
constraint.origin&.range,
|
|
50
|
+
constraint:,
|
|
51
|
+
trace: [],
|
|
52
|
+
)
|
|
53
|
+
]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def derive_unary(constraint, inner_type, stdlib_fn, lookup, entry_name)
|
|
57
|
+
dep = Type.constraint(INTERFACE, inner_type, nil)
|
|
58
|
+
|
|
59
|
+
resolve_dep(dep, lookup, entry_name).and_then do |dep_impl|
|
|
60
|
+
body = [:call,
|
|
61
|
+
[:stdlib_fn, stdlib_fn],
|
|
62
|
+
[
|
|
63
|
+
[:impl_arg, 0, 'decoder'],
|
|
64
|
+
],
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
Ok[implementation(constraint, body, [dep_impl])]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def derive_struct(constraint, struct_sym, type_args, registry, lookup, entry_name)
|
|
72
|
+
fields = struct_fields(struct_sym, type_args, registry)
|
|
73
|
+
|
|
74
|
+
[:struct_constructor, struct_sym.qualified_name, fields.size]
|
|
75
|
+
.then { derive_record(constraint, fields, it, lookup, entry_name) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def derive_anonymous_record(constraint, fields, lookup, entry_name)
|
|
79
|
+
keys = fields.keys.map(&:to_s)
|
|
80
|
+
|
|
81
|
+
[:anon_record_constructor, keys]
|
|
82
|
+
.then { derive_record(constraint, fields.to_a, it, lookup, entry_name) }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def derive_record(constraint, fields, constructor_ref, lookup, entry_name)
|
|
86
|
+
field_deps = fields.map do |_, field_type|
|
|
87
|
+
Type.constraint(INTERFACE, field_type, nil)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
resolved_deps = field_deps.map do |dep|
|
|
91
|
+
resolve_dep(dep, lookup, entry_name) => Ok[impl]
|
|
92
|
+
impl
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
seed = [:call, [:stdlib_fn, 'Decode.succeed'], [constructor_ref]]
|
|
96
|
+
|
|
97
|
+
body = fields.each_with_index.reduce(seed) do |acc, ((field_name, _), idx)|
|
|
98
|
+
field_decoder = [:call,
|
|
99
|
+
[:stdlib_fn, 'Decode.field'],
|
|
100
|
+
[
|
|
101
|
+
field_name.to_s,
|
|
102
|
+
[:impl_arg, idx, 'decoder'],
|
|
103
|
+
],
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
[:call, [:stdlib_fn, 'Decode.and_map'], [acc, field_decoder]]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
Ok[implementation(constraint, body, resolved_deps)]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Free-var inner constraints fall back to the constraint marker
|
|
113
|
+
# itself — codegen later resolves it from the caller's dict env.
|
|
114
|
+
# Without this, `Decodable(List(a))` with `a` free would bail
|
|
115
|
+
# with UnresolvedConstraint.
|
|
116
|
+
def resolve_dep(dep, lookup, entry_name)
|
|
117
|
+
lookup
|
|
118
|
+
.call(dep)
|
|
119
|
+
.on_err(Error::UnresolvedConstraint) {
|
|
120
|
+
dep.type.is_a?(Type::Var) ? Ok[dep] : Err[it]
|
|
121
|
+
}
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def implementation(constraint, body, deps)
|
|
125
|
+
decoder_fn = Symbol::DerivedFunction.new(params: [], body:)
|
|
126
|
+
|
|
127
|
+
Symbol::Implementation.new(
|
|
128
|
+
module_name: nil,
|
|
129
|
+
interface: Symbol.type_ref_from_qualified_name(constraint.interface),
|
|
130
|
+
type: constraint.type,
|
|
131
|
+
type_params: [],
|
|
132
|
+
constraints: [],
|
|
133
|
+
functions: { 'decoder' => decoder_fn },
|
|
134
|
+
deps:,
|
|
135
|
+
extends: [],
|
|
136
|
+
decl_span: nil,
|
|
137
|
+
)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|