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.
Files changed (326) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +23 -0
  3. data/LICENSE +21 -0
  4. data/README.md +386 -0
  5. data/exe/jade +6 -0
  6. data/lib/jade/ast/node.rb +44 -0
  7. data/lib/jade/ast/nodes.rb +35 -0
  8. data/lib/jade/ast/pretty_printer.rb +50 -0
  9. data/lib/jade/ast.rb +723 -0
  10. data/lib/jade/calendar/runtime.rb +15 -0
  11. data/lib/jade/cli/fmt.rb +96 -0
  12. data/lib/jade/cli/lsp.rb +13 -0
  13. data/lib/jade/cli/q.rb +113 -0
  14. data/lib/jade/cli.rb +43 -0
  15. data/lib/jade/clock/runtime.rb +13 -0
  16. data/lib/jade/codegen/boundary/cache.rb +94 -0
  17. data/lib/jade/codegen/boundary/specialized/list.rb +65 -0
  18. data/lib/jade/codegen/boundary/specialized/maybe.rb +40 -0
  19. data/lib/jade/codegen/boundary/specialized/record.rb +165 -0
  20. data/lib/jade/codegen/boundary/specialized/scalar.rb +67 -0
  21. data/lib/jade/codegen/boundary/specialized.rb +106 -0
  22. data/lib/jade/codegen/boundary.rb +189 -0
  23. data/lib/jade/codegen/constructor_reference.rb +18 -0
  24. data/lib/jade/codegen/context.rb +96 -0
  25. data/lib/jade/codegen/emitter.rb +81 -0
  26. data/lib/jade/codegen/function_call.rb +367 -0
  27. data/lib/jade/codegen/function_declaration.rb +199 -0
  28. data/lib/jade/codegen/helpers.rb +103 -0
  29. data/lib/jade/codegen/implementation.rb +178 -0
  30. data/lib/jade/codegen/inline.rb +89 -0
  31. data/lib/jade/codegen/inlines.rb +326 -0
  32. data/lib/jade/codegen/method_names.rb +54 -0
  33. data/lib/jade/codegen/pattern/constructor.rb +57 -0
  34. data/lib/jade/codegen/port_decoder.rb +77 -0
  35. data/lib/jade/codegen/pretty.rb +53 -0
  36. data/lib/jade/codegen/transforms/fold_shape.rb +222 -0
  37. data/lib/jade/codegen/transforms/self_call.rb +80 -0
  38. data/lib/jade/codegen/transforms/tail_call.rb +120 -0
  39. data/lib/jade/codegen/variant_declaration.rb +41 -0
  40. data/lib/jade/codegen.rb +400 -0
  41. data/lib/jade/compiler.rb +69 -0
  42. data/lib/jade/decode.rb +320 -0
  43. data/lib/jade/diagnostics/renderer.rb +121 -0
  44. data/lib/jade/diagnostics.rb +77 -0
  45. data/lib/jade/did_you_mean.rb +16 -0
  46. data/lib/jade/entry.rb +177 -0
  47. data/lib/jade/error.rb +72 -0
  48. data/lib/jade/formatter/accesses.rb +37 -0
  49. data/lib/jade/formatter/bindings.rb +29 -0
  50. data/lib/jade/formatter/body.rb +50 -0
  51. data/lib/jade/formatter/calls.rb +51 -0
  52. data/lib/jade/formatter/case_of.rb +31 -0
  53. data/lib/jade/formatter/case_of_branch.rb +59 -0
  54. data/lib/jade/formatter/collections.rb +78 -0
  55. data/lib/jade/formatter/declarations.rb +178 -0
  56. data/lib/jade/formatter/exposing.rb +48 -0
  57. data/lib/jade/formatter/function_declaration.rb +72 -0
  58. data/lib/jade/formatter/helper.rb +122 -0
  59. data/lib/jade/formatter/if_then_else.rb +64 -0
  60. data/lib/jade/formatter/infix_application.rb +69 -0
  61. data/lib/jade/formatter/lambda.rb +50 -0
  62. data/lib/jade/formatter/leaves.rb +111 -0
  63. data/lib/jade/formatter/module_node.rb +26 -0
  64. data/lib/jade/formatter/pattern.rb +61 -0
  65. data/lib/jade/formatter/type.rb +67 -0
  66. data/lib/jade/formatter.rb +38 -0
  67. data/lib/jade/frontend/comment_attacher.rb +121 -0
  68. data/lib/jade/frontend/desugaring/placeholder.rb +39 -0
  69. data/lib/jade/frontend/desugaring/resolved.rb +63 -0
  70. data/lib/jade/frontend/desugaring.rb +217 -0
  71. data/lib/jade/frontend/fixity_fixer.rb +209 -0
  72. data/lib/jade/frontend/forward_declaration/body.rb +30 -0
  73. data/lib/jade/frontend/forward_declaration/error/bad_import.rb +19 -0
  74. data/lib/jade/frontend/forward_declaration/error/exposed_type_not_found.rb +18 -0
  75. data/lib/jade/frontend/forward_declaration/error/exposed_value_not_found.rb +18 -0
  76. data/lib/jade/frontend/forward_declaration/error/module_not_found.rb +18 -0
  77. data/lib/jade/frontend/forward_declaration/error/private_type_expansion.rb +19 -0
  78. data/lib/jade/frontend/forward_declaration/error/tuple_arity_overflow.rb +25 -0
  79. data/lib/jade/frontend/forward_declaration/error/type_not_found.rb +29 -0
  80. data/lib/jade/frontend/forward_declaration/error/type_not_lowerable.rb +16 -0
  81. data/lib/jade/frontend/forward_declaration/error/unknown_extends_interface.rb +18 -0
  82. data/lib/jade/frontend/forward_declaration/error.rb +11 -0
  83. data/lib/jade/frontend/forward_declaration/function_declaration.rb +32 -0
  84. data/lib/jade/frontend/forward_declaration/helper.rb +91 -0
  85. data/lib/jade/frontend/forward_declaration/implementation.rb +63 -0
  86. data/lib/jade/frontend/forward_declaration/implementation_function.rb +39 -0
  87. data/lib/jade/frontend/forward_declaration/import_declaration.rb +115 -0
  88. data/lib/jade/frontend/forward_declaration/interface_declaration.rb +66 -0
  89. data/lib/jade/frontend/forward_declaration/interop_import_declaration.rb +99 -0
  90. data/lib/jade/frontend/forward_declaration/module.rb +98 -0
  91. data/lib/jade/frontend/forward_declaration/struct_declaration.rb +42 -0
  92. data/lib/jade/frontend/forward_declaration/type_declaration.rb +42 -0
  93. data/lib/jade/frontend/forward_declaration.rb +71 -0
  94. data/lib/jade/frontend/pattern_analysis/exhaustiveness.rb +65 -0
  95. data/lib/jade/frontend/pattern_analysis/matrix.rb +235 -0
  96. data/lib/jade/frontend/pattern_analysis.rb +40 -0
  97. data/lib/jade/frontend/semantic_analysis/assign.rb +20 -0
  98. data/lib/jade/frontend/semantic_analysis/body.rb +33 -0
  99. data/lib/jade/frontend/semantic_analysis/case_of.rb +19 -0
  100. data/lib/jade/frontend/semantic_analysis/case_of_branch.rb +20 -0
  101. data/lib/jade/frontend/semantic_analysis/char_literal.rb +14 -0
  102. data/lib/jade/frontend/semantic_analysis/constructor_reference.rb +64 -0
  103. data/lib/jade/frontend/semantic_analysis/error/circular_extends.rb +19 -0
  104. data/lib/jade/frontend/semantic_analysis/error/constant_not_callable.rb +24 -0
  105. data/lib/jade/frontend/semantic_analysis/error/constructor_not_found.rb +34 -0
  106. data/lib/jade/frontend/semantic_analysis/error/constructor_pattern_arity_mismatch.rb +24 -0
  107. data/lib/jade/frontend/semantic_analysis/error/duplicate_field.rb +18 -0
  108. data/lib/jade/frontend/semantic_analysis/error/duplicate_function_declaration.rb +25 -0
  109. data/lib/jade/frontend/semantic_analysis/error/duplicate_record_field.rb +19 -0
  110. data/lib/jade/frontend/semantic_analysis/error/invalid_list_rest_pattern.rb +21 -0
  111. data/lib/jade/frontend/semantic_analysis/error/kwargs_on_non_constructor.rb +17 -0
  112. data/lib/jade/frontend/semantic_analysis/error/missing_exposing_clause.rb +17 -0
  113. data/lib/jade/frontend/semantic_analysis/error/missing_extends_implementation.rb +21 -0
  114. data/lib/jade/frontend/semantic_analysis/error/missing_field.rb +20 -0
  115. data/lib/jade/frontend/semantic_analysis/error/missing_implementation_function.rb +19 -0
  116. data/lib/jade/frontend/semantic_analysis/error/module_not_found.rb +22 -0
  117. data/lib/jade/frontend/semantic_analysis/error/nested_task_port.rb +19 -0
  118. data/lib/jade/frontend/semantic_analysis/error/non_task_port.rb +22 -0
  119. data/lib/jade/frontend/semantic_analysis/error/orphan_implementation.rb +20 -0
  120. data/lib/jade/frontend/semantic_analysis/error/predicate_must_return_bool.rb +22 -0
  121. data/lib/jade/frontend/semantic_analysis/error/predicate_name_not_allowed.rb +25 -0
  122. data/lib/jade/frontend/semantic_analysis/error/shadowing_error.rb +22 -0
  123. data/lib/jade/frontend/semantic_analysis/error/type_args_mismatch.rb +25 -0
  124. data/lib/jade/frontend/semantic_analysis/error/type_param_required.rb +19 -0
  125. data/lib/jade/frontend/semantic_analysis/error/unbound_type_variable.rb +22 -0
  126. data/lib/jade/frontend/semantic_analysis/error/undefined_variable.rb +29 -0
  127. data/lib/jade/frontend/semantic_analysis/error/unknown_field.rb +20 -0
  128. data/lib/jade/frontend/semantic_analysis/error/unknown_implementation_function.rb +19 -0
  129. data/lib/jade/frontend/semantic_analysis/error/unused_interface_type_param.rb +24 -0
  130. data/lib/jade/frontend/semantic_analysis/error/value_not_exposed.rb +23 -0
  131. data/lib/jade/frontend/semantic_analysis/error/variable_not_found.rb +25 -0
  132. data/lib/jade/frontend/semantic_analysis/error.rb +40 -0
  133. data/lib/jade/frontend/semantic_analysis/function_call.rb +60 -0
  134. data/lib/jade/frontend/semantic_analysis/function_declaration.rb +58 -0
  135. data/lib/jade/frontend/semantic_analysis/grouping.rb +17 -0
  136. data/lib/jade/frontend/semantic_analysis/helper.rb +152 -0
  137. data/lib/jade/frontend/semantic_analysis/if_then_else.rb +20 -0
  138. data/lib/jade/frontend/semantic_analysis/implementation.rb +143 -0
  139. data/lib/jade/frontend/semantic_analysis/implementation_function.rb +16 -0
  140. data/lib/jade/frontend/semantic_analysis/import_declaration.rb +14 -0
  141. data/lib/jade/frontend/semantic_analysis/interface_declaration.rb +45 -0
  142. data/lib/jade/frontend/semantic_analysis/interop_import_declaration.rb +69 -0
  143. data/lib/jade/frontend/semantic_analysis/keyed_call/validation.rb +109 -0
  144. data/lib/jade/frontend/semantic_analysis/keyed_call.rb +88 -0
  145. data/lib/jade/frontend/semantic_analysis/lambda.rb +23 -0
  146. data/lib/jade/frontend/semantic_analysis/list.rb +17 -0
  147. data/lib/jade/frontend/semantic_analysis/literal.rb +23 -0
  148. data/lib/jade/frontend/semantic_analysis/member_access.rb +87 -0
  149. data/lib/jade/frontend/semantic_analysis/module_node.rb +27 -0
  150. data/lib/jade/frontend/semantic_analysis/pattern_binding.rb +27 -0
  151. data/lib/jade/frontend/semantic_analysis/pattern_constructor.rb +47 -0
  152. data/lib/jade/frontend/semantic_analysis/pattern_list.rb +33 -0
  153. data/lib/jade/frontend/semantic_analysis/pattern_literal.rb +17 -0
  154. data/lib/jade/frontend/semantic_analysis/pattern_record.rb +25 -0
  155. data/lib/jade/frontend/semantic_analysis/pattern_wildcard.rb +14 -0
  156. data/lib/jade/frontend/semantic_analysis/qualified_access.rb +14 -0
  157. data/lib/jade/frontend/semantic_analysis/record_access.rb +14 -0
  158. data/lib/jade/frontend/semantic_analysis/record_field.rb +17 -0
  159. data/lib/jade/frontend/semantic_analysis/record_literal.rb +21 -0
  160. data/lib/jade/frontend/semantic_analysis/record_update.rb +21 -0
  161. data/lib/jade/frontend/semantic_analysis/struct_declaration.rb +44 -0
  162. data/lib/jade/frontend/semantic_analysis/tuple.rb +17 -0
  163. data/lib/jade/frontend/semantic_analysis/type_declaration.rb +69 -0
  164. data/lib/jade/frontend/semantic_analysis/variable_reference.rb +27 -0
  165. data/lib/jade/frontend/semantic_analysis/variant_declaration.rb +18 -0
  166. data/lib/jade/frontend/semantic_analysis.rb +161 -0
  167. data/lib/jade/frontend/type_checking/canonicalize.rb +97 -0
  168. data/lib/jade/frontend/type_checking/constraints/deriving/decodable.rb +144 -0
  169. data/lib/jade/frontend/type_checking/constraints/deriving/encodable.rb +144 -0
  170. data/lib/jade/frontend/type_checking/constraints/deriving/eq.rb +265 -0
  171. data/lib/jade/frontend/type_checking/constraints/deriving/helpers.rb +59 -0
  172. data/lib/jade/frontend/type_checking/constraints/deriving.rb +28 -0
  173. data/lib/jade/frontend/type_checking/constraints.rb +101 -0
  174. data/lib/jade/frontend/type_checking/definition.rb +71 -0
  175. data/lib/jade/frontend/type_checking/env.rb +79 -0
  176. data/lib/jade/frontend/type_checking/error/case_of_branches_type_mismatch.rb +19 -0
  177. data/lib/jade/frontend/type_checking/error/derivation_failed.rb +21 -0
  178. data/lib/jade/frontend/type_checking/error/function_body_type_mismatch.rb +23 -0
  179. data/lib/jade/frontend/type_checking/error/function_call_type_mismatch.rb +37 -0
  180. data/lib/jade/frontend/type_checking/error/if_branch_type_mismatch.rb +19 -0
  181. data/lib/jade/frontend/type_checking/error/if_branches_type_mismatch.rb +18 -0
  182. data/lib/jade/frontend/type_checking/error/if_condition_type_mismatch.rb +17 -0
  183. data/lib/jade/frontend/type_checking/error/implementation_type_mismatch.rb +20 -0
  184. data/lib/jade/frontend/type_checking/error/list_item_type_mismatch.rb +19 -0
  185. data/lib/jade/frontend/type_checking/error/missing_implementation.rb +20 -0
  186. data/lib/jade/frontend/type_checking/error/missing_patterns.rb +26 -0
  187. data/lib/jade/frontend/type_checking/error/pattern_type_mismatch.rb +13 -0
  188. data/lib/jade/frontend/type_checking/error/port_not_decodable.rb +38 -0
  189. data/lib/jade/frontend/type_checking/error/record_access_type_mismatch.rb +14 -0
  190. data/lib/jade/frontend/type_checking/error/type_mismatch.rb +23 -0
  191. data/lib/jade/frontend/type_checking/error/unresolved_constraint.rb +20 -0
  192. data/lib/jade/frontend/type_checking/error.rb +18 -0
  193. data/lib/jade/frontend/type_checking/expected.rb +23 -0
  194. data/lib/jade/frontend/type_checking/generalization.rb +17 -0
  195. data/lib/jade/frontend/type_checking/generalizer.rb +38 -0
  196. data/lib/jade/frontend/type_checking/inference/assign.rb +58 -0
  197. data/lib/jade/frontend/type_checking/inference/body.rb +45 -0
  198. data/lib/jade/frontend/type_checking/inference/case_of.rb +102 -0
  199. data/lib/jade/frontend/type_checking/inference/constructor_reference.rb +21 -0
  200. data/lib/jade/frontend/type_checking/inference/function_call.rb +132 -0
  201. data/lib/jade/frontend/type_checking/inference/function_declaration.rb +70 -0
  202. data/lib/jade/frontend/type_checking/inference/grouping.rb +18 -0
  203. data/lib/jade/frontend/type_checking/inference/helpers.rb +34 -0
  204. data/lib/jade/frontend/type_checking/inference/if_then_else.rb +46 -0
  205. data/lib/jade/frontend/type_checking/inference/implementation.rb +150 -0
  206. data/lib/jade/frontend/type_checking/inference/import_declaration.rb +19 -0
  207. data/lib/jade/frontend/type_checking/inference/interface_declaration.rb +18 -0
  208. data/lib/jade/frontend/type_checking/inference/interop_import_declaration.rb +18 -0
  209. data/lib/jade/frontend/type_checking/inference/lambda.rb +87 -0
  210. data/lib/jade/frontend/type_checking/inference/list.rb +52 -0
  211. data/lib/jade/frontend/type_checking/inference/literal.rb +24 -0
  212. data/lib/jade/frontend/type_checking/inference/module.rb +18 -0
  213. data/lib/jade/frontend/type_checking/inference/pattern.rb +135 -0
  214. data/lib/jade/frontend/type_checking/inference/qualified_access.rb +23 -0
  215. data/lib/jade/frontend/type_checking/inference/record_access.rb +35 -0
  216. data/lib/jade/frontend/type_checking/inference/record_field.rb +19 -0
  217. data/lib/jade/frontend/type_checking/inference/record_literal.rb +24 -0
  218. data/lib/jade/frontend/type_checking/inference/record_update.rb +37 -0
  219. data/lib/jade/frontend/type_checking/inference/struct_declaration.rb +18 -0
  220. data/lib/jade/frontend/type_checking/inference/type_declaration.rb +18 -0
  221. data/lib/jade/frontend/type_checking/inference/variable_reference.rb +27 -0
  222. data/lib/jade/frontend/type_checking/inference.rb +27 -0
  223. data/lib/jade/frontend/type_checking/instantiation.rb +24 -0
  224. data/lib/jade/frontend/type_checking/loader.rb +80 -0
  225. data/lib/jade/frontend/type_checking/placeholder.rb +12 -0
  226. data/lib/jade/frontend/type_checking/port_resolution.rb +123 -0
  227. data/lib/jade/frontend/type_checking/result.rb +41 -0
  228. data/lib/jade/frontend/type_checking/scheme.rb +20 -0
  229. data/lib/jade/frontend/type_checking/state.rb +52 -0
  230. data/lib/jade/frontend/type_checking/substitution.rb +93 -0
  231. data/lib/jade/frontend/type_checking/unification.rb +282 -0
  232. data/lib/jade/frontend/type_checking/var_gen.rb +33 -0
  233. data/lib/jade/frontend/type_checking.rb +129 -0
  234. data/lib/jade/frontend/unused_analysis.rb +41 -0
  235. data/lib/jade/frontend/usage_analysis/reference_index.rb +53 -0
  236. data/lib/jade/frontend/usage_analysis.rb +195 -0
  237. data/lib/jade/frontend.rb +101 -0
  238. data/lib/jade/interop/boundary.rb +68 -0
  239. data/lib/jade/interop/error.rb +84 -0
  240. data/lib/jade/interop/lowering/error.rb +32 -0
  241. data/lib/jade/interop/lowering.rb +53 -0
  242. data/lib/jade/interop/runtime.rb +24 -0
  243. data/lib/jade/interop.rb +1 -0
  244. data/lib/jade/lexer.rb +189 -0
  245. data/lib/jade/lsp/converters.rb +542 -0
  246. data/lib/jade/lsp/handlers.rb +340 -0
  247. data/lib/jade/lsp/server.rb +63 -0
  248. data/lib/jade/lsp/snippets.rb +100 -0
  249. data/lib/jade/lsp/state.rb +25 -0
  250. data/lib/jade/lsp.rb +16 -0
  251. data/lib/jade/module_loader/cache.rb +56 -0
  252. data/lib/jade/module_loader/dependency_graph.rb +23 -0
  253. data/lib/jade/module_loader/dependency_resolver.rb +48 -0
  254. data/lib/jade/module_loader/normalize.rb +34 -0
  255. data/lib/jade/module_loader/topological_sort.rb +41 -0
  256. data/lib/jade/module_loader.rb +127 -0
  257. data/lib/jade/parsing/combinators.rb +291 -0
  258. data/lib/jade/parsing/error.rb +154 -0
  259. data/lib/jade/parsing/token.rb +12 -0
  260. data/lib/jade/parsing/type.rb +92 -0
  261. data/lib/jade/parsing.rb +674 -0
  262. data/lib/jade/port.rb +1 -0
  263. data/lib/jade/registry.rb +79 -0
  264. data/lib/jade/result.rb +121 -0
  265. data/lib/jade/runtime.rb +127 -0
  266. data/lib/jade/source.rb +62 -0
  267. data/lib/jade/stdlib/basics.rb +214 -0
  268. data/lib/jade/stdlib/bytes.rb +70 -0
  269. data/lib/jade/stdlib/calendar.rb +405 -0
  270. data/lib/jade/stdlib/char.rb +27 -0
  271. data/lib/jade/stdlib/clock.rb +342 -0
  272. data/lib/jade/stdlib/compiled.rb +48 -0
  273. data/lib/jade/stdlib/decode/params.rb +154 -0
  274. data/lib/jade/stdlib/decode.rb +315 -0
  275. data/lib/jade/stdlib/dict.rb +134 -0
  276. data/lib/jade/stdlib/encode.rb +143 -0
  277. data/lib/jade/stdlib/intrinsics.rb +280 -0
  278. data/lib/jade/stdlib/list.rb +214 -0
  279. data/lib/jade/stdlib/maybe.rb +73 -0
  280. data/lib/jade/stdlib/result.rb +131 -0
  281. data/lib/jade/stdlib/set.rb +123 -0
  282. data/lib/jade/stdlib/string.rb +65 -0
  283. data/lib/jade/stdlib/task.rb +55 -0
  284. data/lib/jade/stdlib/tuple.rb +21 -0
  285. data/lib/jade/stdlib.rb +112 -0
  286. data/lib/jade/symbol/anonymous_record.rb +7 -0
  287. data/lib/jade/symbol/base.rb +15 -0
  288. data/lib/jade/symbol/constructor.rb +11 -0
  289. data/lib/jade/symbol/derived_function.rb +5 -0
  290. data/lib/jade/symbol/function.rb +15 -0
  291. data/lib/jade/symbol/function_type.rb +7 -0
  292. data/lib/jade/symbol/implementation.rb +17 -0
  293. data/lib/jade/symbol/implementation_template.rb +13 -0
  294. data/lib/jade/symbol/interface.rb +11 -0
  295. data/lib/jade/symbol/interface_function.rb +18 -0
  296. data/lib/jade/symbol/interop_function.rb +22 -0
  297. data/lib/jade/symbol/lambda.rb +7 -0
  298. data/lib/jade/symbol/parser.rb +79 -0
  299. data/lib/jade/symbol/partial_application.rb +7 -0
  300. data/lib/jade/symbol/record_type.rb +8 -0
  301. data/lib/jade/symbol/stdlib_function.rb +15 -0
  302. data/lib/jade/symbol/stdlib_implementation.rb +7 -0
  303. data/lib/jade/symbol/struct.rb +15 -0
  304. data/lib/jade/symbol/type_application.rb +8 -0
  305. data/lib/jade/symbol/type_ref.rb +11 -0
  306. data/lib/jade/symbol/union.rb +15 -0
  307. data/lib/jade/symbol/value_ref.rb +15 -0
  308. data/lib/jade/symbol/variable.rb +7 -0
  309. data/lib/jade/symbol/variant.rb +11 -0
  310. data/lib/jade/symbol.rb +162 -0
  311. data/lib/jade/task.rb +103 -0
  312. data/lib/jade/tasks/rspec.rb +266 -0
  313. data/lib/jade/tasks.rb +70 -0
  314. data/lib/jade/type/anonymous_record.rb +33 -0
  315. data/lib/jade/type/application.rb +21 -0
  316. data/lib/jade/type/base.rb +9 -0
  317. data/lib/jade/type/constraint.rb +17 -0
  318. data/lib/jade/type/constructor.rb +19 -0
  319. data/lib/jade/type/function.rb +18 -0
  320. data/lib/jade/type/partial_application.rb +17 -0
  321. data/lib/jade/type/unit.rb +15 -0
  322. data/lib/jade/type/var.rb +21 -0
  323. data/lib/jade/type.rb +259 -0
  324. data/lib/jade/version.rb +3 -0
  325. data/lib/jade.rb +55 -0
  326. metadata +387 -0
data/lib/jade/error.rb ADDED
@@ -0,0 +1,72 @@
1
+ require 'jade/did_you_mean'
2
+
3
+ module Jade
4
+ class Error
5
+ attr_reader :entry, :span
6
+
7
+ def initialize(entry:, span:, **rest)
8
+ @entry = entry
9
+ @span = span
10
+ end
11
+
12
+ def message
13
+ fail NotImplementedError
14
+ end
15
+
16
+ def label
17
+ nil
18
+ end
19
+
20
+ def notes
21
+ []
22
+ end
23
+
24
+ def queried_name
25
+ nil
26
+ end
27
+
28
+ def candidates
29
+ []
30
+ end
31
+
32
+ def to_diagnostic(registry = nil, source: nil)
33
+ source ||=
34
+ case entry
35
+ when String then registry&.get(entry)&.source
36
+ else entry&.source
37
+ end
38
+
39
+ Jade::Diagnostics::Diagnostic.error(
40
+ message,
41
+ primary: Jade::Diagnostics::Label[source, span, label],
42
+ annotations: notes + did_you_mean_notes,
43
+ )
44
+ end
45
+
46
+ private
47
+
48
+ def did_you_mean_notes
49
+ return [] if queried_name.nil? || candidates.empty?
50
+
51
+ Jade::DidYouMean
52
+ .suggest(queried_name, candidates)
53
+ .then { it.empty? ? [] : [help_annotation(it)] }
54
+ end
55
+
56
+ def help_annotation(suggestions)
57
+ Jade::Diagnostics::Annotation[
58
+ :help,
59
+ "did you mean #{suggestions.map { "`#{it}`" }.join(' or ')}?",
60
+ ]
61
+ end
62
+
63
+ def ordinal(n)
64
+ if (11..13).cover?(n % 100)
65
+ 'th'
66
+ else
67
+ %w[th st nd rd th th th th th th][n % 10]
68
+ end
69
+ .then { "#{n}#{it}" }
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,37 @@
1
+ module Jade
2
+ module Formatter
3
+ # The three `target.member`-style accesses. Each has a slightly
4
+ # different `.name` shape (member is an Identifier, qualified is a
5
+ # raw string), but the formatting is `<target>.<rendered name>`.
6
+
7
+ module MemberAccess
8
+ extend self
9
+ extend Helper
10
+
11
+ def format(node, indent:, source:)
12
+ "#{format_node(node.target, source:)}.#{node.name.name}"
13
+ .then(&and_indent(indent))
14
+ end
15
+ end
16
+
17
+ module QualifiedAccess
18
+ extend self
19
+ extend Helper
20
+
21
+ def format(node, indent:, source:)
22
+ "#{format_node(node.target, source:)}.#{node.name}"
23
+ .then(&and_indent(indent))
24
+ end
25
+ end
26
+
27
+ module RecordAccess
28
+ extend self
29
+ extend Helper
30
+
31
+ def format(node, indent:, source:)
32
+ "#{format_node(node.target, source:)}.#{node.name.name}"
33
+ .then(&and_indent(indent))
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ module Jade
2
+ module Formatter
3
+ # `name = expr` and `name <- task` — same shape, different operator.
4
+
5
+ module Assign
6
+ extend self
7
+ extend Helper
8
+
9
+ def format(node, indent:, source:)
10
+ node => AST::Assign(pattern:, expression:)
11
+
12
+ "#{format_pattern(pattern)} = #{format_node(expression, source:)}"
13
+ .then(&and_indent(indent))
14
+ end
15
+ end
16
+
17
+ module Bind
18
+ extend self
19
+ extend Helper
20
+
21
+ def format(node, indent:, source:)
22
+ node => AST::Bind(pattern:, expression:)
23
+
24
+ "#{format_pattern(pattern)} <- #{format_node(expression, source:)}"
25
+ .then(&and_indent(indent))
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,50 @@
1
+ module Jade
2
+ module Formatter
3
+ module Body
4
+ extend self
5
+ extend Helper
6
+
7
+ def format(node, indent:, source:)
8
+ node => AST::Body(expressions:, dangling_comments:)
9
+
10
+ if expressions.empty? && !dangling_comments.empty?
11
+ dangling_comments
12
+ .map { |tok| "#{INDENT * indent}#{tok.value}" }
13
+ .join("\n")
14
+ else
15
+ join_expressions(expressions, indent, source:)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ # Prettier-style: preserve at most one user-written blank line between
22
+ # adjacent statements. ≥2 newlines in the source slice between them →
23
+ # join with `\n\n`. Otherwise → `\n`. If we have no source (synthetic
24
+ # body), fall back to single newline.
25
+ def join_expressions(expressions, indent, source:)
26
+ expressions
27
+ .each_cons(2)
28
+ .map { |prev, succ| separator_between(prev, succ, source) }
29
+ .then { [nil, *it] }
30
+ .zip(expressions)
31
+ .map { |sep, expr| "#{sep}#{format_node(expr, indent:, source:)}" }
32
+ .join
33
+ end
34
+
35
+ def separator_between(prev, succ, source)
36
+ blank_line_between?(prev, succ, source) ? "\n\n" : "\n"
37
+ end
38
+
39
+ def blank_line_between?(prev, succ, source)
40
+ return false unless source
41
+
42
+ slice = source.text[prev.range.end...succ.range.begin] || ""
43
+ # A blank line means two newlines separated only by whitespace.
44
+ # `\n # comment\n ` has two newlines but content between them
45
+ # — not a blank line.
46
+ slice.match?(/\n[ \t]*\n/)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,51 @@
1
+ module Jade
2
+ module Formatter
3
+ # FunctionCall and KeyedCall share the same break-on-too-long /
4
+ # respect-trailing-comma logic. Grouped here as siblings.
5
+
6
+ module FunctionCall
7
+ extend self
8
+ extend Helper
9
+
10
+ def format(node, indent:, source:)
11
+ node => AST::FunctionCall(callee:, args:, trailing_comma:)
12
+
13
+ callee_str = format_node(callee, source:)
14
+ args_strs = args.map { format_node(it, source:) }
15
+ Calls.render(callee_str, args_strs, trailing_comma, indent)
16
+ end
17
+ end
18
+
19
+ module KeyedCall
20
+ extend self
21
+ extend Helper
22
+
23
+ def format(node, indent:, source:)
24
+ node => AST::KeyedCall(callee:, fields:, trailing_comma:)
25
+
26
+ callee_str = format_node(callee, source:)
27
+ field_strs = fields.map { "#{it.key}: #{format_node(it.value, source:)}" }
28
+ Calls.render(callee_str, field_strs, trailing_comma, indent)
29
+ end
30
+ end
31
+
32
+ module Calls
33
+ extend self
34
+ extend Helper
35
+
36
+ def render(callee_str, item_strs, trailing_comma, indent)
37
+ inline = "#{callee_str}(#{item_strs.join(', ')})"
38
+
39
+ if trailing_comma || too_long?(inline, indent)
40
+ inner = item_strs
41
+ .map { "#{it.then(&and_indent(indent + 1))}," }
42
+ .join("\n")
43
+
44
+ "#{callee_str.then(&and_indent(indent))}(\n#{inner}\n#{INDENT * indent})"
45
+ else
46
+ inline.then(&and_indent(indent))
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,31 @@
1
+ module Jade
2
+ module Formatter
3
+ module CaseOf
4
+ extend self
5
+ extend Helper
6
+
7
+ def format(node, indent:, source:)
8
+ node => AST::CaseOf(expression:, branches:)
9
+
10
+ branches_str = branches
11
+ .map.with_index { |b, i| format_branch(b, branches, i, indent, source:) }
12
+ .join("\n")
13
+
14
+ [
15
+ "case #{format_node(expression, source:)}".then(&and_indent(indent)),
16
+ branches_str,
17
+ "end".then(&and_indent(indent)),
18
+ ].join("\n")
19
+ end
20
+
21
+ # The last branch is rendered as `else` when its pattern is a
22
+ # wildcard — purely sugar; the AST shape is the same.
23
+ def format_branch(branch, all_branches, i, indent, source:)
24
+ last_wildcard = i == all_branches.length - 1 &&
25
+ branch.pattern.is_a?(AST::Pattern::Wildcard)
26
+
27
+ CaseOfBranch.format(branch, indent:, source:, as_else: last_wildcard)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,59 @@
1
+ module Jade
2
+ module Formatter
3
+ # CaseOfBranch is invoked from CaseOf with an extra `as_else:` flag
4
+ # — it doesn't go through the generic dispatcher, so its `format`
5
+ # signature differs from siblings on purpose.
6
+ module CaseOfBranch
7
+ extend self
8
+ extend Helper
9
+
10
+ # Three shapes, in order of preference:
11
+ # - Single-expression body, fits on one line → `in <pat> then <expr>`
12
+ # - Single-expression body, doesn't fit / nested case / has a
13
+ # leading comment → `in <pat>\n <body>` (drop `then`).
14
+ # - Multi-statement body → same as above.
15
+ def format(node, indent:, source:, as_else: false)
16
+ # `else` already conveys "wildcard inline body" — no `then` after.
17
+ header = as_else ? "else" : "in #{format_pattern(node.pattern)}"
18
+ inline_sep = as_else ? "" : " then"
19
+ body = unwrap_grouped_case_body(node.body)
20
+ first = body.expressions.first
21
+ single = body.expressions.length == 1
22
+ has_leading = !first.leading_comments.empty? ||
23
+ !body.leading_comments.empty?
24
+
25
+ multi_line = ->(child) {
26
+ [
27
+ header.then(&and_indent(indent)),
28
+ format_node(child, indent: indent + 1, source:),
29
+ ].join("\n")
30
+ }
31
+
32
+ return multi_line.call(first) if single && first.is_a?(AST::CaseOf)
33
+ return multi_line.call(body) unless single && !has_leading
34
+
35
+ first_str = format_node(first, source:)
36
+ inline = "#{header}#{inline_sep} #{first_str}"
37
+
38
+ if first_str.include?("\n") || too_long?(inline, indent)
39
+ multi_line.call(first)
40
+ else
41
+ inline.then(&and_indent(indent))
42
+ end
43
+ end
44
+
45
+ # Strip `(case … end)` parens around a branch body. With block-form
46
+ # `case`, the inner `end` terminates the case, so wrapping parens
47
+ # are redundant — drop them so reformat normalises both shapes.
48
+ def unwrap_grouped_case_body(body)
49
+ return body unless body.expressions.length == 1
50
+
51
+ first = body.expressions.first
52
+ return body unless first.is_a?(AST::Grouping) &&
53
+ first.expression.is_a?(AST::CaseOf)
54
+
55
+ AST::Body.new(expressions: [first.expression], range: body.range)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,78 @@
1
+ module Jade
2
+ module Formatter
3
+ # Tuple / List share the open-sep-close shape (delegated to
4
+ # `format_delimited`). RecordLiteral / RecordUpdate are similar but
5
+ # carry field-shaped contents and an open-brace prelude.
6
+
7
+ module Tuple
8
+ extend self
9
+ extend Helper
10
+
11
+ def format(node, indent:, source:)
12
+ node => AST::Tuple(items:, trailing_comma:)
13
+
14
+ format_delimited(
15
+ items.map { format_node(it, source:) },
16
+ '(', ')', trailing_comma, indent,
17
+ )
18
+ end
19
+ end
20
+
21
+ module List
22
+ extend self
23
+ extend Helper
24
+
25
+ def format(node, indent:, source:)
26
+ node => AST::List(items:, trailing_comma:)
27
+
28
+ format_delimited(
29
+ items.map { format_node(it, source:) },
30
+ '[', ']', trailing_comma, indent,
31
+ )
32
+ end
33
+ end
34
+
35
+ module RecordLiteral
36
+ extend self
37
+ extend Helper
38
+
39
+ def format(node, indent:, source:)
40
+ node => AST::RecordLiteral(fields:, trailing_comma:)
41
+
42
+ field_strs = fields.map { "#{it.key}: #{format_node(it.value, source:)}" }
43
+ inline = "{ #{field_strs.join(', ')} }"
44
+
45
+ if trailing_comma || too_long?(inline, indent)
46
+ inner = field_strs
47
+ .map { "#{it.then(&and_indent(indent + 1))}," }
48
+ .join("\n")
49
+ "#{INDENT * indent}{\n#{inner}\n#{INDENT * indent}}"
50
+ else
51
+ inline.then(&and_indent(indent))
52
+ end
53
+ end
54
+ end
55
+
56
+ module RecordUpdate
57
+ extend self
58
+ extend Helper
59
+
60
+ def format(node, indent:, source:)
61
+ node => AST::RecordUpdate(base:, fields:, trailing_comma:)
62
+
63
+ base_str = format_node(base, source:)
64
+ field_strs = fields.map { "#{it.key}: #{format_node(it.value, source:)}" }
65
+ inline = "{ #{base_str} | #{field_strs.join(', ')} }"
66
+
67
+ if trailing_comma || too_long?(inline, indent)
68
+ inner = field_strs
69
+ .map { "#{it.then(&and_indent(indent + 1))}," }
70
+ .join("\n")
71
+ "#{INDENT * indent}{ #{base_str} |\n#{inner}\n#{INDENT * indent}}"
72
+ else
73
+ inline.then(&and_indent(indent))
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,178 @@
1
+ module Jade
2
+ module Formatter
3
+ # Top-level declaration nodes other than `def` (which lives in its
4
+ # own file because of the signature break logic).
5
+
6
+ module TypeDeclaration
7
+ extend self
8
+ extend Helper
9
+
10
+ def format(node, indent:, source:)
11
+ node => AST::TypeDeclaration(name:, type_params:, variants:)
12
+
13
+ params_str = type_params.empty? ?
14
+ "" :
15
+ "(#{type_params.map(&:name).join(', ')})"
16
+ header = "type #{name}#{params_str}"
17
+
18
+ if variants.size == 1
19
+ "#{header} = #{format_node(variants.first, source:)}"
20
+ .then(&and_indent(indent))
21
+ else
22
+ inner = INDENT * (indent + 1)
23
+ variants_str = variants
24
+ .map { format_node(it, source:) }
25
+ .map.with_index { |v, i| "#{inner}#{i == 0 ? '=' : '|'} #{v}" }
26
+ .join("\n")
27
+
28
+ "#{and_indent(indent).call(header)}\n#{variants_str}"
29
+ end
30
+ end
31
+ end
32
+
33
+ module VariantDeclaration
34
+ extend self
35
+ extend Helper
36
+
37
+ def format(node, indent:, source:)
38
+ node => AST::VariantDeclaration(name:, args:)
39
+
40
+ case args
41
+ in nil | []
42
+ name
43
+
44
+ in [AST::TypeRecord(fields:, row_var: nil)]
45
+ fields
46
+ .map { |k, v| "#{k}: #{format_type(v)}" }
47
+ .join(', ')
48
+ .then { "#{name}(#{it})" }
49
+
50
+ else
51
+ args
52
+ .map { format_type(it) }
53
+ .join(', ')
54
+ .then { "#{name}(#{it})" }
55
+ end
56
+ end
57
+ end
58
+
59
+ module StructDeclaration
60
+ extend self
61
+ extend Helper
62
+
63
+ def format(node, indent:, source:)
64
+ node => AST::StructDeclaration(name:, type_params:, record_type:)
65
+
66
+ params_str = type_params.empty? ?
67
+ "" :
68
+ "(#{type_params.map(&:name).join(', ')})"
69
+ header = "struct #{name}#{params_str} ="
70
+
71
+ record_type => AST::TypeRecord(fields:, row_var:)
72
+
73
+ if fields.size > 1
74
+ format_multiline(header, fields, row_var, indent)
75
+ else
76
+ "#{header} #{format_type(record_type)}".then(&and_indent(indent))
77
+ end
78
+ end
79
+
80
+ def format_multiline(header, fields, row_var, indent)
81
+ open_brace = row_var ? "{ #{row_var.name} |" : "{"
82
+ fields_str = fields
83
+ .map { |k, v| "#{k}: #{format_type(v)}".then(&and_indent(indent + 1)) }
84
+ .join(",\n")
85
+
86
+ and_indent(indent)
87
+ .call("#{header} #{open_brace}")
88
+ .then { "#{it}\n#{fields_str}\n#{INDENT * indent}}" }
89
+ end
90
+ end
91
+
92
+ module ImportDeclaration
93
+ extend self
94
+ extend Helper
95
+
96
+ def format(node, indent:, source:)
97
+ node => AST::ImportDeclaration(module_name:, as:, exposing:)
98
+
99
+ parts = ["import #{module_name}"]
100
+ parts << "as #{as.as}" if as
101
+ parts << format_exposing(exposing) unless exposing in AST::ExposeNone | nil
102
+
103
+ parts.join(' ').then(&and_indent(indent))
104
+ end
105
+ end
106
+
107
+ module InteropImportDeclaration
108
+ extend self
109
+ extend Helper
110
+
111
+ def format(node, indent:, source:)
112
+ node => AST::InteropImportDeclaration(module: interop_module, functions:)
113
+
114
+ funcs_str = functions
115
+ .map { format_node(it, source:).then(&and_indent(indent + 1)) }
116
+ .join(",\n")
117
+
118
+ [
119
+ "uses #{interop_module.name} with".then(&and_indent(indent)),
120
+ funcs_str,
121
+ "end".then(&and_indent(indent)),
122
+ ].join("\n")
123
+ end
124
+ end
125
+
126
+ module InterfaceDeclaration
127
+ extend self
128
+ extend Helper
129
+
130
+ def format(node, indent:, source:)
131
+ node => AST::InterfaceDeclaration(name:, type_param:, functions:)
132
+
133
+ fns_str = functions
134
+ .map { format_node(it, indent: indent + 1, source:) }
135
+ .join(",\n")
136
+
137
+ [
138
+ "interface #{name}(#{type_param.name}) with".then(&and_indent(indent)),
139
+ fns_str,
140
+ "end".then(&and_indent(indent)),
141
+ ].join("\n")
142
+ end
143
+ end
144
+
145
+ module Implementation
146
+ extend self
147
+ extend Helper
148
+
149
+ def format(node, indent:, source:)
150
+ node => AST::Implementation(interface:, applied_type:, extends:, functions:)
151
+
152
+ extends_str = extends.empty? ? "" : " extends #{extends.join(', ')}"
153
+ header = "implements #{interface}(#{format_type(applied_type)})" \
154
+ "#{extends_str} with"
155
+ fns_str = functions
156
+ .map { format_node(it, indent: indent + 1, source:) }
157
+ .join(",\n")
158
+
159
+ [
160
+ header.then(&and_indent(indent)),
161
+ fns_str,
162
+ "end".then(&and_indent(indent)),
163
+ ].join("\n")
164
+ end
165
+ end
166
+
167
+ module ImplementationFunction
168
+ extend self
169
+ extend Helper
170
+
171
+ def format(node, indent:, source:)
172
+ node => AST::ImplementationFunction(name:, fn:)
173
+
174
+ "#{name}: #{format_node(fn, source:)}".then(&and_indent(indent))
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,48 @@
1
+ module Jade
2
+ module Formatter
3
+ module Exposing
4
+ extend self
5
+ extend Helper
6
+
7
+ def format(node, indent: 0)
8
+ case node
9
+ in AST::ExposeAll
10
+ "exposing (..)"
11
+
12
+ in AST::ExposeNone | nil
13
+ ""
14
+
15
+ in AST::ExposeList(items:, trailing_comma:)
16
+ item_strs = sort(items).map { format_item(it) }
17
+ inline = "exposing (#{item_strs.join(', ')})"
18
+
19
+ if trailing_comma || too_long?(inline, indent)
20
+ inner = item_strs.map { "#{INDENT * (indent + 1)}#{it}," }.join("\n")
21
+ "exposing (\n#{inner}\n#{INDENT * indent})"
22
+ else
23
+ inline
24
+ end
25
+ end
26
+ end
27
+
28
+ # Types and constructors first, then values — both alphabetised.
29
+ def sort(items)
30
+ items.sort_by do |item|
31
+ case item
32
+ in AST::ExposeType | AST::ExposeTypeExpand then [0, item.name]
33
+ in AST::ExposeValue then [1, item.name]
34
+ end
35
+ end
36
+ end
37
+
38
+ def format_item(node)
39
+ case node
40
+ in AST::ExposeValue(name:) then name
41
+ in AST::ExposeType(name:) then name
42
+ in AST::ExposeTypeExpand(name:) then "#{name}(..)"
43
+ in AST::ExposeAs(as:) then as
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end