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,72 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Formatter
|
|
3
|
+
module FunctionDeclaration
|
|
4
|
+
extend self
|
|
5
|
+
extend Helper
|
|
6
|
+
|
|
7
|
+
def format(node, indent:, source:)
|
|
8
|
+
node => AST::FunctionDeclaration(
|
|
9
|
+
name:, params:, return_type:, body:
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
[
|
|
13
|
+
format_signature(name, params, return_type, indent, source:),
|
|
14
|
+
format_node(body, indent: indent + 1, source:),
|
|
15
|
+
"end".then(&and_indent(indent)),
|
|
16
|
+
].join("\n")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
# `def name(params) -> Return`. When the inline form is too long:
|
|
22
|
+
# - if return is a breakable record, break the record (params stay
|
|
23
|
+
# inline when the resulting header fits).
|
|
24
|
+
# - else if there are params, break params multi-line with
|
|
25
|
+
# `-> Type` on the close-paren line.
|
|
26
|
+
# - else live with the long line.
|
|
27
|
+
def format_signature(name, params, return_type, indent, source:)
|
|
28
|
+
return_str = format_type_atom(return_type)
|
|
29
|
+
params_inline = format_params_inline(params, source:)
|
|
30
|
+
inline = "def #{name}#{params_inline} -> #{return_str}"
|
|
31
|
+
|
|
32
|
+
return inline.then(&and_indent(indent)) unless too_long?(inline, indent)
|
|
33
|
+
|
|
34
|
+
broken_record = try_break_record_return(name, params_inline, return_type, indent)
|
|
35
|
+
return broken_record if broken_record
|
|
36
|
+
|
|
37
|
+
return inline.then(&and_indent(indent)) if params.empty?
|
|
38
|
+
|
|
39
|
+
format_params_multi(name, params, return_str, indent, source:)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def format_params_inline(params, source:)
|
|
43
|
+
return "" if params.empty?
|
|
44
|
+
|
|
45
|
+
params.map { format_node(it, source:) }.join(", ").then { "(#{it})" }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def try_break_record_return(name, params_inline, return_type, indent)
|
|
49
|
+
return nil unless Type.breakable_record?(return_type)
|
|
50
|
+
|
|
51
|
+
record_multi = Type.format_record_multiline(return_type, indent)
|
|
52
|
+
header = "def #{name}#{params_inline} -> #{record_multi.lines.first.chomp}"
|
|
53
|
+
return nil if too_long?(header, indent)
|
|
54
|
+
|
|
55
|
+
"def #{name}#{params_inline} -> #{record_multi}"
|
|
56
|
+
.then(&and_indent(indent))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def format_params_multi(name, params, return_str, indent, source:)
|
|
60
|
+
params_lines = params
|
|
61
|
+
.map { "#{format_node(it, source:)},".then(&and_indent(indent + 1)) }
|
|
62
|
+
.join("\n")
|
|
63
|
+
|
|
64
|
+
[
|
|
65
|
+
"def #{name}(".then(&and_indent(indent)),
|
|
66
|
+
params_lines,
|
|
67
|
+
") -> #{return_str}".then(&and_indent(indent)),
|
|
68
|
+
].join("\n")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Formatter
|
|
3
|
+
# Mixin for per-node formatter modules. Provides:
|
|
4
|
+
# - INDENT, LINE_LIMIT constants
|
|
5
|
+
# - `format_node(node, indent:, source:)` — top-level dispatcher
|
|
6
|
+
# that prepends leading comments and appends a trailing one.
|
|
7
|
+
# - `and_indent(n)` — prefixes every line of a string with N levels of
|
|
8
|
+
# indent, leaving blank lines untouched.
|
|
9
|
+
# - `too_long?(line, indent)` — width check against LINE_LIMIT.
|
|
10
|
+
# - `format_delimited(...)` — the open/items/close pattern used by
|
|
11
|
+
# Tuple, List, and a few callers.
|
|
12
|
+
# - `format_pattern`, `format_type`, `format_exposing` — sibling
|
|
13
|
+
# walks delegated to their own modules.
|
|
14
|
+
module Helper
|
|
15
|
+
def format_node(node, indent: 0, source: nil)
|
|
16
|
+
leading = format_leading_comments(node, indent)
|
|
17
|
+
trailing = format_trailing_comment(node)
|
|
18
|
+
|
|
19
|
+
dispatch_for(node)
|
|
20
|
+
.format(node, indent:, source:)
|
|
21
|
+
.then { leading + it + trailing }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def dispatch_for(node)
|
|
25
|
+
case node
|
|
26
|
+
in AST::Module then ModuleNode
|
|
27
|
+
in AST::Body then Body
|
|
28
|
+
in AST::FunctionDeclaration then FunctionDeclaration
|
|
29
|
+
in AST::FunctionDeclarationParam then FunctionDeclarationParam
|
|
30
|
+
in AST::TypeDeclaration then TypeDeclaration
|
|
31
|
+
in AST::VariantDeclaration then VariantDeclaration
|
|
32
|
+
in AST::StructDeclaration then StructDeclaration
|
|
33
|
+
in AST::ImportDeclaration then ImportDeclaration
|
|
34
|
+
in AST::InteropImportDeclaration then InteropImportDeclaration
|
|
35
|
+
in AST::InteropFunction then InteropFunction
|
|
36
|
+
in AST::InterfaceDeclaration then InterfaceDeclaration
|
|
37
|
+
in AST::InterfaceFunctionDecl then InterfaceFunctionDecl
|
|
38
|
+
in AST::Assign then Assign
|
|
39
|
+
in AST::Bind then Bind
|
|
40
|
+
in AST::Implementation then Implementation
|
|
41
|
+
in AST::ImplementationFunction then ImplementationFunction
|
|
42
|
+
in AST::IfThenElse then IfThenElse
|
|
43
|
+
in AST::CaseOf then CaseOf
|
|
44
|
+
in AST::CaseOfBranch then CaseOfBranch
|
|
45
|
+
in AST::Lambda then Lambda
|
|
46
|
+
in AST::InfixApplication then InfixApplication
|
|
47
|
+
in AST::FunctionCall then FunctionCall
|
|
48
|
+
in AST::KeyedCall then KeyedCall
|
|
49
|
+
in AST::Placeholder then Placeholder
|
|
50
|
+
in AST::MemberAccess then MemberAccess
|
|
51
|
+
in AST::QualifiedAccess then QualifiedAccess
|
|
52
|
+
in AST::RecordAccess then RecordAccess
|
|
53
|
+
in AST::RecordAccessSugar then RecordAccessSugar
|
|
54
|
+
in AST::RecordUpdateSugar then RecordUpdateSugar
|
|
55
|
+
in AST::Grouping then Grouping
|
|
56
|
+
in AST::Tuple then Tuple
|
|
57
|
+
in AST::List then List
|
|
58
|
+
in AST::RecordLiteral then RecordLiteral
|
|
59
|
+
in AST::RecordUpdate then RecordUpdate
|
|
60
|
+
in AST::VariableReference then VariableReference
|
|
61
|
+
in AST::ConstructorReference then ConstructorReference
|
|
62
|
+
in AST::CharLiteral then CharLiteral
|
|
63
|
+
in AST::Literal then Literal
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def and_indent(indent)
|
|
68
|
+
->(str) {
|
|
69
|
+
prefix = INDENT * indent
|
|
70
|
+
str.lines.map { |line| line == "\n" ? line : "#{prefix}#{line}" }.join
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def too_long?(line, indent)
|
|
75
|
+
(INDENT * indent).length + line.length > LINE_LIMIT
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def format_leading_comments(node, indent)
|
|
79
|
+
return "" if node.leading_comments.empty?
|
|
80
|
+
|
|
81
|
+
node.leading_comments
|
|
82
|
+
.map { |tok| tok.value.then(&and_indent(indent)) }
|
|
83
|
+
.join("\n")
|
|
84
|
+
.then { it + "\n" }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def format_trailing_comment(node)
|
|
88
|
+
return "" if node.trailing_comments.empty?
|
|
89
|
+
|
|
90
|
+
" #{node.trailing_comments.first.value}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Generic open/sep/close formatter shared by Tuple and List. Inline
|
|
94
|
+
# when it fits and no trailing-comma hint; multi-line otherwise.
|
|
95
|
+
def format_delimited(strs, open, close, trailing_comma, indent)
|
|
96
|
+
inline = "#{open}#{strs.join(', ')}#{close}"
|
|
97
|
+
if trailing_comma || too_long?(inline, indent)
|
|
98
|
+
inner = strs.map { "#{it.then(&and_indent(indent + 1))}," }.join("\n")
|
|
99
|
+
"#{INDENT * indent}#{open}\n#{inner}\n#{INDENT * indent}#{close}"
|
|
100
|
+
else
|
|
101
|
+
inline.then(&and_indent(indent))
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def format_pattern(node, source: nil)
|
|
106
|
+
Pattern.format(node, source:)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def format_type(node)
|
|
110
|
+
Type.format(node)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def format_type_atom(node)
|
|
114
|
+
Type.format_atom(node)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def format_exposing(node, indent: 0)
|
|
118
|
+
Exposing.format(node, indent:)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Formatter
|
|
3
|
+
module IfThenElse
|
|
4
|
+
extend self
|
|
5
|
+
extend Helper
|
|
6
|
+
|
|
7
|
+
def format(node, indent:, source:)
|
|
8
|
+
node => AST::IfThenElse(condition:, if_branch:, else_branch:)
|
|
9
|
+
|
|
10
|
+
cond_str = format_node(condition, source:)
|
|
11
|
+
try_inline_ternary(cond_str, if_branch, else_branch, indent, source:) ||
|
|
12
|
+
format_block(cond_str, if_branch, else_branch, indent, source:)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns nil when block form is needed: either branch is multi-
|
|
16
|
+
# statement / has a leading comment, the combined line is too long,
|
|
17
|
+
# or either single-expression branch already formats across multiple
|
|
18
|
+
# lines (e.g. a `|>` ladder).
|
|
19
|
+
def try_inline_ternary(cond_str, if_branch, else_branch, indent, source:)
|
|
20
|
+
return nil if block_form?(if_branch, else_branch)
|
|
21
|
+
|
|
22
|
+
if_str = single_branch_expr(if_branch, source:)
|
|
23
|
+
else_str = single_branch_expr(else_branch, source:)
|
|
24
|
+
inline = "#{cond_str} ? #{if_str} : #{else_str}"
|
|
25
|
+
|
|
26
|
+
return nil if if_str.include?("\n") || else_str.include?("\n")
|
|
27
|
+
return nil if too_long?(inline, indent)
|
|
28
|
+
|
|
29
|
+
inline.then(&and_indent(indent))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def format_block(cond_str, if_branch, else_branch, indent, source:)
|
|
33
|
+
[
|
|
34
|
+
"if #{cond_str} then".then(&and_indent(indent)),
|
|
35
|
+
format_node(if_branch, indent: indent + 1, source:),
|
|
36
|
+
"else".then(&and_indent(indent)),
|
|
37
|
+
format_node(else_branch, indent: indent + 1, source:),
|
|
38
|
+
"end".then(&and_indent(indent)),
|
|
39
|
+
].join("\n")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Block form needed whenever a branch has more than one expression
|
|
43
|
+
# or a leading comment that the ternary form would drop.
|
|
44
|
+
def block_form?(if_branch, else_branch)
|
|
45
|
+
multi?(if_branch) || multi?(else_branch)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def multi?(body)
|
|
49
|
+
body.expressions.length > 1 ||
|
|
50
|
+
!body.leading_comments.empty? ||
|
|
51
|
+
!body.expressions.first.leading_comments.empty?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Format a body known to hold a single expression with no leading
|
|
55
|
+
# comments. Called only after `block_form?` is false — the raise is
|
|
56
|
+
# an invariant guard, not a user-facing error.
|
|
57
|
+
def single_branch_expr(body, source:)
|
|
58
|
+
raise "formatter invariant: single-expr body expected" if multi?(body)
|
|
59
|
+
|
|
60
|
+
format_node(body.expressions.first, source:)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Formatter
|
|
3
|
+
module InfixApplication
|
|
4
|
+
extend self
|
|
5
|
+
extend Helper
|
|
6
|
+
|
|
7
|
+
def format(node, indent:, source:)
|
|
8
|
+
node => AST::InfixApplication(left:, operator:, right:)
|
|
9
|
+
|
|
10
|
+
case operator.value
|
|
11
|
+
when '|>'
|
|
12
|
+
format_pipe_chain(node, indent, source:)
|
|
13
|
+
when '++'
|
|
14
|
+
format_concat_chain(node, indent, source:)
|
|
15
|
+
else
|
|
16
|
+
"#{format_node(left, source:)} #{operator.value} #{format_node(right, source:)}"
|
|
17
|
+
.then(&and_indent(indent))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# `|>` chains of 3 or more arms always render as a ladder; the
|
|
22
|
+
# vertical shape reads as "transform stage by stage". Two-arm
|
|
23
|
+
# chains stay inline unless they bust the line budget.
|
|
24
|
+
def format_pipe_chain(node, indent, source:)
|
|
25
|
+
chain = collect_chain(node, '|>')
|
|
26
|
+
inline = chain.map { format_node(it, source:) }.join(' |> ')
|
|
27
|
+
|
|
28
|
+
if chain.length > 2 || too_long?(inline, indent)
|
|
29
|
+
format_ladder(chain, '|>', indent, source:)
|
|
30
|
+
else
|
|
31
|
+
inline.then(&and_indent(indent))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# `++` chains stay inline when they fit, ladder when they don't.
|
|
36
|
+
def format_concat_chain(node, indent, source:)
|
|
37
|
+
chain = collect_chain(node, '++')
|
|
38
|
+
inline = chain.map { format_node(it, source:) }.join(' ++ ')
|
|
39
|
+
|
|
40
|
+
if chain.length > 1 && too_long?(inline, indent)
|
|
41
|
+
format_ladder(chain, '++', indent, source:)
|
|
42
|
+
else
|
|
43
|
+
inline.then(&and_indent(indent))
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Walk a left-associative chain and return the operands in order
|
|
48
|
+
# (`a op b op c` → [a, b, c]).
|
|
49
|
+
def collect_chain(node, op)
|
|
50
|
+
case node
|
|
51
|
+
in AST::InfixApplication(left:, operator: AST::InfixOperator(value: ^op), right:)
|
|
52
|
+
collect_chain(left, op) + [right]
|
|
53
|
+
else
|
|
54
|
+
[node]
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Emit a chain ladder: head on its own line, each subsequent
|
|
59
|
+
# operand prefixed by `op` indented one level deeper.
|
|
60
|
+
def format_ladder(chain, op, indent, source:)
|
|
61
|
+
cont = INDENT * (indent + 1)
|
|
62
|
+
head = format_node(chain.first, indent:, source:)
|
|
63
|
+
tail = chain[1..].map { "#{cont}#{op} #{format_node(it, source:)}" }
|
|
64
|
+
|
|
65
|
+
([head] + tail).join("\n")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Formatter
|
|
3
|
+
module Lambda
|
|
4
|
+
extend self
|
|
5
|
+
extend Helper
|
|
6
|
+
|
|
7
|
+
# Atoms (and a few near-atoms) that read fine on a single line
|
|
8
|
+
# next to the lambda head. Everything else forces the multi-line
|
|
9
|
+
# `{ body }` shape.
|
|
10
|
+
INLINE_BODY = [
|
|
11
|
+
AST::Literal, AST::CharLiteral, AST::VariableReference,
|
|
12
|
+
AST::ConstructorReference, AST::FunctionCall, AST::RecordAccess,
|
|
13
|
+
AST::MemberAccess, AST::InfixApplication, AST::RecordLiteral,
|
|
14
|
+
AST::List, AST::Tuple, AST::Grouping, AST::RecordUpdate,
|
|
15
|
+
AST::RecordUpdateSugar, AST::RecordAccessSugar,
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
def format(node, indent:, source:)
|
|
19
|
+
node => AST::Lambda(params:, body:)
|
|
20
|
+
|
|
21
|
+
head = format_head(params)
|
|
22
|
+
|
|
23
|
+
if inline_body?(body)
|
|
24
|
+
"#{head} { #{format_node(body.expressions.first, source:)} }"
|
|
25
|
+
.then(&and_indent(indent))
|
|
26
|
+
else
|
|
27
|
+
[
|
|
28
|
+
"#{head} {".then(&and_indent(indent)),
|
|
29
|
+
format_node(body, indent: indent + 1, source:),
|
|
30
|
+
"}".then(&and_indent(indent)),
|
|
31
|
+
].join("\n")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def format_head(params)
|
|
36
|
+
return "->" if params.empty?
|
|
37
|
+
|
|
38
|
+
params
|
|
39
|
+
.map { format_pattern(it) }
|
|
40
|
+
.join(', ')
|
|
41
|
+
.then { "(#{it}) ->" }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def inline_body?(body)
|
|
45
|
+
body.expressions.length == 1 &&
|
|
46
|
+
INLINE_BODY.any? { body.expressions.first.is_a?(it) }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Formatter
|
|
3
|
+
# Simple leaf nodes: each is at most a one-liner of formatting logic.
|
|
4
|
+
# Grouped here so the per-node directory doesn't drown in trivia.
|
|
5
|
+
|
|
6
|
+
module VariableReference
|
|
7
|
+
extend self
|
|
8
|
+
extend Helper
|
|
9
|
+
|
|
10
|
+
def format(node, indent:, source:)
|
|
11
|
+
node.name.then(&and_indent(indent))
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module ConstructorReference
|
|
16
|
+
extend self
|
|
17
|
+
extend Helper
|
|
18
|
+
|
|
19
|
+
def format(node, indent:, source:)
|
|
20
|
+
node.name.then(&and_indent(indent))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
module CharLiteral
|
|
25
|
+
extend self
|
|
26
|
+
extend Helper
|
|
27
|
+
|
|
28
|
+
def format(node, indent:, source:)
|
|
29
|
+
"'#{node.value}'".then(&and_indent(indent))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
module Literal
|
|
34
|
+
extend self
|
|
35
|
+
extend Helper
|
|
36
|
+
|
|
37
|
+
def format(node, indent:, source:)
|
|
38
|
+
case node.value
|
|
39
|
+
in Integer | Float then node.value.to_s
|
|
40
|
+
in TrueClass then "True"
|
|
41
|
+
in FalseClass then "False"
|
|
42
|
+
in String then node.value.inspect
|
|
43
|
+
end
|
|
44
|
+
.then(&and_indent(indent))
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
module Placeholder
|
|
49
|
+
extend self
|
|
50
|
+
extend Helper
|
|
51
|
+
|
|
52
|
+
def format(node, indent:, source:)
|
|
53
|
+
"_".then(&and_indent(indent))
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
module RecordAccessSugar
|
|
58
|
+
extend self
|
|
59
|
+
extend Helper
|
|
60
|
+
|
|
61
|
+
def format(node, indent:, source:)
|
|
62
|
+
".#{node.field_key}".then(&and_indent(indent))
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
module RecordUpdateSugar
|
|
67
|
+
extend self
|
|
68
|
+
extend Helper
|
|
69
|
+
|
|
70
|
+
def format(node, indent:, source:)
|
|
71
|
+
".#{node.field_key}=".then(&and_indent(indent))
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
module Grouping
|
|
76
|
+
extend self
|
|
77
|
+
extend Helper
|
|
78
|
+
|
|
79
|
+
def format(node, indent:, source:)
|
|
80
|
+
"(#{format_node(node.expression, source:)})".then(&and_indent(indent))
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
module FunctionDeclarationParam
|
|
85
|
+
extend self
|
|
86
|
+
extend Helper
|
|
87
|
+
|
|
88
|
+
def format(node, indent:, source:)
|
|
89
|
+
"#{node.name}: #{format_type(node.type)}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
module InteropFunction
|
|
94
|
+
extend self
|
|
95
|
+
extend Helper
|
|
96
|
+
|
|
97
|
+
def format(node, indent:, source:)
|
|
98
|
+
"#{node.name} : #{format_type(node.type)}"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
module InterfaceFunctionDecl
|
|
103
|
+
extend self
|
|
104
|
+
extend Helper
|
|
105
|
+
|
|
106
|
+
def format(node, indent:, source:)
|
|
107
|
+
"#{node.name} : #{format_type(node.type)}".then(&and_indent(indent))
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Formatter
|
|
3
|
+
module ModuleNode
|
|
4
|
+
extend self
|
|
5
|
+
extend Helper
|
|
6
|
+
|
|
7
|
+
def format(node, indent:, source:)
|
|
8
|
+
node => AST::Module(name:, exposing:, body:)
|
|
9
|
+
|
|
10
|
+
chunks = body.expressions
|
|
11
|
+
.chunk_while { |a, b|
|
|
12
|
+
(a in AST::ImportDeclaration) && (b in AST::ImportDeclaration)
|
|
13
|
+
}
|
|
14
|
+
.map { |group|
|
|
15
|
+
group.map { format_node(it, indent:, source:) }.join("\n")
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
header = "module #{name} #{format_exposing(exposing)}"
|
|
19
|
+
# Two blank lines between top-level chunks so def-to-def boundaries
|
|
20
|
+
# don't blur with blank lines inside a def body. Module header to
|
|
21
|
+
# the first chunk stays one blank line.
|
|
22
|
+
chunks.empty? ? header : "#{header}\n\n#{chunks.join("\n\n\n")}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Formatter
|
|
3
|
+
module Pattern
|
|
4
|
+
extend self
|
|
5
|
+
extend Helper
|
|
6
|
+
|
|
7
|
+
def format(node, source: nil)
|
|
8
|
+
case node
|
|
9
|
+
in AST::Pattern::Wildcard
|
|
10
|
+
"_"
|
|
11
|
+
|
|
12
|
+
in AST::Pattern::Literal(literal:)
|
|
13
|
+
format_node(literal, source:)
|
|
14
|
+
|
|
15
|
+
in AST::Pattern::Binding(name:)
|
|
16
|
+
name
|
|
17
|
+
|
|
18
|
+
in AST::Pattern::Constructor(constructor:, patterns:)
|
|
19
|
+
name = format_node(constructor, source:)
|
|
20
|
+
|
|
21
|
+
if patterns.nil? || patterns.empty?
|
|
22
|
+
name
|
|
23
|
+
else
|
|
24
|
+
patterns
|
|
25
|
+
.map { format(it) }
|
|
26
|
+
.join(', ')
|
|
27
|
+
.then { "#{name}(#{it})" }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
in AST::Pattern::Record(fields:)
|
|
31
|
+
fields
|
|
32
|
+
.map { format(it) }
|
|
33
|
+
.join(", ")
|
|
34
|
+
.then { "{ #{it} }" }
|
|
35
|
+
|
|
36
|
+
in AST::Pattern::RecordField(name:, pattern: AST::Pattern::Binding(name: ^name))
|
|
37
|
+
"#{name}:"
|
|
38
|
+
|
|
39
|
+
in AST::Pattern::RecordField(name:, pattern:)
|
|
40
|
+
"#{name}: #{format(pattern)}"
|
|
41
|
+
|
|
42
|
+
in AST::Pattern::Tuple(patterns:)
|
|
43
|
+
patterns
|
|
44
|
+
.map { format(it) }
|
|
45
|
+
.join(', ')
|
|
46
|
+
.then { "(#{it})" }
|
|
47
|
+
|
|
48
|
+
in AST::Pattern::List(patterns:, rest:)
|
|
49
|
+
heads = patterns.map { format(it) }.join(', ')
|
|
50
|
+
tail = case rest
|
|
51
|
+
in AST::Pattern::Binding(name:) then " | #{name}"
|
|
52
|
+
in AST::Pattern::Wildcard then " | _"
|
|
53
|
+
in nil then ""
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
"[#{heads}#{tail}]"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Formatter
|
|
3
|
+
module Type
|
|
4
|
+
extend self
|
|
5
|
+
extend Helper
|
|
6
|
+
|
|
7
|
+
def format(node)
|
|
8
|
+
case node
|
|
9
|
+
in AST::TypeName(type:)
|
|
10
|
+
type
|
|
11
|
+
|
|
12
|
+
in AST::QualifiedTypeName(path:)
|
|
13
|
+
path.join(".")
|
|
14
|
+
|
|
15
|
+
in AST::TypeVar(type:)
|
|
16
|
+
type
|
|
17
|
+
|
|
18
|
+
in AST::TypeApplication(constructor:, args:)
|
|
19
|
+
if args.empty?
|
|
20
|
+
format(constructor)
|
|
21
|
+
else
|
|
22
|
+
args
|
|
23
|
+
.map { format(it) }
|
|
24
|
+
.join(', ')
|
|
25
|
+
.then { "#{format(constructor)}(#{it})" }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
in AST::TypeFunction(params:, return_type:)
|
|
29
|
+
params_str = params.empty? ?
|
|
30
|
+
"()" :
|
|
31
|
+
params.map { format_atom(it) }.join(', ')
|
|
32
|
+
|
|
33
|
+
"#{params_str} -> #{format_atom(return_type)}"
|
|
34
|
+
|
|
35
|
+
in AST::TypeRecord(fields:, row_var:)
|
|
36
|
+
fields_str = fields.map { |k, v| "#{k}: #{format(v)}" }.join(", ")
|
|
37
|
+
row_prefix = row_var ? "#{row_var.name} | " : ""
|
|
38
|
+
|
|
39
|
+
"{ #{row_prefix}#{fields_str} }"
|
|
40
|
+
|
|
41
|
+
in AST::TypeTuple(items:)
|
|
42
|
+
items.map { format(it) }.join(', ').then { "(#{it})" }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Wrap a function type in `(...)` so nested arrows stay unambiguous —
|
|
47
|
+
# the type parser only accepts a `type_atom` on either side of `->`.
|
|
48
|
+
def format_atom(node)
|
|
49
|
+
node.is_a?(AST::TypeFunction) ? "(#{format(node)})" : format(node)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def breakable_record?(type)
|
|
53
|
+
type.is_a?(AST::TypeRecord) && type.fields.size > 1
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def format_record_multiline(type, indent)
|
|
57
|
+
type => AST::TypeRecord(fields:, row_var:)
|
|
58
|
+
open = row_var ? "{ #{row_var.name} |" : "{"
|
|
59
|
+
fields_str = fields
|
|
60
|
+
.map { |k, v| "#{k}: #{format(v)},".then(&and_indent(indent + 1)) }
|
|
61
|
+
.join("\n")
|
|
62
|
+
|
|
63
|
+
"#{open}\n#{fields_str}\n#{INDENT * indent}}"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'jade/formatter/helper'
|
|
2
|
+
require 'jade/formatter/pattern'
|
|
3
|
+
require 'jade/formatter/type'
|
|
4
|
+
require 'jade/formatter/exposing'
|
|
5
|
+
require 'jade/formatter/leaves'
|
|
6
|
+
require 'jade/formatter/accesses'
|
|
7
|
+
require 'jade/formatter/bindings'
|
|
8
|
+
require 'jade/formatter/calls'
|
|
9
|
+
require 'jade/formatter/collections'
|
|
10
|
+
require 'jade/formatter/declarations'
|
|
11
|
+
require 'jade/formatter/module_node'
|
|
12
|
+
require 'jade/formatter/body'
|
|
13
|
+
require 'jade/formatter/function_declaration'
|
|
14
|
+
require 'jade/formatter/lambda'
|
|
15
|
+
require 'jade/formatter/infix_application'
|
|
16
|
+
require 'jade/formatter/if_then_else'
|
|
17
|
+
require 'jade/formatter/case_of'
|
|
18
|
+
require 'jade/formatter/case_of_branch'
|
|
19
|
+
|
|
20
|
+
module Jade
|
|
21
|
+
module Formatter
|
|
22
|
+
extend self
|
|
23
|
+
extend Helper
|
|
24
|
+
|
|
25
|
+
# Constants live at the top-level module so unqualified references
|
|
26
|
+
# resolve via Ruby's lexical-scope constant lookup from any nested
|
|
27
|
+
# per-node module (which only `extend`s Helper — `extend` doesn't
|
|
28
|
+
# bring constants in).
|
|
29
|
+
INDENT = " "
|
|
30
|
+
LINE_LIMIT = 80
|
|
31
|
+
|
|
32
|
+
def format(node, comments:, source:, indent: 0)
|
|
33
|
+
Frontend::CommentAttacher
|
|
34
|
+
.attach(node, comments, source)
|
|
35
|
+
.then { format_node(it, indent:, source:) }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|