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
@@ -0,0 +1,123 @@
1
+ require 'jade/type'
2
+ require 'jade/frontend/type_checking/constraints'
3
+ require 'jade/frontend/type_checking/var_gen'
4
+ require 'jade/frontend/type_checking/error/port_not_decodable'
5
+
6
+ module Jade
7
+ module Frontend
8
+ module TypeChecking
9
+ # Resolves the Decode.Decodable instances each port needs for its ok/err
10
+ # arms. Runs at the end of type-checking, when registry.implementations
11
+ # is fully populated. The resolved Symbol::Implementation (or the :pass
12
+ # sentinel for Decode.Value / Never) is stamped onto each
13
+ # InteropFunction's `decoders` field so codegen can emit straight away.
14
+ module PortResolution
15
+ extend self
16
+
17
+ def resolve(entry, registry)
18
+ entry
19
+ .defined_values
20
+ .reduce([{}, []]) do |(values, errors), (name, sym)|
21
+ new_sym, new_errors = resolve_value(sym, entry, registry)
22
+ [
23
+ values.merge(name => new_sym),
24
+ errors + new_errors,
25
+ ]
26
+ end
27
+ .then { |values, errors|
28
+ errors.empty? \
29
+ ? Ok[entry.with(defined_values: values)]
30
+ : Err[errors]
31
+ }
32
+ end
33
+
34
+ private
35
+
36
+ def resolve_value(sym, entry, registry)
37
+ case sym
38
+ in Symbol::InteropFunction(return_type: Symbol::TypeApplication)
39
+ resolve_port(sym, entry, registry)
40
+
41
+ else
42
+ [sym, []]
43
+ end
44
+ end
45
+
46
+ def resolve_port(interop_fn, entry, registry)
47
+ interop_fn.return_type => Symbol::TypeApplication(args: [ok_sym, err_sym])
48
+
49
+ # Single Type.from_symbol on the whole return so a var that appears
50
+ # in both arms gets the same Type::Var id. PortDecoder relies on
51
+ # those ids to build the call-site synthetic dict_env.
52
+ Type
53
+ .from_symbol(interop_fn.return_type, registry, VarGen.new)
54
+ .first => Type::Application(args: [ok_type, err_type])
55
+
56
+ ok, ok_errors = resolve_arm(ok_sym, ok_type, interop_fn, :ok, entry, registry)
57
+ err, err_errors = resolve_arm(err_sym, err_type, interop_fn, :err, entry, registry)
58
+
59
+ [
60
+ interop_fn.with(decoders: { ok:, err: }),
61
+ ok_errors + err_errors,
62
+ ]
63
+ end
64
+
65
+ def resolve_arm(type_sym, type, interop_fn, arm, entry, registry)
66
+ return [Symbol::InteropFunction::PASS, []] if pass_through?(type_sym)
67
+
68
+ case type
69
+ in Type::Var(name:)
70
+ constraint_index_for(interop_fn, name)
71
+ .then { [Symbol::InteropFunction::Dict.new(constraint_index: it), []] }
72
+
73
+ else
74
+ # Concrete OR compound-with-free-var. Resolve succeeds with a
75
+ # partial Implementation (marker deps for free vars) thanks to
76
+ # the deriver fallback in decodable.rb.
77
+ Type
78
+ .constraint('Decode.Decodable', type, nil)
79
+ .then { Constraints.resolve(it, registry, entry.name) }
80
+ .then { decoder_result(it, interop_fn, arm, entry, type, span_of(type_sym, interop_fn)) }
81
+ end
82
+ end
83
+
84
+ def constraint_index_for(interop_fn, var_name)
85
+ interop_fn
86
+ .constraints
87
+ .index { |_iface, name| name == var_name }
88
+ .tap { fail "no Decodable constraint for #{var_name.inspect}" if it.nil? }
89
+ end
90
+
91
+ def decoder_result(constraint_result, interop_fn, arm, entry, type, span)
92
+ case constraint_result
93
+ in Ok[impl]
94
+ [impl, []]
95
+
96
+ in Err
97
+ Error::PortNotDecodable
98
+ .new(entry, span, port_name: interop_fn.name, arm:, type:)
99
+ .then { [nil, [it]] }
100
+ end
101
+ end
102
+
103
+ def span_of(type_sym, interop_fn)
104
+ case type_sym
105
+ in Symbol::TypeApplication(span:) then span
106
+ in Symbol::Variable(decl_span:) then decl_span
107
+ else interop_fn.return_type.span
108
+ end
109
+ end
110
+
111
+ def pass_through?(type_sym)
112
+ case type_sym
113
+ in Symbol::TypeApplication(constructor: Symbol::TypeRef(module_name:, name:))
114
+ [module_name, name] in ['Basics', 'Never'] | ['Decode', 'Value']
115
+
116
+ else
117
+ false
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,41 @@
1
+ module Jade
2
+ module Frontend
3
+ module TypeChecking
4
+ Result = Data.define(:type, :constraints) do
5
+ def self.init(type, constraints = [])
6
+ new(type, constraints)
7
+ end
8
+
9
+ def apply(substitution)
10
+ with(type: substitution.apply(type))
11
+ .with(constraints: constraints.map { substitution.apply(it) })
12
+ end
13
+
14
+ def map(&block)
15
+ block
16
+ .call(type)
17
+ .then { with(type: it) }
18
+ end
19
+
20
+ def attach_origin(node)
21
+ constraints
22
+ .map { it.with(origin: node) }
23
+ .then { with(constraints: it) }
24
+ end
25
+
26
+ def self.accumulator
27
+ ResultAcc[[], []]
28
+ end
29
+ end
30
+
31
+ ResultAcc = Data.define(:types, :constraints) do
32
+ def add(result)
33
+ with(
34
+ types: types + [result.type],
35
+ constraints: constraints + result.constraints,
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,20 @@
1
+ module Jade
2
+ module Frontend
3
+ module TypeChecking
4
+ Scheme = Data.define(:quantified, :type, :constraints) do
5
+ def unbound_vars
6
+ type.unbound_vars
7
+ end
8
+
9
+ def free_vars
10
+ type.unbound_vars - quantified
11
+ end
12
+
13
+ def self.mono(type)
14
+ Scheme[[], type, []]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,52 @@
1
+ module Jade
2
+ module Frontend
3
+ module TypeChecking
4
+ State = Data.define(:env, :errors, :skip_constraints) do
5
+ def self.init(env, skip_constraints: false)
6
+ new(env, [], skip_constraints)
7
+ end
8
+
9
+ def unify_result(result, right, rigid_vars = [], &block)
10
+ unify(result.type, right, rigid_vars, &block)
11
+ .then { [it, result.apply(it.env.substitution)] }
12
+ end
13
+
14
+ def unify(left, right, rigid_vars = [], &block)
15
+ applied_left = env.substitution.apply(left)
16
+ applied_right = env.substitution.apply(right)
17
+
18
+ case Unification.unify(applied_left, applied_right, env, Unification::Context[rigid_vars])
19
+ in Ok(sub)
20
+ with(env: env.composose_substitution(sub))
21
+
22
+ in Err(error)
23
+ with(
24
+ env: env.composose_substitution(error.partial_sub),
25
+ errors: errors + [block.call(error)],
26
+ )
27
+ end
28
+ end
29
+
30
+ def add_errors(more_errors)
31
+ with(errors: errors + more_errors)
32
+ end
33
+
34
+ def fresh
35
+ env.fresh
36
+ end
37
+
38
+ def bind(key, value)
39
+ with(env: env.bind(key, value))
40
+ end
41
+
42
+ def to_result
43
+ if errors.any?
44
+ Err[errors]
45
+ else
46
+ Ok[env]
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,93 @@
1
+ module Jade
2
+ module Frontend
3
+ module TypeChecking
4
+ Substitution = Data.define(:mappings) do
5
+ def initialize(mappings: {})
6
+ super
7
+ end
8
+
9
+ def empty?
10
+ mappings.empty?
11
+ end
12
+
13
+ def self.empty
14
+ EMPTY
15
+ end
16
+
17
+ def apply(type)
18
+ case type
19
+ in Type::Constraint(type: constraint_type)
20
+ type.with(type: apply(constraint_type))
21
+
22
+ in Type::Function(args:, return_type:)
23
+ type.with(
24
+ args: args.map { apply(it) },
25
+ return_type: apply(return_type),
26
+ )
27
+
28
+ in Type::Constructor
29
+ type
30
+
31
+ in Type::Var(id:)
32
+ mapping = mappings[id]
33
+
34
+ return type unless mapping
35
+
36
+ case mapping
37
+ in Type::Var(id: ^id)
38
+ mapping
39
+
40
+ else
41
+ apply(mapping)
42
+ end
43
+
44
+ in Type::PartialApplication(constructor:, args:)
45
+ type.with(constructor: apply(constructor), args: args.map { apply(it) })
46
+
47
+ in Type::Application(args:)
48
+ case apply(type.constructor)
49
+ in Type::PartialApplication(constructor:, args: tail_args)
50
+ Type::Application[constructor, args.map { apply(it) } + tail_args]
51
+
52
+ in constructor
53
+ type.with(constructor:, args: args.map { apply(it) })
54
+ end
55
+
56
+ in Type::AnonymousRecord(fields:, row_var:)
57
+ applied_fields = fields.transform_values { apply(it) }
58
+
59
+ return type.with(fields: applied_fields) if type.closed?
60
+
61
+ case apply(row_var)
62
+ in Type::AnonymousRecord(fields: extra_fields, row_var: new_row_var)
63
+ Type.anonymous_record(applied_fields.merge(extra_fields), new_row_var)
64
+
65
+ in Type::Var => applied_row_var
66
+ type.with(fields: applied_fields, row_var: applied_row_var)
67
+
68
+ in Type::Application => struct
69
+ # `{γ | fields}` whose row resolved to a nominal struct
70
+ # collapses to the struct — the open record was always a
71
+ # structural query against it.
72
+ struct
73
+
74
+ end
75
+ end
76
+ end
77
+
78
+ def bind(name, type)
79
+ with(mappings: mappings.merge(name => type))
80
+ end
81
+
82
+ def compose(other)
83
+ return self if other.mappings.empty?
84
+ return other if mappings.empty?
85
+
86
+ Substitution[mappings.merge(other.mappings)]
87
+ end
88
+ end
89
+
90
+ Substitution::EMPTY = Substitution[{}].freeze
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,282 @@
1
+ module Jade
2
+ module Frontend
3
+ module TypeChecking
4
+ module Unification
5
+ extend self
6
+
7
+ Context = Data.define(:rigid_vars) do
8
+ def self.empty
9
+ new([])
10
+ end
11
+
12
+ def rigid?(type)
13
+ rigid_ids = rigid_vars.map(&:id).to_set
14
+ type.unbound_vars.any? { rigid_ids.include?(it.id) }
15
+ end
16
+ end
17
+
18
+ def unify(type1, type2, env, ctx = Context.empty)
19
+ return Ok[Substitution::EMPTY] if never?(type1) || never?(type2)
20
+
21
+ case [type1, type2]
22
+ in [Type::Application, Type::Application]
23
+ case [type1.constructor, type2.constructor]
24
+ in [Type::Var, _] if type1.args.length < type2.args.length
25
+ unify_partial(type1, type2, env, ctx)
26
+ .map_error { UnificationError.new(type1, type2) }
27
+
28
+ in [_, Type::Var] if type2.args.length < type1.args.length
29
+ unify_partial(type2, type1, env, ctx)
30
+ .map_error { UnificationError.new(type1, type2) }
31
+
32
+ else
33
+ unify(type1.constructor, type2.constructor, env, ctx)
34
+ .map_error { UnificationError.new(type1, type2) }
35
+ .and_then do |cons|
36
+ unify_many(type1.args.map { cons.apply(it) }, type2.args.map { cons.apply(it) }, env, ctx)
37
+ .map_both { cons.compose(it) }
38
+ .map_error do |final_sub|
39
+ UnificationError.new(
40
+ final_sub.apply(type1),
41
+ final_sub.apply(type2),
42
+ )
43
+ end
44
+ end
45
+ end
46
+
47
+ in [Type::Var, _]
48
+ return Ok[Substitution::EMPTY] if type1 == type2
49
+
50
+ if ctx.rigid?(type1)
51
+ if type2.is_a?(Type::Var) && !ctx.rigid?(type2)
52
+ return Err[UnificationError.new(type2, type1)] if occurs_in?(type2, type1)
53
+
54
+ return Ok[Substitution::EMPTY.bind(type2.id, type1)]
55
+ end
56
+
57
+ return Err[UnificationError.new(type1, type2)]
58
+ end
59
+
60
+ return Err[UnificationError.new(type1, type2)] if occurs_in?(type1, type2)
61
+
62
+ Ok[Substitution::EMPTY.bind(type1.id, type2)]
63
+
64
+ in [_, Type::Var]
65
+ unify(type2, type1, env, ctx)
66
+ .map_error(&:flip)
67
+
68
+ in [Type::Function, Type::Function]
69
+ unless type1.args.size == type2.args.size
70
+ return Err[UnificationError.new(type1, type2)]
71
+ end
72
+
73
+ unify_many(type1.args, type2.args, env, ctx)
74
+ .then do |args_r|
75
+ args_sub = substitution_of(args_r)
76
+ unify(args_sub.apply(type1.return_type), args_sub.apply(type2.return_type), env, ctx)
77
+ .on_err { args_r.and_then { Err[it] } }
78
+ .and_then { |sub| args_r.map_both { it.compose(sub) } }
79
+ end
80
+ .map_error do |final_sub|
81
+ UnificationError.new(
82
+ final_sub.apply(type1),
83
+ final_sub.apply(type2),
84
+ final_sub,
85
+ )
86
+ end
87
+
88
+ in [Type::Constructor, Type::Constructor]
89
+ type1 == type2 ?
90
+ Ok[Substitution::EMPTY] :
91
+ Err[UnificationError.new(type1, type2)]
92
+
93
+ in [Type::AnonymousRecord, Type::AnonymousRecord]
94
+ f1 = type1.field_names
95
+ f2 = type2.field_names
96
+
97
+ if type1.closed? && (f2 - f1).any?
98
+ return Err[UnificationError.new(type1, type2)]
99
+ end
100
+
101
+ if type2.closed? && (f1 - f2).any?
102
+ return Err[UnificationError.new(type1, type2)]
103
+ end
104
+
105
+ unify_shared_fields(type1, type2, env, ctx)
106
+ .map_error do |final_sub|
107
+ UnificationError.new(
108
+ final_sub.apply(type1),
109
+ final_sub.apply(type2),
110
+ )
111
+ end
112
+ .and_then do |fields_r|
113
+ if type1.open? && type2.open?
114
+ fresh_type = env.fresh
115
+
116
+ Type
117
+ .anonymous_record(type1.fields.merge(type2.fields), env.fresh)
118
+ .then { Substitution::EMPTY.bind(fresh_type.id, it)}
119
+ .bind(type1.row_var.id, fresh_type)
120
+ .bind(type2.row_var.id, fresh_type)
121
+ .compose(fields_r)
122
+ .then { Ok[it] }
123
+
124
+ elsif type1.open?
125
+ unify(type1.row_var, type2, env, ctx)
126
+ .map { fields_r.compose(it) }
127
+
128
+ elsif type2.open?
129
+ unify(type2.row_var, type1, env, ctx)
130
+ .map { fields_r.compose(it) }
131
+
132
+ else
133
+ Ok[fields_r]
134
+ end
135
+ end
136
+
137
+ in [Type::AnonymousRecord, Type::Application]
138
+ # Only OPEN anon records (record-access queries like `{a | x: T}`)
139
+ # can match a nominal struct. Closed records are distinct types.
140
+ return Err[UnificationError.new(type1, type2)] if type1.closed?
141
+
142
+ expanded = env.lookup_def(type2.constructor.name)
143
+
144
+ return Err[UnificationError.new(type1, type2)] unless expanded.is_a?(StructDef)
145
+
146
+ expanded
147
+ .type_params.map(&:id).zip(type2.args).to_h
148
+ .reduce(Substitution::EMPTY) do |acc, (k, v)|
149
+ acc.bind(k, v)
150
+ end
151
+ .apply(expanded.body)
152
+ .then { unify(type1, it, env, ctx) }
153
+ .and_then do |body_r|
154
+ unify(type1.row_var, type2, env, ctx).map { body_r.compose(it) }
155
+ end
156
+ .on_err { Err[UnificationError.new(type1, type2)] }
157
+
158
+
159
+ in [Type::Application, Type::AnonymousRecord]
160
+ unify(type2, type1, env, ctx)
161
+ .map_error(&:flip)
162
+
163
+ else
164
+ Err[UnificationError.new(type1, type2)]
165
+ end
166
+ end
167
+
168
+ private
169
+
170
+ def never?(type)
171
+ case type
172
+ in Type::Application(constructor: Type::Constructor(name: 'Basics.Never'))
173
+ true
174
+ else
175
+ false
176
+ end
177
+ end
178
+
179
+ def occurs_in?(var, type)
180
+ case type
181
+ in Type::Var(id:)
182
+ var.id == id
183
+
184
+ in Type::Application(args:)
185
+ occurs_in?(var, type.constructor) || args.any? { occurs_in?(var, it) }
186
+
187
+ in Type::Function(args:, return_type:)
188
+ args.any? { occurs_in?(var, it) } || occurs_in?(var, return_type)
189
+
190
+ in Type::PartialApplication(constructor:, args:)
191
+ occurs_in?(var, constructor) || args.any? { occurs_in?(var, it) }
192
+
193
+ in Type::Constraint(type: inner)
194
+ occurs_in?(var, inner)
195
+
196
+ in Type::AnonymousRecord(fields:, row_var:)
197
+ fields.values.any? { occurs_in?(var, it) } ||
198
+ (row_var ? occurs_in?(var, row_var) : false)
199
+
200
+ in Type::Constructor | Type::TypeUnit
201
+ false
202
+ end
203
+ end
204
+
205
+ def substitution_of(result)
206
+ case result
207
+ in Ok(sub) then sub
208
+ in Err(sub) then sub
209
+ end
210
+ end
211
+
212
+ def unify_partial(var_side, concrete_side, env, ctx)
213
+ head, *tail = concrete_side.args
214
+ partial_c = tail.empty? ? concrete_side.constructor : Type::PartialApplication[concrete_side.constructor, tail]
215
+
216
+ unify(var_side.constructor, partial_c, env, ctx)
217
+ .and_then do |cons|
218
+ unify_many(var_side.args.map { cons.apply(it) }, [cons.apply(head)], env, ctx)
219
+ .map_both { cons.compose(it) }
220
+ end
221
+ end
222
+
223
+ def unify_shared_fields(type1, type2, env, ctx)
224
+ shared_fields = type1.field_names & type2.field_names
225
+ fields1 = type1.fields
226
+ fields2 = type2.fields
227
+
228
+ shared_fields
229
+ .reduce(Ok[Substitution::EMPTY]) do |subs_r, key|
230
+ sub = substitution_of(subs_r)
231
+
232
+ case unify(fields1[key], fields2[key], env, ctx)
233
+ in Err
234
+ next subs_r.and_then { Err[it] }
235
+ in Ok(k_sub)
236
+ subs_r.map_both { it.compose(k_sub) }
237
+ end
238
+ end
239
+ end
240
+
241
+ def unify_many(types1, types2, env, ctx)
242
+ types1
243
+ .zip(types2)
244
+ .reduce(Ok[Substitution::EMPTY]) do |subs_r, args|
245
+ args_r = args
246
+ .map { substitution_of(subs_r).apply(it) }
247
+ .then { unify(*it, env, ctx) }
248
+
249
+ case args_r
250
+ in Err
251
+ next subs_r.and_then { Err[it] }
252
+
253
+ in Ok(arg_sub)
254
+ subs_r.map_both { it.compose(arg_sub) }
255
+ end
256
+ end
257
+ end
258
+
259
+ class UnificationError
260
+ attr_reader :expected, :actual, :partial_sub
261
+
262
+ def initialize(actual, expected, partial_sub = nil)
263
+ @actual = actual
264
+ @expected = expected
265
+ @partial_sub = partial_sub || Substitution::EMPTY
266
+ end
267
+
268
+ def flip
269
+ old_expected = @expected
270
+ @expected = @actual
271
+ @actual = old_expected
272
+ self
273
+ end
274
+
275
+ def message
276
+ "Cannot unify #{expected} with #{actual}"
277
+ end
278
+ end
279
+ end
280
+ end
281
+ end
282
+ end
@@ -0,0 +1,33 @@
1
+ module Jade
2
+ module Frontend
3
+ module TypeChecking
4
+ # Type-var ids must be unique across every scheme that ever flows
5
+ # through unification. Per-instance counters made cross-module
6
+ # imports fragile: a fresh id from one module could equal a
7
+ # quantified id from another, aliasing them through
8
+ # Substitution.apply. A class-level counter makes collisions
9
+ # impossible by construction.
10
+ class VarGen
11
+ @counter = 0
12
+
13
+ class << self
14
+ attr_accessor :counter
15
+ end
16
+
17
+ def fresh_id
18
+ "t#{self.class.counter += 1}"
19
+ end
20
+
21
+ def fresh(name = nil)
22
+ fresh_id
23
+ .then { Type.var(it, name) }
24
+ end
25
+
26
+ def next(name)
27
+ "#{name}#{self.class.counter += 1}"
28
+ .then { Type.var(it, name) }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end