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,57 @@
1
+ module Jade
2
+ module Codegen
3
+ module Pattern
4
+ module Constructor
5
+ extend self
6
+ extend Helpers
7
+
8
+ def generate(node, registry)
9
+ node => AST::Pattern::Constructor(symbol:, patterns:)
10
+ constructor = registry.lookup(symbol)
11
+ qualified = to_qualified(constructor.qualified_name)
12
+
13
+ if keyed_variant?(constructor)
14
+ generate_keyed(qualified, patterns.first, registry)
15
+ else
16
+ generate_positional(qualified, patterns, registry)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def keyed_variant?(constructor)
23
+ constructor.args in [Symbol::RecordType]
24
+ end
25
+
26
+ def generate_positional(qualified, patterns, registry)
27
+ patterns
28
+ .map { generate_node(it, registry) }
29
+ .join(', ')
30
+ .then { it.empty? ? it : "(#{it})" }
31
+ .then { "#{qualified}#{it}" }
32
+ end
33
+
34
+ # Keyed variants have a single inner pattern that conceptually matches
35
+ # the record-shaped payload. The runtime class itself carries the
36
+ # record's fields, so we project the pattern onto the variant directly:
37
+ # binding/wildcard captures the whole instance; record patterns
38
+ # destructure via Ruby's Data deconstruct_keys.
39
+ def generate_keyed(qualified, pattern, registry)
40
+ case pattern
41
+ in AST::Pattern::Binding(name:)
42
+ "#{qualified} => #{name}"
43
+
44
+ in AST::Pattern::Wildcard
45
+ qualified
46
+
47
+ in AST::Pattern::Record(fields:)
48
+ fields
49
+ .map { generate_node(it, registry) }
50
+ .join(', ')
51
+ .then { "#{qualified}(#{it})" }
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,77 @@
1
+ module Jade
2
+ module Codegen
3
+ module PortDecoder
4
+ extend self
5
+
6
+ PASS = "Jade::Decode::Decoder[Jade::Decode::Desc::Pass[]]"
7
+
8
+ # `dictionaries` is the call site's constraint-attachment list; only
9
+ # used when an arm is a Dict marker.
10
+ def task_call(interop_fn, registry, dictionaries = [])
11
+ [
12
+ interop_fn.interop_module_name,
13
+ ":#{interop_fn.name}",
14
+ decoder(interop_fn, :ok, registry, dictionaries),
15
+ decoder(interop_fn, :err, registry, dictionaries),
16
+ ]
17
+ .join(', ')
18
+ .then { "Jade::Runtime.task_call(#{it})" }
19
+ end
20
+
21
+ private
22
+
23
+ # Per-arm decoder. PortResolution stamps one of:
24
+ # - :pass — Decode.Value or Never arm, no decoder needed
25
+ # - Symbol::Implementation — concrete OR partial impl (with marker
26
+ # deps for free vars). We push a synthetic dict_env mapping the
27
+ # port's vars to the call-site dictionaries so generate_impl_dispatch
28
+ # can resolve markers uniformly.
29
+ # - Symbol::InteropFunction::Dict — bare-var arm, decoder comes
30
+ # from the caller's threaded dictionary at the given constraint index
31
+ def decoder(interop_fn, arm, registry, dictionaries)
32
+ case interop_fn.decoders.fetch(arm)
33
+ in Symbol::InteropFunction::PASS
34
+ PASS
35
+
36
+ in Symbol::Implementation => impl
37
+ emit_impl_decoder(impl, interop_fn, dictionaries, registry)
38
+
39
+ in Symbol::InteropFunction::Dict(constraint_index:)
40
+ "#{FunctionCall.dispatch_value(dictionaries.fetch(constraint_index), registry)}[\"decoder\"]"
41
+ end
42
+ end
43
+
44
+ def emit_impl_decoder(impl, interop_fn, dictionaries, registry)
45
+ synthetic_env = build_synthetic_dict_env(impl, interop_fn, dictionaries, registry)
46
+
47
+ Codegen.with_dict_env(synthetic_env) {
48
+ FunctionCall.generate_impl_dispatch(impl, registry).fetch('decoder')
49
+ }
50
+ end
51
+
52
+ # Maps [iface, port_var_id] → ruby expression for the call-site dict.
53
+ # For concrete impls (no markers) this is empty — generate_impl_dispatch
54
+ # never reads dict_env. For partial impls, each marker dep's Type::Var
55
+ # gets resolved to the dictionaries[i] corresponding to its name.
56
+ def build_synthetic_dict_env(impl, interop_fn, dictionaries, registry)
57
+ collect_marker_vars(impl).to_h do |iface, var|
58
+ idx = interop_fn.constraints.index { |i, n| i == iface && n == var.name }
59
+ [[iface, var.id], FunctionCall.dispatch_value(dictionaries.fetch(idx), registry)]
60
+ end
61
+ end
62
+
63
+ def collect_marker_vars(impl, acc = [])
64
+ impl.deps.each do |dep|
65
+ case dep
66
+ in Symbol::Implementation
67
+ collect_marker_vars(dep, acc)
68
+
69
+ in Type::Constraint(interface:, type: Type::Var => var)
70
+ acc << [interface, var]
71
+ end
72
+ end
73
+ acc.uniq { |iface, var| [iface, var.id] }
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,53 @@
1
+ module Jade
2
+ module Codegen
3
+ module Pretty
4
+ extend self
5
+
6
+ INDENT = " "
7
+
8
+ def newline(count = 1)
9
+ "\n" * count
10
+ end
11
+
12
+ def indent(str, levels = 1)
13
+ str.gsub(/^(?!$)/, INDENT * levels)
14
+ end
15
+
16
+ def block(header, body, footer = "end")
17
+ body.empty? ? "#{header}\n#{footer}" : "#{header}\n#{indent(body)}\n#{footer}"
18
+ end
19
+
20
+ def lambda(params, body)
21
+ multiline?(body) ? block("->(#{params}) {", body, "}") : "->(#{params}) { #{body} }"
22
+ end
23
+
24
+ def hash(pairs)
25
+ pairs
26
+ .map { |k, v| "#{k.inspect} => #{v}" }
27
+ .join(', ')
28
+ .then { "{ #{it} }" }
29
+ end
30
+
31
+ def array(items)
32
+ "[#{items.join(', ')}]"
33
+ end
34
+
35
+ # `callee(a, b, c)` on one line when it fits, multi-line with trailing
36
+ # comma when it doesn't or when an arg is already multi-line. Pass
37
+ # `open:`/`close:` to emit `Struct[a, b, c]`-shaped construction.
38
+ def call(callee, args, width: 80, open: '(', close: ')')
39
+ "#{callee}#{open}#{args.join(', ')}#{close}".then do |oneline|
40
+ if oneline.length <= width && args.none? { multiline?(it) }
41
+ oneline
42
+ else
43
+ "#{callee}#{open}\n#{indent(args.join(",\n"))},\n#{close}"
44
+ end
45
+ end
46
+ end
47
+
48
+ def multiline?(str)
49
+ str.include?("\n")
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,222 @@
1
+ module Jade
2
+ module Codegen
3
+ module Transforms
4
+ module FoldShape
5
+ extend self
6
+ extend Helpers
7
+
8
+ ACC_NAME = '__fold_acc__'
9
+
10
+ # The right-fold shape:
11
+ #
12
+ # def f(xs) ->
13
+ # case xs
14
+ # of [] -> BASE (no self-call)
15
+ # of [h | rest] -> COMBINE (exactly one f(rest), strict)
16
+ #
17
+ # Returns a shape hash, or nil if the body doesn't match.
18
+ def shape_for(body, self_sym, param_names, registry)
19
+ return nil unless param_names.size == 1
20
+
21
+ sig = [self_sym, 1]
22
+ expr = unwrap_body(body)
23
+ return nil unless expr.is_a?(AST::CaseOf)
24
+ return nil unless expr.branches.size == 2
25
+
26
+ list_arg = param_names.first
27
+ return nil unless subject_is_arg?(expr.expression, list_arg)
28
+
29
+ empty_branch = expr.branches.find { empty_list_pattern?(it.pattern) }
30
+ cons_branch = expr.branches.find { cons_pattern?(it.pattern) }
31
+ return nil unless empty_branch && cons_branch
32
+ return nil if SelfCall.contains_self_call?(
33
+ empty_branch.body, sig, registry
34
+ )
35
+
36
+ head_name = head_binding_name(cons_branch.pattern)
37
+ rest_name = rest_binding_name(cons_branch.pattern)
38
+ return nil unless head_name && rest_name
39
+
40
+ calls = strict_self_calls(cons_branch.body, sig, registry)
41
+ return nil unless calls&.size == 1
42
+
43
+ call = calls.first
44
+ return nil unless call.args.size == 1
45
+
46
+ arg = call.args.first
47
+ return nil unless arg in AST::VariableReference(name: ^rest_name)
48
+ return nil unless rest_used_only?(cons_branch.body, rest_name, call)
49
+
50
+ {
51
+ list_arg: list_arg,
52
+ base: empty_branch.body,
53
+ head_name: head_name,
54
+ combine: cons_branch.body,
55
+ self_call: call,
56
+ }
57
+ end
58
+
59
+ # Emits `xs.reverse.reduce(BASE) { |acc, head| COMBINE' }`. The
60
+ # `reverse` gives right-associative combine order regardless of the
61
+ # combiner's algebraic properties. Task effects are unaffected by
62
+ # build order — only the final Task chain shape determines run-time
63
+ # behavior.
64
+ def generate_body(shape, registry)
65
+ shape => { list_arg:, base:, head_name:, combine:, self_call: }
66
+
67
+ base_code = generate_node(base, registry)
68
+ combine_code = substitute(combine, self_call)
69
+ .then { generate_node(it, registry) }
70
+
71
+ "#{list_arg}.reverse.reduce(#{base_code}) " \
72
+ "{ |#{ACC_NAME}, #{head_name}| #{combine_code} }"
73
+ end
74
+
75
+ private
76
+
77
+ def unwrap_body(node)
78
+ case node
79
+ in AST::Body(expressions: [single]) then unwrap_body(single)
80
+ in AST::Grouping(expression:) then unwrap_body(expression)
81
+ else node
82
+ end
83
+ end
84
+
85
+ def subject_is_arg?(expression, arg_name)
86
+ expression in AST::VariableReference(name: ^arg_name)
87
+ end
88
+
89
+ def empty_list_pattern?(pattern)
90
+ pattern in AST::Pattern::List(patterns: [], rest: nil)
91
+ end
92
+
93
+ # Only binding/wildcard heads qualify. Literal or constructor heads
94
+ # (`[True | rest]`, `[1 | rest]`) make the source function partial
95
+ # over the head; folding it would silently widen it to total.
96
+ def cons_pattern?(pattern)
97
+ case pattern
98
+ in AST::Pattern::List(
99
+ patterns: [AST::Pattern::Binding | AST::Pattern::Wildcard],
100
+ rest: AST::Pattern::Binding
101
+ ) then true
102
+ else false
103
+ end
104
+ end
105
+
106
+ def rest_binding_name(pattern)
107
+ case pattern
108
+ in AST::Pattern::List(rest: AST::Pattern::Binding(name:)) then name
109
+ else nil
110
+ end
111
+ end
112
+
113
+ def head_binding_name(pattern)
114
+ case pattern
115
+ in AST::Pattern::List(patterns: [AST::Pattern::Binding(name:)])
116
+ name
117
+
118
+ in AST::Pattern::List(patterns: [AST::Pattern::Wildcard])
119
+ '_'
120
+
121
+ else
122
+ nil
123
+ end
124
+ end
125
+
126
+ # The emitted block binds only `head` and `acc` — not `rest`. Any
127
+ # reference to `rest` in COMBINE outside the chosen self-call's
128
+ # argument would emit unbound Ruby.
129
+ def rest_used_only?(node, rest_name, call)
130
+ return true if node.equal?(call)
131
+ return false if node in AST::VariableReference(name: ^rest_name)
132
+
133
+ SelfCall.child_values(node)
134
+ .all? { rest_check_value(it, rest_name, call) }
135
+ end
136
+
137
+ def rest_check_value(value, rest_name, call)
138
+ case value
139
+ when Array then value.all? { rest_check_value(it, rest_name, call) }
140
+ when AST::Node then rest_used_only?(value, rest_name, call)
141
+ else true
142
+ end
143
+ end
144
+
145
+ # Collects self-calls in strict (always-evaluated) positions. Returns
146
+ # nil when any self-call sits in a lazy position — a Lambda body,
147
+ # an If branch, or a Case branch body — because `reduce` walks every
148
+ # element unconditionally and can't skip or duplicate the recursive
149
+ # step the way the source might.
150
+ def strict_self_calls(node, sig, registry)
151
+ deep = ->(n) {
152
+ SelfCall.contains_self_call_anywhere?(n, sig, registry)
153
+ }
154
+
155
+ case node
156
+ in AST::FunctionCall if SelfCall.self_call?(node, sig, registry)
157
+ return nil if node.args.any? { deep.call(it) }
158
+ [node]
159
+
160
+ in AST::Lambda
161
+ deep.call(node) ? nil : []
162
+
163
+ in AST::IfThenElse(condition:, if_branch:, else_branch:)
164
+ return nil if deep.call(if_branch)
165
+ return nil if deep.call(else_branch)
166
+ strict_self_calls(condition, sig, registry)
167
+
168
+ in AST::CaseOf(expression:, branches:)
169
+ return nil if branches.any? { deep.call(it.body) }
170
+ strict_self_calls(expression, sig, registry)
171
+
172
+ else
173
+ SelfCall.child_values(node)
174
+ .map { collect_strict_value(it, sig, registry) }
175
+ .then { it.any?(&:nil?) ? nil : it.flatten(1) }
176
+ end
177
+ end
178
+
179
+ def collect_strict_value(value, sig, registry)
180
+ case value
181
+ when Array
182
+ value
183
+ .map { collect_strict_value(it, sig, registry) }
184
+ .then { it.any?(&:nil?) ? nil : it.flatten(1) }
185
+ when AST::Node
186
+ strict_self_calls(value, sig, registry)
187
+ else
188
+ []
189
+ end
190
+ end
191
+
192
+ # AST nodes are immutable Data; rebuilds the tree with `target`
193
+ # replaced by a fresh `__fold_acc__` reference.
194
+ def substitute(node, target)
195
+ return acc_var_ref if node.equal?(target)
196
+ return node unless node.is_a?(AST::Node)
197
+
198
+ node
199
+ .to_h
200
+ .transform_values { substitute_value(it, target) }
201
+ .then { node.class.new(**it) }
202
+ end
203
+
204
+ def substitute_value(value, target)
205
+ case value
206
+ when Array then value.map { substitute_value(it, target) }
207
+ when AST::Node then substitute(value, target)
208
+ else value
209
+ end
210
+ end
211
+
212
+ def acc_var_ref
213
+ AST::VariableReference.new(
214
+ name: ACC_NAME,
215
+ symbol: Symbol::Variable.new(name: ACC_NAME, decl_span: nil),
216
+ range: nil,
217
+ )
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,80 @@
1
+ module Jade
2
+ module Codegen
3
+ module Transforms
4
+ # AST-walking primitives for recognizing self-recursive calls. A
5
+ # "self-call signature" is the pair `[self_sym, arity]`: a ValueRef
6
+ # carrying module_name + name, paired with the function's user-declared
7
+ # arity (partial applications never qualify).
8
+ module SelfCall
9
+ extend self
10
+
11
+ METADATA_KEYS = %i[
12
+ range symbol id
13
+ leading_comments trailing_comments dangling_comments
14
+ trailing_comma
15
+ ].freeze
16
+
17
+ # Defensive on `node` — anything that isn't a FunctionCall returns
18
+ # false, so callers don't need to type-check before calling.
19
+ def self_call?(node, sig, registry)
20
+ return false unless node.is_a?(AST::FunctionCall)
21
+
22
+ self_sym, arity = sig
23
+ resolved = resolve(node.callee.symbol, registry)
24
+
25
+ resolved.is_a?(Symbol::Function) &&
26
+ resolved.module_name == self_sym.module_name &&
27
+ resolved.name == self_sym.name &&
28
+ node.args.size == arity
29
+ end
30
+
31
+ # Scope-aware: stops at Lambda boundaries. A self-call inside a
32
+ # lambda body belongs to that lambda, not to the enclosing function.
33
+ def contains_self_call?(node, sig, registry)
34
+ return true if self_call?(node, sig, registry)
35
+ return false if node.is_a?(AST::Lambda)
36
+
37
+ child_descendants(node)
38
+ .any? { contains_self_call?(it, sig, registry) }
39
+ end
40
+
41
+ # Scope-blind: descends into Lambda bodies. For disqualifying any
42
+ # subtree that textually mentions a self-call at any depth.
43
+ def contains_self_call_anywhere?(node, sig, registry)
44
+ return true if self_call?(node, sig, registry)
45
+
46
+ child_descendants(node)
47
+ .any? { contains_self_call_anywhere?(it, sig, registry) }
48
+ end
49
+
50
+ def child_values(node)
51
+ node
52
+ .to_h
53
+ .reject { |k, _| METADATA_KEYS.include?(k) }
54
+ .values
55
+ end
56
+
57
+ private
58
+
59
+ def resolve(symbol, registry)
60
+ case symbol
61
+ in Symbol::ValueRef => ref then registry.lookup(ref)
62
+ in s then s
63
+ end
64
+ end
65
+
66
+ # Flat list of direct AST::Node descendants, dipping into array
67
+ # fields (e.g. FunctionCall#args) but skipping scalars.
68
+ def child_descendants(node)
69
+ child_values(node).flat_map do |v|
70
+ case v
71
+ when Array then v.grep(AST::Node)
72
+ when AST::Node then [v]
73
+ else []
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,120 @@
1
+ module Jade
2
+ module Codegen
3
+ module Transforms
4
+ module TailCall
5
+ extend self
6
+ extend Helpers
7
+
8
+ def tail_recursive?(body, self_sym, arity, registry)
9
+ classify(body, [self_sym, arity], registry) == :tail
10
+ end
11
+
12
+ def generate_body(body, registry, self_sym, param_names)
13
+ [self_sym, param_names.size]
14
+ .then { emit_tail(body, registry, it, param_names) }
15
+ .then { Pretty.block("loop do", it) }
16
+ end
17
+
18
+ private
19
+
20
+ def classify(node, sig, registry)
21
+ has_self = ->(n) { SelfCall.contains_self_call?(n, sig, registry) }
22
+
23
+ case node
24
+ in AST::FunctionCall if SelfCall.self_call?(node, sig, registry)
25
+ node.args.any? { has_self.call(it) } ? :non_tail : :tail
26
+
27
+ in AST::Body(expressions:)
28
+ *leading, last = expressions
29
+ if leading.any? { has_self.call(it) }
30
+ :non_tail
31
+ else
32
+ classify(last, sig, registry)
33
+ end
34
+
35
+ in AST::IfThenElse(condition:, if_branch:, else_branch:)
36
+ if has_self.call(condition)
37
+ :non_tail
38
+ else
39
+ combine(
40
+ classify(if_branch, sig, registry),
41
+ classify(else_branch, sig, registry),
42
+ )
43
+ end
44
+
45
+ in AST::CaseOf(expression:, branches:)
46
+ if has_self.call(expression)
47
+ :non_tail
48
+ else
49
+ branches
50
+ .map { classify(it.body, sig, registry) }
51
+ .reduce(:none) { |acc, c| combine(acc, c) }
52
+ end
53
+
54
+ in AST::Grouping(expression:)
55
+ classify(expression, sig, registry)
56
+
57
+ else
58
+ has_self.call(node) ? :non_tail : :none
59
+ end
60
+ end
61
+
62
+ def combine(a, b)
63
+ return :non_tail if a == :non_tail || b == :non_tail
64
+ return :tail if a == :tail || b == :tail
65
+ :none
66
+ end
67
+
68
+ def emit_tail(node, registry, sig, params)
69
+ case node
70
+ in AST::FunctionCall if SelfCall.self_call?(node, sig, registry)
71
+ node.args
72
+ .map { generate_node(it, registry) }
73
+ .join(', ')
74
+ .then { "#{params.join(', ')} = #{it}" }
75
+
76
+ in AST::Body(expressions:)
77
+ *leading, last = expressions
78
+ [
79
+ *leading.map { generate_node(it, registry) },
80
+ emit_tail(last, registry, sig, params),
81
+ ].join("\n")
82
+
83
+ in AST::IfThenElse(condition:, if_branch:, else_branch:)
84
+ [
85
+ "if (#{generate_node(condition, registry)})",
86
+ Pretty.indent(emit_tail(if_branch, registry, sig, params)),
87
+ "else",
88
+ Pretty.indent(emit_tail(else_branch, registry, sig, params)),
89
+ "end",
90
+ ].join("\n")
91
+
92
+ in AST::CaseOf(expression:, branches:)
93
+ subject = generate_node(expression, registry)
94
+ branches
95
+ .map { emit_tail_branch(it, registry, sig, params) }
96
+ .join("\n")
97
+ .then { "case #{subject}\n#{it}\nend" }
98
+
99
+ in AST::Grouping(expression:)
100
+ emit_tail(expression, registry, sig, params)
101
+
102
+ else
103
+ "break #{generate_node(node, registry)}"
104
+ end
105
+ end
106
+
107
+ def emit_tail_branch(branch, registry, sig, params)
108
+ pat = generate_node(branch.pattern, registry)
109
+ body = emit_tail(branch.body, registry, sig, params)
110
+
111
+ if Pretty.multiline?(body)
112
+ "in #{pat} then\n#{Pretty.indent(body)}"
113
+ else
114
+ "in #{pat} then #{body}"
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,41 @@
1
+ module Jade
2
+ module Codegen
3
+ module VariantDeclaration
4
+ extend self
5
+ extend Helpers
6
+
7
+ def generate(node, sibling_names)
8
+ node => AST::VariantDeclaration(name:, args:, symbol:)
9
+
10
+ impls = symbol.qualified_name
11
+ .then { "::#{to_qualified(it)}" }
12
+ .then { Codegen.dispatched_methods[it] || [] }
13
+
14
+ sibling_names
15
+ .map { |s| "def #{predicate_name(s)}; #{s == name}; end" }
16
+ .then { [it.join(Pretty.newline), *impls] }
17
+ .reject(&:empty?)
18
+ .join(Pretty.newline(2))
19
+ .then { Pretty.block("#{name} = #{data_define(fields_for(args))} do", it) }
20
+ end
21
+
22
+ private
23
+
24
+ def fields_for(args)
25
+ case args
26
+ in [AST::TypeRecord(fields:)]
27
+ fields.keys
28
+ else
29
+ args.map.with_index { |_, i| "_#{i + 1}" }
30
+ end
31
+ end
32
+
33
+ def predicate_name(variant_name)
34
+ variant_name
35
+ .gsub(/([a-z])([A-Z])/, '\1_\2')
36
+ .downcase
37
+ .then { "#{it}?" }
38
+ end
39
+ end
40
+ end
41
+ end