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,542 @@
1
+ require 'uri'
2
+
3
+ module Jade
4
+ module LSP
5
+ module Converters
6
+ extend self
7
+
8
+ # Byte offsets, not UTF-16 code units. Matches the `utf-8` position
9
+ # encoding negotiated at initialize; under the default `utf-16`,
10
+ # columns drift right by N for each multi-byte char on the line.
11
+ def offset_to_position(source, offset)
12
+ line = source.line_starts.rindex { it <= offset } || 0
13
+ { line:, character: offset - source.line_starts[line] }
14
+ end
15
+
16
+ def position_to_offset(source, line, character)
17
+ source.line_starts[line] + character
18
+ end
19
+
20
+ def span_to_range(source, span)
21
+ {
22
+ start: offset_to_position(source, span.begin),
23
+ end: offset_to_position(source, span.end),
24
+ }
25
+ end
26
+
27
+ SEVERITY = { error: 1, warning: 2, info: 3, hint: 4 }.freeze
28
+
29
+ SYMBOL_KIND = {
30
+ function: 12,
31
+ enum: 10,
32
+ enum_member: 22,
33
+ struct: 23,
34
+ interface: 11,
35
+ }.freeze
36
+
37
+ HOVERABLE_SYMBOLS = [
38
+ Jade::Symbol::Function,
39
+ Jade::Symbol::StdlibFunction,
40
+ Jade::Symbol::InteropFunction,
41
+ Jade::Symbol::InterfaceFunction,
42
+ Jade::Symbol::Constructor,
43
+ Jade::Symbol::Variant,
44
+ Jade::Symbol::Union,
45
+ Jade::Symbol::Struct,
46
+ ].freeze
47
+
48
+ # LSP CompletionItemKind values we use.
49
+ COMPLETION_KIND_SNIPPET = 15
50
+ # LSP InsertTextFormat: 1 = PlainText, 2 = Snippet (with tab stops).
51
+ INSERT_FORMAT_SNIPPET = 2
52
+
53
+ def definition_for_path(path, registry, entry, source_root)
54
+ innermost_resolved(path, registry, entry)
55
+ .then { definition_location(it, registry, entry, source_root) }
56
+ end
57
+
58
+ def hover_for_path(path, registry, entry)
59
+ path
60
+ .reverse
61
+ .lazy
62
+ .filter_map { hover_for_node(it, registry, entry) }
63
+ .first
64
+ rescue StandardError
65
+ nil
66
+ end
67
+
68
+ def completion_items
69
+ Snippets::ALL.map do |snippet|
70
+ {
71
+ label: snippet.label,
72
+ kind: COMPLETION_KIND_SNIPPET,
73
+ detail: snippet.detail,
74
+ insertText: snippet.body,
75
+ insertTextFormat: INSERT_FORMAT_SNIPPET,
76
+ }
77
+ end
78
+ end
79
+
80
+ # InlayHintKind: 1 = Type, 2 = Parameter
81
+ INLAY_HINT_TYPE = 1
82
+ INLAY_HINT_PARAMETER = 2
83
+
84
+ def inlay_hints_for(entry, range_offsets)
85
+ return [] unless entry.env
86
+
87
+ collect_inlay_hints(entry.ast, entry, range_offsets)
88
+ end
89
+
90
+ # Re-runs the parse + format pipeline on the buffer text. Returns
91
+ # nil if parsing fails (don't overwrite the user's broken buffer
92
+ # with garbage), an empty array if the text is already formatted,
93
+ # or a single whole-document TextEdit otherwise.
94
+ def format_edits(text)
95
+ source = Jade::Source.new(uri: 'buffer', text:)
96
+
97
+ case Jade::Parsing.parse(Jade::Lexer.tokenize(source), source:)
98
+ in Jade::Ok([ast, comments])
99
+ formatted = Jade::Formatter.format(ast, comments:, source:) + "\n"
100
+ formatted == text ? [] : [whole_document_edit(source, formatted)]
101
+ in Jade::Err
102
+ nil
103
+ end
104
+ end
105
+
106
+ def whole_document_edit(source, new_text)
107
+ last_line = source.line_starts.size - 1
108
+ {
109
+ range: {
110
+ start: { line: 0, character: 0 },
111
+ end: { line: last_line, character: source.text.bytesize - source.line_starts[last_line] },
112
+ },
113
+ newText: new_text,
114
+ }
115
+ end
116
+
117
+ def references_for_path(
118
+ path, registry, entry, source_root, include_declaration:
119
+ )
120
+ symbol = innermost_resolved(path, registry, entry)
121
+ return nil unless symbol
122
+
123
+ refs = usage_locations(symbol, registry, source_root)
124
+ return refs unless include_declaration
125
+
126
+ refs + declaration_locations(symbol, registry, entry, source_root)
127
+ end
128
+
129
+ def prepare_rename_for_path(path, registry, entry, offset)
130
+ node = innermost_resolvable_node(path, registry, entry)
131
+ return nil unless node
132
+
133
+ symbol = resolve_symbol(node, registry, entry)
134
+ return nil unless renameable?(symbol, registry)
135
+
136
+ identifier_span(node, symbol, entry.source)
137
+ .then { it.cover?(offset) ? span_to_range(entry.source, it) : nil }
138
+ end
139
+
140
+ def rename_for_path(path, registry, entry, source_root, new_name)
141
+ symbol = innermost_resolved(path, registry, entry)
142
+ return nil unless renameable?(symbol, registry)
143
+
144
+ rename_edits(symbol, registry, entry, source_root)
145
+ .group_by { it[:uri] }
146
+ .transform_values { it.map { |e| { range: e[:range], newText: new_name } } }
147
+ .then { { changes: it } }
148
+ end
149
+
150
+ def to_document_symbol(node, source)
151
+ case node
152
+ in AST::FunctionDeclaration(name:, range:)
153
+ document_symbol(name, :function, source, range)
154
+
155
+ in AST::TypeDeclaration(name:, range:, variants:)
156
+ document_symbol(
157
+ name, :enum, source, range,
158
+ children: variants.map { variant_symbol(it, source) },
159
+ )
160
+
161
+ in AST::StructDeclaration(name:, range:)
162
+ document_symbol(name, :struct, source, range)
163
+
164
+ in AST::InterfaceDeclaration(name:, range:, functions:)
165
+ document_symbol(
166
+ name, :interface, source, range,
167
+ children: functions.map { interface_fn_symbol(it, source) },
168
+ )
169
+
170
+ else
171
+ nil
172
+ end
173
+ end
174
+
175
+ def diagnostic_to_lsp(diagnostic)
176
+ {
177
+ range: diagnostic.primary.then { span_to_range(it.source, it.span) },
178
+ severity: SEVERITY.fetch(diagnostic.severity, 3),
179
+ source: 'jade',
180
+ message: diagnostic_message(diagnostic),
181
+ }
182
+ end
183
+
184
+ def relative_path(uri, source_root)
185
+ uri
186
+ .sub(%r{\Afile://}, '')
187
+ .then { URI::DEFAULT_PARSER.unescape(it) }
188
+ .then { Pathname.new(it) }
189
+ .then { it.relative_path_from(Pathname.new(source_root)) }
190
+ .then { it.to_s }
191
+ end
192
+
193
+ def lsp_uri(relative_path, source_root)
194
+ File
195
+ .expand_path(File.join(source_root, relative_path))
196
+ .then { URI::DEFAULT_PARSER.escape(it) }
197
+ .then { "file://#{it}" }
198
+ end
199
+
200
+ private
201
+
202
+ def definition_location(symbol, registry, entry, source_root)
203
+ return nil unless symbol&.respond_to?(:decl_span) && symbol.decl_span
204
+
205
+ # Locals (Symbol::Variable) carry no module — they're declared in
206
+ # the file the cursor is in, so resolve against the current entry.
207
+ source =
208
+ if symbol.respond_to?(:module_name)
209
+ registry.modules.fetch(symbol.module_name).source
210
+ else
211
+ entry.source
212
+ end
213
+
214
+ source && build_location(source, symbol.decl_span, source_root)
215
+ end
216
+
217
+ def usage_locations(symbol, registry, source_root)
218
+ registry
219
+ .modules
220
+ .each_value
221
+ .flat_map do |entry|
222
+ next [] unless entry.source && entry.usage_index
223
+
224
+ entry
225
+ .usage_index
226
+ .for(symbol)
227
+ .map { build_location(entry.source, it.range, source_root) }
228
+ end
229
+ end
230
+
231
+ def declaration_locations(symbol, registry, entry, source_root)
232
+ definition_location(symbol, registry, entry, source_root)
233
+ .then { it ? [it] : [] }
234
+ end
235
+
236
+ # Rename targets must have a declaration we can point at AND live
237
+ # in a module whose source we can write back. Stdlib and interop
238
+ # modules are excluded for both reasons. Locals (Symbol::Variable)
239
+ # carry no module — they live in the file the cursor is in.
240
+ def renameable?(symbol, registry)
241
+ return false unless symbol&.respond_to?(:decl_span) && symbol.decl_span
242
+ return true if symbol.is_a?(Jade::Symbol::Variable)
243
+
244
+ registry
245
+ .modules[symbol.module_name]
246
+ .then { it && it.source && !Stdlib.is_stdlib?(it) }
247
+ end
248
+
249
+ def rename_edits(symbol, registry, entry, source_root)
250
+ [decl_edit(symbol, registry, entry, source_root)] +
251
+ usage_edits(symbol, registry, source_root)
252
+ end
253
+
254
+ def decl_edit(symbol, registry, entry, source_root)
255
+ decl_source(symbol, registry, entry)
256
+ .then { build_location(it, narrowed_decl_span(it, symbol), source_root) }
257
+ end
258
+
259
+ # Locals (Variable) belong to the file the cursor is in; module
260
+ # symbols belong to their declaring module.
261
+ def decl_source(symbol, registry, entry)
262
+ symbol.is_a?(Jade::Symbol::Variable) ?
263
+ entry.source :
264
+ registry.modules.fetch(symbol.module_name).source
265
+ end
266
+
267
+ # Function/Variable decl_spans are already name-only; Union /
268
+ # Struct / Variant / Interface decl_spans cover the entire
269
+ # declaration. Search the source slice for the identifier so the
270
+ # rename edit replaces just the name in both cases.
271
+ def narrowed_decl_span(source, symbol)
272
+ span = symbol.decl_span
273
+ offset = source.text.byteslice(span.begin, span.size)&.index(symbol.name)
274
+ return span unless offset
275
+
276
+ (span.begin + offset)...(span.begin + offset + symbol.name.bytesize)
277
+ end
278
+
279
+ # Reference ranges from usage_index cover the whole node (e.g.
280
+ # `M.foo` for QualifiedAccess), so we trim to the trailing
281
+ # identifier. For bare VariableReference / ConstructorReference
282
+ # the range already equals the identifier — trimming is a no-op.
283
+ def usage_edits(symbol, registry, source_root)
284
+ registry
285
+ .modules
286
+ .each_value
287
+ .flat_map do |entry|
288
+ next [] unless entry.source && entry.usage_index
289
+
290
+ entry
291
+ .usage_index
292
+ .for(symbol)
293
+ .map { trail_identifier_span(it.range, symbol.name) }
294
+ .map { build_location(entry.source, it, source_root) }
295
+ end
296
+ end
297
+
298
+ def trail_identifier_span(range, name)
299
+ (range.end - name.bytesize)...range.end
300
+ end
301
+
302
+ # Walks the AST gathering inlay hints. Every Pattern::Binding
303
+ # with a pinned type produces a hint — naturally covers let-
304
+ # bindings (`x = expr`), case-of pattern bindings (`in Just(x)`),
305
+ # and lambda params (`(x) -> ...`) once their types are pinned.
306
+ def collect_inlay_hints(node, entry, range_offsets)
307
+ return [] unless node.is_a?(AST::Node)
308
+
309
+ own = node.is_a?(AST::Pattern::Binding) ?
310
+ binding_hint(node, entry, range_offsets) : nil
311
+
312
+ children_of(node)
313
+ .flat_map { collect_inlay_hints(it, entry, range_offsets) }
314
+ .then { own ? [own] + it : it }
315
+ end
316
+
317
+ def children_of(node)
318
+ (node.members - AST::Node::BOILERPLATE_FIELDS)
319
+ .flat_map { node.public_send(it) }
320
+ .flat_map { it.is_a?(Array) ? it : [it] }
321
+ end
322
+
323
+ def binding_hint(binding, entry, range_offsets)
324
+ return nil unless range_offsets.cover?(binding.range.end)
325
+
326
+ type = entry.env.node_types[binding.id]
327
+ return nil unless type
328
+
329
+ {
330
+ position: offset_to_position(entry.source, binding.range.end),
331
+ label: ": #{type}",
332
+ kind: INLAY_HINT_TYPE,
333
+ paddingLeft: false,
334
+ paddingRight: false,
335
+ }
336
+ end
337
+
338
+ def build_location(source, span, source_root)
339
+ {
340
+ uri: lsp_uri(source.uri, source_root),
341
+ range: span_to_range(source, span),
342
+ }
343
+ end
344
+
345
+ def hoverable?(symbol)
346
+ symbol && HOVERABLE_SYMBOLS.include?(symbol.class)
347
+ end
348
+
349
+ # Symbol-based hover (richer — signatures, constraints, impls) is
350
+ # tried first; pinned-type hover (from TypeChecking's per-node
351
+ # table) is the fallback for nodes that don't resolve to a named
352
+ # symbol (locals, intermediate expressions).
353
+ def hover_for_node(node, registry, entry)
354
+ symbol = resolve_symbol(node, registry, entry)
355
+ return hover_response(symbol, registry) if hoverable?(symbol)
356
+
357
+ type = entry.env.node_types[node.id]
358
+ return nil unless type
359
+
360
+ { contents: { kind: 'markdown', value: code_block(pinned_text(node, type)) } }
361
+ end
362
+
363
+ def pinned_text(node, type)
364
+ node.respond_to?(:name) && node.name.is_a?(String) ?
365
+ "#{node.name} : #{type}" :
366
+ type.to_s
367
+ end
368
+
369
+ def hover_response(symbol, registry)
370
+ hover_body(symbol, registry)
371
+ .then { { contents: { kind: 'markdown', value: code_block(it) } } }
372
+ end
373
+
374
+ def hover_body(symbol, registry)
375
+ case symbol
376
+ in Jade::Symbol::Union | Jade::Symbol::Struct
377
+ render_type(symbol, registry)
378
+ else
379
+ render_value(symbol, registry)
380
+ end
381
+ end
382
+
383
+ def code_block(body)
384
+ "```jade\n#{body}\n```"
385
+ end
386
+
387
+ # For Symbol::Function we prefer the Scheme stored in the defining
388
+ # module's env — that's where inferred constraints (e.g. `Eq a`
389
+ # picked up from `==`) live. Falls back to Type.from_symbol for
390
+ # symbol kinds whose constraints surface directly on the symbol.
391
+ def render_value(symbol, registry)
392
+ type_and_constraints(symbol, registry)
393
+ .then { |(t, cs)| render_signature(symbol.name, t, cs) }
394
+ end
395
+
396
+ def type_and_constraints(symbol, registry)
397
+ scheme = symbol.is_a?(Jade::Symbol::Function) &&
398
+ lookup_scheme(symbol, registry)
399
+ return [scheme.type, scheme.constraints] if scheme
400
+
401
+ Jade::Type.from_symbol(
402
+ symbol, registry, Frontend::TypeChecking::VarGen.new
403
+ )
404
+ end
405
+
406
+ def render_type(symbol, registry)
407
+ impls_for(symbol, registry)
408
+ .then { it.empty? ? '' : "\n\nimplements #{it.join(', ')}" }
409
+ .then { "#{type_kind(symbol)} #{symbol.name}#{it}" }
410
+ end
411
+
412
+ def type_kind(symbol)
413
+ symbol.is_a?(Jade::Symbol::Union) ? 'type' : 'struct'
414
+ end
415
+
416
+ def impls_for(type_symbol, registry)
417
+ registry
418
+ .implementations
419
+ .keys
420
+ .select { it[1] == type_symbol.qualified_name }
421
+ .map { it[0].split('.').last }
422
+ .uniq
423
+ end
424
+
425
+ def lookup_scheme(symbol, registry)
426
+ registry
427
+ .modules[symbol.module_name]
428
+ &.env
429
+ &.bindings
430
+ &.[](symbol.qualified_name)
431
+ &.then { it.is_a?(Frontend::TypeChecking::Scheme) ? it : nil }
432
+ end
433
+
434
+ def render_signature(name, type, constraints)
435
+ "#{name} : #{constraint_prefix(constraints)}#{type}"
436
+ end
437
+
438
+ def constraint_prefix(constraints)
439
+ return '' if constraints.empty?
440
+
441
+ constraints
442
+ .map { short_constraint(it) }
443
+ .uniq
444
+ .join(', ')
445
+ .then { "#{it} => " }
446
+ end
447
+
448
+ def short_constraint(constraint)
449
+ "#{constraint.interface.split('.').last} #{constraint.type}"
450
+ end
451
+
452
+ # First node in the path (innermost-to-outermost) that resolves to a
453
+ # symbol. Stops at the most specific resolvable node so a stdlib
454
+ # call doesn't fall through to its enclosing function declaration.
455
+ def innermost_resolved(path, registry, entry)
456
+ innermost_resolvable_node(path, registry, entry)
457
+ &.then { resolve_symbol(it, registry, entry) }
458
+ end
459
+
460
+ def innermost_resolvable_node(path, registry, entry)
461
+ path.reverse.find { resolve_symbol(it, registry, entry) }
462
+ end
463
+
464
+ # For prepareRename / rename — identifier-only span of `node`.
465
+ # QualifiedAccess ranges include the `Module.` prefix, so trim
466
+ # to the trailing identifier. Declaration nodes fall back to
467
+ # narrowing `symbol.decl_span` (which is the whole declaration
468
+ # for Union / Struct / Variant / Interface, name-only for
469
+ # Function / Variable).
470
+ def identifier_span(node, symbol, source)
471
+ case node
472
+ in AST::QualifiedAccess
473
+ trail_identifier_span(node.range, symbol.name)
474
+ in AST::VariableReference | AST::ConstructorReference |
475
+ AST::ExposeValue | AST::ExposeType | AST::ExposeTypeExpand
476
+ node.range
477
+ else
478
+ narrowed_decl_span(source, symbol)
479
+ end
480
+ end
481
+
482
+ def resolve_symbol(node, registry, entry)
483
+ case node
484
+ in AST::VariableReference | AST::ConstructorReference |
485
+ AST::QualifiedAccess | AST::FunctionDeclaration |
486
+ AST::TypeDeclaration | AST::StructDeclaration |
487
+ AST::InterfaceDeclaration | AST::VariantDeclaration
488
+ node.symbol.then { resolve_ref(it, registry) }
489
+
490
+ in AST::FunctionDeclarationParam(name:, range:)
491
+ Jade::Symbol::Variable.new(name:, decl_span: range)
492
+
493
+ in AST::TypeName(type:)
494
+ entry.types[type].then { resolve_ref(it, registry) }
495
+
496
+ in AST::ExposeValue(name:)
497
+ entry.lookup_value(name)&.then { resolve_ref(it, registry) }
498
+
499
+ in AST::ExposeType | AST::ExposeTypeExpand
500
+ entry.lookup_type(node.name)&.then { resolve_ref(it, registry) }
501
+
502
+ else
503
+ nil
504
+ end
505
+ end
506
+
507
+ def resolve_ref(symbol, registry)
508
+ case symbol
509
+ in Jade::Symbol::ValueRef | Jade::Symbol::TypeRef
510
+ registry.lookup(symbol)
511
+ else
512
+ symbol
513
+ end
514
+ end
515
+
516
+ def document_symbol(name, kind, source, range, children: [])
517
+ {
518
+ name: name.to_s,
519
+ kind: SYMBOL_KIND.fetch(kind),
520
+ range: span_to_range(source, range),
521
+ selectionRange: span_to_range(source, range),
522
+ children:,
523
+ }
524
+ end
525
+
526
+ def variant_symbol(variant, source)
527
+ document_symbol(variant.name, :enum_member, source, variant.range)
528
+ end
529
+
530
+ def interface_fn_symbol(fn, source)
531
+ document_symbol(fn.name, :function, source, fn.range)
532
+ end
533
+
534
+ def diagnostic_message(diagnostic)
535
+ [
536
+ diagnostic.message,
537
+ *diagnostic.annotations.map { "#{it.kind}: #{it.message}" },
538
+ ].join("\n")
539
+ end
540
+ end
541
+ end
542
+ end