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,67 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Codegen
|
|
3
|
+
module Boundary
|
|
4
|
+
module Specialized
|
|
5
|
+
# Int / Float / Bool / String. The runtime validators in
|
|
6
|
+
# `Jade::Interop::Boundary` do the check + conversion (e.g.
|
|
7
|
+
# `String#dup`, `Float#to_f`) in one call.
|
|
8
|
+
module Scalar
|
|
9
|
+
extend self
|
|
10
|
+
|
|
11
|
+
HELPER = {
|
|
12
|
+
'Basics.Int' => 'integer',
|
|
13
|
+
'Basics.Float' => 'float',
|
|
14
|
+
'Basics.Bool' => 'bool',
|
|
15
|
+
'String.String' => 'string',
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
LABEL = {
|
|
19
|
+
'Basics.Int' => 'Int',
|
|
20
|
+
'Basics.Float' => 'Float',
|
|
21
|
+
'Basics.Bool' => 'Bool',
|
|
22
|
+
'String.String' => 'String',
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
# Ruby class used by `List.decode` to validate a list of scalars
|
|
26
|
+
# in a single `Array#all?` C-loop.
|
|
27
|
+
LIST_ELEM_CLASS = {
|
|
28
|
+
'Basics.Int' => '::Integer',
|
|
29
|
+
'Basics.Float' => '::Numeric',
|
|
30
|
+
'Basics.Bool' => '::TrueClass',
|
|
31
|
+
'String.String' => '::String',
|
|
32
|
+
}.freeze
|
|
33
|
+
|
|
34
|
+
def decode(type, input)
|
|
35
|
+
qname = qname_for(type) or return nil
|
|
36
|
+
label = LABEL[qname].inspect
|
|
37
|
+
"Jade::Interop::Boundary.#{HELPER[qname]}(#{label}, #{input})"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Scalar encoders are identity (Ruby int IS the JSON int, etc.),
|
|
41
|
+
# so `encode` returns nil — callers handle that via
|
|
42
|
+
# `Specialized.identity_encoder?`.
|
|
43
|
+
def encode(_type, _value_expr, _registry)
|
|
44
|
+
nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def identity_encoder?(type)
|
|
48
|
+
qname_for(type) ? true : false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def specializable?(type, _registry, _seen)
|
|
52
|
+
identity_encoder?(type)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# The scalar's qname (e.g. `"Basics.Int"`) if `type` is a 0-arg
|
|
56
|
+
# application of a known scalar constructor, else nil. Used by
|
|
57
|
+
# `List.decode` to pick `LIST_ELEM_CLASS` for the all? check.
|
|
58
|
+
def qname_for(type)
|
|
59
|
+
return nil unless Specialized.args_of(type) == []
|
|
60
|
+
|
|
61
|
+
Specialized.qname_of(type).then { HELPER.key?(it) ? it : nil }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
require 'jade/codegen/boundary/specialized/scalar'
|
|
2
|
+
require 'jade/codegen/boundary/specialized/list'
|
|
3
|
+
require 'jade/codegen/boundary/specialized/maybe'
|
|
4
|
+
require 'jade/codegen/boundary/specialized/record'
|
|
5
|
+
|
|
6
|
+
module Jade
|
|
7
|
+
module Codegen
|
|
8
|
+
module Boundary
|
|
9
|
+
# Emits inline boundary code for known-shape types — scalars,
|
|
10
|
+
# `List(specializable)`, `Maybe(specializable)`, and structs whose
|
|
11
|
+
# fields are all specializable. Bypasses `Decode::Runner` and the
|
|
12
|
+
# descriptor cache.
|
|
13
|
+
#
|
|
14
|
+
# This module is the dispatcher: each shape (`Scalar`, `List`,
|
|
15
|
+
# `Maybe`, `Record`) lives in its own file under `specialized/`,
|
|
16
|
+
# exposing `decode` / `encode` / `specializable?` methods that the
|
|
17
|
+
# dispatcher tries in order. Shapes that contain other types
|
|
18
|
+
# (`List`, `Maybe`, `Record`) recurse back through the dispatcher.
|
|
19
|
+
module Specialized
|
|
20
|
+
extend self
|
|
21
|
+
|
|
22
|
+
# Ruby expression that validates `input` and yields the decoded
|
|
23
|
+
# value, or `nil` if `type` isn't specializable.
|
|
24
|
+
def decode_expr(type, input, registry)
|
|
25
|
+
Scalar.decode(type, input) ||
|
|
26
|
+
List.decode(type, input, registry) ||
|
|
27
|
+
Maybe.decode(type, input, registry) ||
|
|
28
|
+
Record.decode(type, input, registry)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Ruby expression that encodes `value_expr` to the wire form, or
|
|
32
|
+
# `nil` if the encoder is identity (caller skips the wrap) or the
|
|
33
|
+
# type isn't specializable (caller falls back to the cache).
|
|
34
|
+
def encode_expr(type, value_expr, registry)
|
|
35
|
+
Record.encode(type, value_expr, registry) ||
|
|
36
|
+
List.encode(type, value_expr, registry) ||
|
|
37
|
+
Maybe.encode(type, value_expr, registry)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# True when the encoder for `type` produces output equal to the
|
|
41
|
+
# input — the boundary wrapper can skip the encode call entirely.
|
|
42
|
+
# Recursive: `List(t)` is identity iff `t` is.
|
|
43
|
+
def identity_encoder?(type)
|
|
44
|
+
Scalar.identity_encoder?(type) || List.identity_encoder?(type)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Predicate used by `Record.specializable_struct` when checking
|
|
48
|
+
# field types. The `seen` set carries struct qnames we're already
|
|
49
|
+
# inside, threaded through container shapes for cycle detection.
|
|
50
|
+
def specializable_field?(type, registry, seen)
|
|
51
|
+
Scalar.specializable?(type, registry, seen) ||
|
|
52
|
+
List.specializable?(type, registry, seen) ||
|
|
53
|
+
Maybe.specializable?(type, registry, seen) ||
|
|
54
|
+
Record.specializable?(type, registry, seen)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def collect_helpers(body, registry)
|
|
58
|
+
Record.collect_helpers(body, registry)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def emit_helpers(structs, registry)
|
|
62
|
+
Record.emit_helpers(structs, registry)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# --- type-shape helpers shared across shape modules ---
|
|
66
|
+
|
|
67
|
+
# Both `Type::Application` (from inferred boundary types) and
|
|
68
|
+
# `Symbol::TypeApplication` (from struct field declarations) carry
|
|
69
|
+
# the same constructor/args shape; normalize to a qname string.
|
|
70
|
+
def qname_of(type)
|
|
71
|
+
case type
|
|
72
|
+
in Type::Application(constructor: Type::Constructor(name:))
|
|
73
|
+
name
|
|
74
|
+
|
|
75
|
+
in Symbol::TypeApplication(constructor: Symbol::TypeRef(module_name:, name: n))
|
|
76
|
+
"#{module_name}.#{n}"
|
|
77
|
+
|
|
78
|
+
else
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def args_of(type)
|
|
84
|
+
case type
|
|
85
|
+
in Type::Application(args:) then args
|
|
86
|
+
in Symbol::TypeApplication(args:) then args
|
|
87
|
+
else nil
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Human-readable label for error messages on container types.
|
|
92
|
+
def type_label(type)
|
|
93
|
+
if (qname = Scalar.qname_for(type))
|
|
94
|
+
Scalar::LABEL[qname]
|
|
95
|
+
elsif (inner = List.inner_of(type))
|
|
96
|
+
"List(#{type_label(inner)})"
|
|
97
|
+
elsif (inner = Maybe.inner_of(type))
|
|
98
|
+
"Maybe(#{type_label(inner)})"
|
|
99
|
+
else
|
|
100
|
+
(qname_of(type) || 'value').split('.').last
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
require 'jade/frontend/type_checking/constraints'
|
|
2
|
+
|
|
3
|
+
module Jade
|
|
4
|
+
module Codegen
|
|
5
|
+
module Boundary
|
|
6
|
+
extend self
|
|
7
|
+
extend Helpers
|
|
8
|
+
|
|
9
|
+
DECODABLE = 'Decode.Decodable'
|
|
10
|
+
ENCODABLE = 'Encode.Encodable'
|
|
11
|
+
|
|
12
|
+
VALUE_PASSTHROUGH_DECODER = 'Jade::Decode::Decoder[Jade::Decode::Desc::Pass[]]'
|
|
13
|
+
VALUE_IDENTITY_ENCODER = '->(v) { v }'
|
|
14
|
+
NEVER_ENCODER = '->(_) { fail "Never arm produced a value" }'
|
|
15
|
+
|
|
16
|
+
def decoder_for(type, registry)
|
|
17
|
+
case type
|
|
18
|
+
in Type::Application(constructor: Type::Constructor(name:), args:)
|
|
19
|
+
decode_app(name, args, registry)
|
|
20
|
+
|
|
21
|
+
else
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def encoder_for(type, registry)
|
|
27
|
+
case type
|
|
28
|
+
in Type::Application(constructor: Type::Constructor(name:), args:)
|
|
29
|
+
encode_app(name, args, registry)
|
|
30
|
+
|
|
31
|
+
else
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def eligible?(fn_type, registry)
|
|
37
|
+
args, return_type = Type.signature(fn_type)
|
|
38
|
+
args.all? { decoder_for(it, registry) } &&
|
|
39
|
+
return_eligible?(return_type, registry)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Task in return position needs both arms encodable — the wrapper
|
|
43
|
+
# discriminates the outcome rather than producing an encoded Task.
|
|
44
|
+
# Everything else checks the type's own encoder directly.
|
|
45
|
+
def return_eligible?(type, registry)
|
|
46
|
+
case type
|
|
47
|
+
in Type::Application(constructor: Type::Constructor(name: 'Task.Task'), args: [ok_t, err_t])
|
|
48
|
+
!encoder_for(ok_t, registry).nil? && !encoder_for(err_t, registry).nil?
|
|
49
|
+
|
|
50
|
+
else
|
|
51
|
+
!encoder_for(type, registry).nil?
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def task_arms(task_type, registry)
|
|
56
|
+
task_type => Type::Application(
|
|
57
|
+
constructor: Type::Constructor(name: 'Task.Task'),
|
|
58
|
+
args: [ok_t, err_t],
|
|
59
|
+
)
|
|
60
|
+
ok_enc = encoder_for(ok_t, registry)
|
|
61
|
+
err_enc = encoder_for(err_t, registry)
|
|
62
|
+
[ok_enc, err_enc] if ok_enc && err_enc
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def decode_app(name, args, registry)
|
|
68
|
+
case [name, args]
|
|
69
|
+
in ['Basics.Int', []] then intr_call('Decode.int')
|
|
70
|
+
in ['Basics.Float', []] then intr_call('Decode.float')
|
|
71
|
+
in ['Basics.Bool', []] then intr_call('Decode.bool')
|
|
72
|
+
in ['String.String', []] then intr_call('Decode.string')
|
|
73
|
+
in ['Decode.Value', []] then VALUE_PASSTHROUGH_DECODER
|
|
74
|
+
|
|
75
|
+
in ['List.List', [inner]]
|
|
76
|
+
decoder_for(inner, registry)
|
|
77
|
+
&.then { "#{intr('Decode.list')}.call(#{it})" }
|
|
78
|
+
|
|
79
|
+
in ['Maybe.Maybe', [inner]]
|
|
80
|
+
decoder_for(inner, registry)
|
|
81
|
+
&.then { "#{intr('Decode.nullable')}.call(#{it})" }
|
|
82
|
+
|
|
83
|
+
in ['Dict.Dict', [k_t, v_t]]
|
|
84
|
+
k_dec = decoder_for(k_t, registry)
|
|
85
|
+
v_dec = decoder_for(v_t, registry)
|
|
86
|
+
"#{intr('Decode.dict')}.curry[#{k_dec}][#{v_dec}]" if k_dec && v_dec
|
|
87
|
+
|
|
88
|
+
else
|
|
89
|
+
decoder_dispatch(name, args, registry)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def encode_app(name, args, registry)
|
|
94
|
+
case [name, args]
|
|
95
|
+
in ['Basics.Int', []] then intr('Encode.int')
|
|
96
|
+
in ['Basics.Float', []] then intr('Encode.float')
|
|
97
|
+
in ['Basics.Bool', []] then intr('Encode.bool')
|
|
98
|
+
in ['String.String', []] then intr('Encode.string')
|
|
99
|
+
in ['Decode.Value', []] then VALUE_IDENTITY_ENCODER
|
|
100
|
+
|
|
101
|
+
# Never is uninhabited — the encoder can never be called. Treat as
|
|
102
|
+
# eligible so Task(a, Never) boundaries work; raise loudly if the
|
|
103
|
+
# impossible happens.
|
|
104
|
+
in ['Basics.Never', []] then NEVER_ENCODER
|
|
105
|
+
|
|
106
|
+
in ['List.List', [inner]]
|
|
107
|
+
encoder_for(inner, registry)
|
|
108
|
+
&.then { "#{intr('Encode.list')}.curry[#{it}]" }
|
|
109
|
+
|
|
110
|
+
in ['Maybe.Maybe', [inner]]
|
|
111
|
+
encoder_for(inner, registry)
|
|
112
|
+
&.then { "#{intr('Encode.nullable')}.curry[#{it}]" }
|
|
113
|
+
|
|
114
|
+
in ['Dict.Dict', [k_t, v_t]]
|
|
115
|
+
k_enc = encoder_for(k_t, registry)
|
|
116
|
+
v_enc = encoder_for(v_t, registry)
|
|
117
|
+
"#{intr('Encode.dict')}.curry[#{k_enc}][#{v_enc}]" if k_enc && v_enc
|
|
118
|
+
|
|
119
|
+
# Task isn't a value-encodable type. `return_eligible?` and
|
|
120
|
+
# `task_arms` handle Task in return position; here we just say
|
|
121
|
+
# "no encoder" so other places that ask for an encoder on a Task
|
|
122
|
+
# value get an honest nil.
|
|
123
|
+
in ['Task.Task', _]
|
|
124
|
+
nil
|
|
125
|
+
|
|
126
|
+
else
|
|
127
|
+
encoder_dispatch(name, args, registry)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def intr(qname)
|
|
132
|
+
"Jade::Runtime.intr(#{qname.inspect})"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def intr_call(qname)
|
|
136
|
+
"#{intr(qname)}.call"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# impl_fn_ref returns a Method ref; callers `.call(...)` it. For
|
|
140
|
+
# 0-arg decoder methods that means `decoder.call()` → the Decoder
|
|
141
|
+
# value. For 1-arg encoder methods that's `encoder.call(value)`.
|
|
142
|
+
def decoder_dispatch(name, args, registry)
|
|
143
|
+
if ref = impl_fn_ref(DECODABLE, name, 'decoder', registry)
|
|
144
|
+
"#{ref}.call"
|
|
145
|
+
else
|
|
146
|
+
derived_dispatch(DECODABLE, name, args, registry)&.dig('decoder')
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def encoder_dispatch(name, args, registry)
|
|
151
|
+
impl_fn_ref(ENCODABLE, name, 'encoder', registry) ||
|
|
152
|
+
derived_dispatch(ENCODABLE, name, args, registry)&.dig('encoder')
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def derived_dispatch(interface_qname, type_qname, args, registry)
|
|
156
|
+
type = Type.constructor(type_qname).apply(args)
|
|
157
|
+
constraint = Type.constraint(interface_qname, type, nil)
|
|
158
|
+
|
|
159
|
+
case Frontend::TypeChecking::Constraints.resolve(constraint, registry, nil)
|
|
160
|
+
in Ok[impl] then Codegen::FunctionCall.generate_impl_dispatch(impl, registry)
|
|
161
|
+
in Err then nil
|
|
162
|
+
end
|
|
163
|
+
rescue NoMethodError, NoMatchingPatternError
|
|
164
|
+
# Deriver assumes derivability (type-check-time invariant); boundary
|
|
165
|
+
# synthesis may probe types whose deps fail — treat as ineligible.
|
|
166
|
+
nil
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def impl_fn_ref(interface_qname, type_qname, fn_name, registry)
|
|
170
|
+
impl = registry.implementations[[interface_qname, type_qname]]
|
|
171
|
+
return nil unless impl
|
|
172
|
+
return nil unless impl.functions[fn_name].is_a?(Symbol::ValueRef)
|
|
173
|
+
|
|
174
|
+
fn_sym = registry.lookup(impl.functions[fn_name])
|
|
175
|
+
|
|
176
|
+
case fn_sym
|
|
177
|
+
in Symbol::Function
|
|
178
|
+
"#{to_qualified(fn_sym.module_name)}::Internal.method(:#{fn_sym.name})"
|
|
179
|
+
|
|
180
|
+
in Symbol::StdlibFunction(codegen:) if codegen.is_a?(String)
|
|
181
|
+
codegen
|
|
182
|
+
|
|
183
|
+
else
|
|
184
|
+
nil
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Codegen
|
|
3
|
+
module ConstructorReference
|
|
4
|
+
extend self
|
|
5
|
+
extend Helpers
|
|
6
|
+
|
|
7
|
+
def generate(node, registry)
|
|
8
|
+
node => AST::ConstructorReference(symbol:)
|
|
9
|
+
from_symbol(registry.lookup(symbol))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def from_symbol(symbol)
|
|
13
|
+
qualified = to_qualified(symbol.qualified_name)
|
|
14
|
+
symbol.args.empty? ? "#{qualified}[]" : "#{qualified}.method(:[])"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Codegen
|
|
3
|
+
# Dynamically-scoped emission state. Each `with_X` wraps a block so the
|
|
4
|
+
# state is visible to the recursive `generate` call tree, then restored
|
|
5
|
+
# on exit. Stored on the Codegen singleton because threading these as
|
|
6
|
+
# parameters through every AST branch would pollute the API.
|
|
7
|
+
module Context
|
|
8
|
+
extend self
|
|
9
|
+
|
|
10
|
+
# Maps [interface_qname, type_var_id] => ruby parameter name. Set by
|
|
11
|
+
# FunctionDeclaration around its body so nested calls can resolve the
|
|
12
|
+
# caller's dict for var-typed constraints. Empty outside any function.
|
|
13
|
+
def dict_env
|
|
14
|
+
@dict_env ||= {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def with_dict_env(env)
|
|
18
|
+
prev = @dict_env
|
|
19
|
+
@dict_env = env
|
|
20
|
+
yield
|
|
21
|
+
ensure
|
|
22
|
+
@dict_env = prev
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# When set, references with this name emit as `self` (and field accesses
|
|
26
|
+
# on them as bare method calls). Used to rewrite operator-impl lambda
|
|
27
|
+
# bodies — `(a, b) -> { a.amount == b.amount }` becomes
|
|
28
|
+
# `def ==(b); amount == b.amount; end`, no `a = self` shim.
|
|
29
|
+
#
|
|
30
|
+
# Name-based, not symbol-identity-based, because Pattern::Binding doesn't
|
|
31
|
+
# carry the resolved Symbol::Variable.
|
|
32
|
+
def self_var_name
|
|
33
|
+
@self_var_name
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def with_self_var_name(name)
|
|
37
|
+
prev = @self_var_name
|
|
38
|
+
@self_var_name = name
|
|
39
|
+
yield
|
|
40
|
+
ensure
|
|
41
|
+
@self_var_name = prev
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# False outside a Module so bare expressions (REPL) get the runtime
|
|
45
|
+
# fallback — no constants exist to reference.
|
|
46
|
+
def hoist_records?
|
|
47
|
+
@hoist_records
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def with_hoisted_records
|
|
51
|
+
prev = @hoist_records
|
|
52
|
+
@hoist_records = true
|
|
53
|
+
yield
|
|
54
|
+
ensure
|
|
55
|
+
@hoist_records = prev
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Methods (def strings) to inline into each type's `Data.define do ... end`
|
|
59
|
+
# block. Populated once at the start of module emission by walking impls
|
|
60
|
+
# of dispatched interfaces; consumed by StructDeclaration /
|
|
61
|
+
# VariantDeclaration. Indexed by the fully-qualified Ruby class string
|
|
62
|
+
# (e.g. `"::Sample::Money"`).
|
|
63
|
+
def dispatched_methods
|
|
64
|
+
@dispatched_methods || {}
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def with_dispatched_methods(map)
|
|
68
|
+
prev = @dispatched_methods
|
|
69
|
+
@dispatched_methods = map
|
|
70
|
+
yield
|
|
71
|
+
ensure
|
|
72
|
+
@dispatched_methods = prev
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Maps boundary decoder/encoder expression strings to module-level
|
|
76
|
+
# const names that hold the same value, precomputed once at module
|
|
77
|
+
# load. Populated by `Boundary.collect_cache` at the start of module
|
|
78
|
+
# emission; consumed by `Boundary.cached_decoder_for` /
|
|
79
|
+
# `cached_encoder_for` from wrapper codegen.
|
|
80
|
+
#
|
|
81
|
+
# Shape: `{ decoders: { spec => const }, encoders: { spec => const } }`.
|
|
82
|
+
# Empty outside a Module — `cached_*` falls through to the raw spec.
|
|
83
|
+
def boundary_cache
|
|
84
|
+
@boundary_cache || { decoders: {}, encoders: {} }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def with_boundary_cache(cache)
|
|
88
|
+
prev = @boundary_cache
|
|
89
|
+
@boundary_cache = cache
|
|
90
|
+
yield
|
|
91
|
+
ensure
|
|
92
|
+
@boundary_cache = prev
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'jade/codegen/helpers'
|
|
2
|
+
|
|
3
|
+
module Jade
|
|
4
|
+
module Codegen
|
|
5
|
+
module Emitter
|
|
6
|
+
extend self
|
|
7
|
+
extend Helpers
|
|
8
|
+
|
|
9
|
+
def emit(ir)
|
|
10
|
+
case ir
|
|
11
|
+
in [:var, expr]
|
|
12
|
+
expr
|
|
13
|
+
|
|
14
|
+
in [:!, expr]
|
|
15
|
+
"!(#{emit(expr)})"
|
|
16
|
+
|
|
17
|
+
in [:and, expr1, expr2]
|
|
18
|
+
"#{emit(expr1)} && #{emit(expr2)}"
|
|
19
|
+
|
|
20
|
+
in Integer | TrueClass | FalseClass | Float
|
|
21
|
+
ir.to_s
|
|
22
|
+
|
|
23
|
+
in String
|
|
24
|
+
ir.inspect
|
|
25
|
+
|
|
26
|
+
in [:case, subject, branches]
|
|
27
|
+
branches
|
|
28
|
+
.map { [:case_branch, *it] }
|
|
29
|
+
.map { emit(it) }
|
|
30
|
+
.join("\n")
|
|
31
|
+
.then { "case #{emit(subject)}\n#{it}\nend" }
|
|
32
|
+
|
|
33
|
+
in [:case_branch, pattern, body]
|
|
34
|
+
body
|
|
35
|
+
.map { emit(it) }.join('; ')
|
|
36
|
+
.then { "in #{emit(pattern)} then #{it}" }
|
|
37
|
+
|
|
38
|
+
in [:call, callee, args]
|
|
39
|
+
args
|
|
40
|
+
.map { emit(it) }
|
|
41
|
+
.join(', ')
|
|
42
|
+
.then { "#{emit(callee)}.call(#{it})"}
|
|
43
|
+
|
|
44
|
+
in [:impl_arg, index, fn]
|
|
45
|
+
"impl_arg[#{index}]['#{fn}']"
|
|
46
|
+
|
|
47
|
+
in [:stdlib_fn, name]
|
|
48
|
+
"Jade::Runtime.intr(#{name.inspect})"
|
|
49
|
+
|
|
50
|
+
in [:struct_constructor, qualified_name, arity]
|
|
51
|
+
"#{to_qualified(qualified_name)}.method(:[]).curry(#{arity})"
|
|
52
|
+
|
|
53
|
+
in [:anon_record_constructor, keys]
|
|
54
|
+
"#{data_define(keys)}.method(:[]).curry(#{keys.size})"
|
|
55
|
+
|
|
56
|
+
in [:list, exprs]
|
|
57
|
+
exprs
|
|
58
|
+
.map { emit(it) }
|
|
59
|
+
.join(', ')
|
|
60
|
+
.then { "[#{it}]" }
|
|
61
|
+
|
|
62
|
+
in [:access, expr, key]
|
|
63
|
+
"#{emit(expr)}.#{key}"
|
|
64
|
+
|
|
65
|
+
# patterns
|
|
66
|
+
|
|
67
|
+
in [:constructor, name, args]
|
|
68
|
+
args
|
|
69
|
+
.map { "#{it}" }
|
|
70
|
+
.join(',')
|
|
71
|
+
.then { "#{to_qualified(name)}(#{it})" }
|
|
72
|
+
|
|
73
|
+
in [:_]
|
|
74
|
+
'_'
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|