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,340 @@
1
+ require 'pathname'
2
+
3
+ module Jade
4
+ module LSP
5
+ module Handlers
6
+ extend self
7
+
8
+ def dispatch(state, message)
9
+ case message['method']
10
+ when 'initialize' then on_initialize(state, message)
11
+ when 'initialized' then [state, []]
12
+ when 'shutdown' then [state, [respond(message['id'], nil)]]
13
+ when 'exit' then [state, []]
14
+ when 'textDocument/didOpen' then on_did_open(state, message['params'])
15
+ when 'textDocument/didChange' then on_did_change(state, message['params'])
16
+ when 'textDocument/didSave' then [state, []]
17
+ when 'textDocument/didClose' then on_did_close(state, message['params'])
18
+ when 'textDocument/documentSymbol' then on_document_symbol(state, message)
19
+ when 'textDocument/hover' then on_hover(state, message)
20
+ when 'textDocument/definition' then on_definition(state, message)
21
+ when 'textDocument/references' then on_references(state, message)
22
+ when 'textDocument/completion' then on_completion(state, message)
23
+ when 'textDocument/prepareRename' then on_prepare_rename(state, message)
24
+ when 'textDocument/rename' then on_rename(state, message)
25
+ when 'textDocument/inlayHint' then on_inlay_hint(state, message)
26
+ when 'textDocument/formatting' then on_formatting(state, message)
27
+ else on_unknown(state, message)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def on_unknown(state, message)
34
+ return [state, []] unless message['id']
35
+
36
+ error = respond_error(message['id'], -32601, "method not found: #{message['method']}")
37
+ [state, [error]]
38
+ end
39
+
40
+ def on_initialize(state, message)
41
+ params = (message['params'] || {})
42
+ root = params
43
+ .then { it['rootUri'] || it.dig('workspaceFolders', 0, 'uri') }
44
+ .then { it ? it.sub(%r{\Afile://}, '') : Dir.pwd }
45
+
46
+ {
47
+ capabilities: {
48
+ textDocumentSync: { openClose: true, change: 1 },
49
+ positionEncoding: negotiate_encoding(params),
50
+ documentSymbolProvider: true,
51
+ hoverProvider: true,
52
+ definitionProvider: true,
53
+ referencesProvider: true,
54
+ completionProvider: { resolveProvider: false },
55
+ renameProvider: { prepareProvider: true },
56
+ inlayHintProvider: true,
57
+ documentFormattingProvider: true,
58
+ },
59
+ serverInfo: { name: 'jade-lsp', version: '0.1.0' },
60
+ }
61
+ .then { [state.with_root(root), [respond(message['id'], it)]] }
62
+ end
63
+
64
+ def negotiate_encoding(params)
65
+ params
66
+ .dig('capabilities', 'general', 'positionEncodings')
67
+ &.include?('utf-8') ? 'utf-8' : 'utf-16'
68
+ end
69
+
70
+ def on_did_open(state, params)
71
+ params['textDocument']
72
+ .then { state.put_buffer(it['uri'], it['text']) }
73
+ .then { recompile_and_publish(it) }
74
+ end
75
+
76
+ def on_did_change(state, params)
77
+ doc = params['textDocument']
78
+ latest = params['contentChanges'].last
79
+ state
80
+ .put_buffer(doc['uri'], latest['text'])
81
+ .then { recompile_and_publish(it) }
82
+ end
83
+
84
+ def on_did_close(state, params)
85
+ params['textDocument']['uri']
86
+ .then { recompile_and_publish(state.close(it), extra_uris: [it]) }
87
+ end
88
+
89
+ def on_document_symbol(state, message)
90
+ symbols = message
91
+ .dig('params', 'textDocument', 'uri')
92
+ .then { document_symbols_for(state, it) }
93
+ [state, [respond(message['id'], symbols)]]
94
+ end
95
+
96
+ def on_hover(state, message)
97
+ message['params']
98
+ .then { hover_for(state, it['textDocument']['uri'], it['position']) }
99
+ .then { [state, [respond(message['id'], it)]] }
100
+ end
101
+
102
+ def on_definition(state, message)
103
+ message['params']
104
+ .then { definition_for(state, it['textDocument']['uri'], it['position']) }
105
+ .then { [state, [respond(message['id'], it)]] }
106
+ end
107
+
108
+ def on_references(state, message)
109
+ params = message['params']
110
+ references_for(
111
+ state,
112
+ params['textDocument']['uri'],
113
+ params['position'],
114
+ include_declaration: params.dig('context', 'includeDeclaration'),
115
+ ).then { [state, [respond(message['id'], it)]] }
116
+ end
117
+
118
+ def on_completion(state, message)
119
+ [state, [respond(message['id'], Converters.completion_items)]]
120
+ end
121
+
122
+ def on_prepare_rename(state, message)
123
+ message['params']
124
+ .then { prepare_rename_for(state, it['textDocument']['uri'], it['position']) }
125
+ .then { [state, [respond(message['id'], it)]] }
126
+ end
127
+
128
+ def on_rename(state, message)
129
+ params = message['params']
130
+ rename_for(
131
+ state,
132
+ params['textDocument']['uri'],
133
+ params['position'],
134
+ params['newName'],
135
+ ).then { [state, [respond(message['id'], it)]] }
136
+ end
137
+
138
+ def on_inlay_hint(state, message)
139
+ params = message['params']
140
+ inlay_hints_for(
141
+ state, params['textDocument']['uri'], params['range'],
142
+ ).then { [state, [respond(message['id'], it)]] }
143
+ end
144
+
145
+ def on_formatting(state, message)
146
+ uri = message.dig('params', 'textDocument', 'uri')
147
+ edits = formatting_edits_for(state, uri)
148
+ [state, [respond(message['id'], edits)]]
149
+ end
150
+
151
+ def formatting_edits_for(state, uri)
152
+ text = state.buffers[uri]
153
+ return nil unless text
154
+
155
+ Converters.format_edits(text)
156
+ end
157
+
158
+ def inlay_hints_for(state, uri, lsp_range)
159
+ return [] unless state.registry
160
+
161
+ rel = Converters.relative_path(uri, state.source_root)
162
+ entry = state.registry.modules.each_value.find { it.source&.uri == rel }
163
+ return [] unless entry
164
+
165
+ start_offset = Converters.position_to_offset(
166
+ entry.source, lsp_range['start']['line'], lsp_range['start']['character'],
167
+ )
168
+ end_offset = Converters.position_to_offset(
169
+ entry.source, lsp_range['end']['line'], lsp_range['end']['character'],
170
+ )
171
+
172
+ Converters.inlay_hints_for(entry, start_offset..end_offset)
173
+ end
174
+
175
+ def prepare_rename_for(state, uri, position)
176
+ return nil unless state.registry
177
+
178
+ rel = Converters.relative_path(uri, state.source_root)
179
+ entry = state.registry.modules.each_value.find { it.source&.uri == rel }
180
+ return nil unless entry
181
+
182
+ offset = Converters.position_to_offset(
183
+ entry.source, position['line'], position['character']
184
+ )
185
+ Converters.prepare_rename_for_path(
186
+ entry.ast.find_at_path(offset), state.registry, entry, offset,
187
+ )
188
+ end
189
+
190
+ def rename_for(state, uri, position, new_name)
191
+ return nil unless state.registry
192
+
193
+ rel = Converters.relative_path(uri, state.source_root)
194
+ entry = state.registry.modules.each_value.find { it.source&.uri == rel }
195
+ return nil unless entry
196
+
197
+ Converters
198
+ .position_to_offset(entry.source, position['line'], position['character'])
199
+ .then { entry.ast.find_at_path(it) }
200
+ .then do |path|
201
+ Converters.rename_for_path(
202
+ path, state.registry, entry, state.source_root, new_name,
203
+ )
204
+ end
205
+ end
206
+
207
+ def references_for(state, uri, position, include_declaration:)
208
+ return nil unless state.registry
209
+
210
+ rel = Converters.relative_path(uri, state.source_root)
211
+ entry = state.registry.modules.each_value.find { it.source&.uri == rel }
212
+ return nil unless entry
213
+
214
+ Converters
215
+ .position_to_offset(entry.source, position['line'], position['character'])
216
+ .then { entry.ast.find_at_path(it) }
217
+ .then do |path|
218
+ Converters.references_for_path(
219
+ path, state.registry, entry, state.source_root,
220
+ include_declaration:,
221
+ )
222
+ end
223
+ end
224
+
225
+ def definition_for(state, uri, position)
226
+ return nil unless state.registry
227
+
228
+ rel = Converters.relative_path(uri, state.source_root)
229
+ entry = state.registry.modules.each_value.find { it.source&.uri == rel }
230
+ return nil unless entry
231
+
232
+ Converters
233
+ .position_to_offset(entry.source, position['line'], position['character'])
234
+ .then { entry.ast.find_at_path(it) }
235
+ .then { Converters.definition_for_path(it, state.registry, entry, state.source_root) }
236
+ end
237
+
238
+ def hover_for(state, uri, position)
239
+ return nil unless state.registry
240
+
241
+ rel = Converters.relative_path(uri, state.source_root)
242
+ entry = state.registry.modules.each_value.find { it.source&.uri == rel }
243
+ return nil unless entry
244
+
245
+ Converters
246
+ .position_to_offset(entry.source, position['line'], position['character'])
247
+ .then { Converters.hover_for_path(entry.ast.find_at_path(it), state.registry, entry) }
248
+ end
249
+
250
+ def document_symbols_for(state, uri)
251
+ return [] unless state.registry
252
+
253
+ rel = Converters.relative_path(uri, state.source_root)
254
+ entry = state.registry.modules.each_value.find { it.source&.uri == rel }
255
+ return [] unless entry
256
+
257
+ entry.ast.body.expressions
258
+ .filter_map { Converters.to_document_symbol(it, entry.source) }
259
+ end
260
+
261
+ # extra_uris always receive a publishDiagnostics, but compile output
262
+ # wins: if a real diagnostic came back for the URI, we send that, not
263
+ # an empty clear.
264
+ def recompile_and_publish(state, extra_uris: [])
265
+ if state.buffers.empty? || state.source_root.nil?
266
+ return [state, extra_uris.map { publish_for(it, []) }]
267
+ end
268
+
269
+ overlays = state.buffers
270
+ .to_h { |uri, text| [Converters.relative_path(uri, state.source_root), text] }
271
+
272
+ diagnostics_by_uri, registry = compile_each(state.source_root, overlays)
273
+
274
+ uris = (diagnostics_by_uri.keys + state.buffers.keys + extra_uris).uniq
275
+ messages = uris.map { publish_for(it, diagnostics_by_uri[it] || []) }
276
+
277
+ next_state = registry ? state.set_registry(registry) : state
278
+ [next_state, messages]
279
+ end
280
+
281
+ # Compile from each open buffer so unrelated modules still produce
282
+ # diagnostics. The same module reached twice yields identical
283
+ # diagnostics (deterministic over overlays), so Hash#merge is safe.
284
+ def compile_each(source_root, overlays)
285
+ overlays.keys.reduce([{}, nil]) do |(diag_acc, reg_acc), entry|
286
+ registry, diagnostics = compile(source_root, entry, overlays)
287
+ [diag_acc.merge(diagnostics), registry || reg_acc]
288
+ end
289
+ end
290
+
291
+ def compile(source_root, entry_path, overlays)
292
+ ModuleLoader
293
+ .load(source_root, entry_path, tolerant: true, overlays:)
294
+ .then { [it, collect_diagnostics(it, source_root)] }
295
+ rescue Jade::CompilationError => e
296
+ [nil, diagnostics_by_uri(e.diagnostics, source_root)]
297
+ rescue StandardError => e
298
+ $stderr.puts "[jade-lsp] compile crash: #{e.class}: #{e.message}"
299
+ $stderr.puts e.backtrace.first(20).join("\n")
300
+ [nil, {}]
301
+ end
302
+
303
+ def collect_diagnostics(registry, source_root)
304
+ registry
305
+ .modules
306
+ .each_value
307
+ .reject { Stdlib.is_stdlib?(it) }
308
+ .reject { it.source.nil? || it.diagnostics.items.empty? }
309
+ .reduce({}) do |acc, entry|
310
+ acc.merge(Converters.lsp_uri(entry.source.uri, source_root) => entry.diagnostics.items)
311
+ end
312
+ end
313
+
314
+ def diagnostics_by_uri(list, source_root)
315
+ list.items
316
+ .group_by { it.primary.source.uri }
317
+ .transform_keys { Converters.lsp_uri(it, source_root) }
318
+ end
319
+
320
+ def publish_for(uri, items)
321
+ notify('textDocument/publishDiagnostics', {
322
+ uri:,
323
+ diagnostics: items.map { Converters.diagnostic_to_lsp(it) },
324
+ })
325
+ end
326
+
327
+ def respond(id, result)
328
+ { jsonrpc: '2.0', id:, result: }
329
+ end
330
+
331
+ def respond_error(id, code, message)
332
+ { jsonrpc: '2.0', id:, error: { code:, message: } }
333
+ end
334
+
335
+ def notify(method, params)
336
+ { jsonrpc: '2.0', method:, params: }
337
+ end
338
+ end
339
+ end
340
+ end
@@ -0,0 +1,63 @@
1
+ require 'json'
2
+
3
+ module Jade
4
+ module LSP
5
+ class Server
6
+ def initialize(input: $stdin, output: $stdout)
7
+ @input = input
8
+ @output = output
9
+ @input.binmode
10
+ @output.binmode
11
+ @output.sync = true
12
+ end
13
+
14
+ def run
15
+ state = State.empty
16
+ loop do
17
+ message = read_message
18
+ break unless message
19
+
20
+ state, outbound = safe_dispatch(state, message)
21
+ outbound.each { write_message(it) }
22
+ break if message['method'] == 'exit'
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def safe_dispatch(state, message)
29
+ Handlers.dispatch(state, message)
30
+ rescue StandardError => e
31
+ $stderr.puts "[jade-lsp] handler crash: #{e.class}: #{e.message}"
32
+ $stderr.puts e.backtrace.first(20).join("\n")
33
+ [state, []]
34
+ end
35
+
36
+ def read_message
37
+ headers = read_headers or return nil
38
+ length = headers['Content-Length'].to_i
39
+ JSON.parse(@input.read(length))
40
+ rescue JSON::ParserError => e
41
+ $stderr.puts "[jade-lsp] bad json: #{e.message}"
42
+ nil
43
+ end
44
+
45
+ def read_headers
46
+ headers = {}
47
+ while (line = @input.gets("\r\n"))
48
+ stripped = line.chomp("\r\n")
49
+ return headers if stripped.empty?
50
+
51
+ k, _, v = stripped.partition(': ')
52
+ headers[k] = v
53
+ end
54
+ nil
55
+ end
56
+
57
+ def write_message(message)
58
+ body = JSON.generate(message)
59
+ @output.write("Content-Length: #{body.bytesize}\r\n\r\n#{body}")
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,100 @@
1
+ module Jade
2
+ module LSP
3
+ module Snippets
4
+ Snippet = Data.define(:label, :detail, :body)
5
+
6
+ ALL = [
7
+ Snippet.new(
8
+ label: 'def',
9
+ detail: 'function declaration',
10
+ body: <<~SNIP.chomp,
11
+ def ${1:name}(${2:params}) -> ${3:Type}
12
+ ${0:body}
13
+ end
14
+ SNIP
15
+ ),
16
+ Snippet.new(
17
+ label: 'type',
18
+ detail: 'union type',
19
+ body: <<~SNIP.chomp,
20
+ type ${1:Name}
21
+ = ${2:Variant1}
22
+ | ${0:Variant2}
23
+ SNIP
24
+ ),
25
+ Snippet.new(
26
+ label: 'struct',
27
+ detail: 'struct declaration',
28
+ body: <<~SNIP.chomp,
29
+ struct ${1:Name} = {
30
+ ${2:field}: ${0:Type}
31
+ }
32
+ SNIP
33
+ ),
34
+ Snippet.new(
35
+ label: 'case',
36
+ detail: 'case expression with else fallback',
37
+ body: <<~SNIP.chomp,
38
+ case ${1:expr}
39
+ in ${2:pattern} then ${3:result}
40
+ else ${0:fallback}
41
+ end
42
+ SNIP
43
+ ),
44
+ Snippet.new(
45
+ label: 'if',
46
+ detail: 'if/then/else block',
47
+ body: <<~SNIP.chomp,
48
+ if ${1:cond} then
49
+ ${2:then_branch}
50
+ else
51
+ ${0:else_branch}
52
+ end
53
+ SNIP
54
+ ),
55
+ Snippet.new(
56
+ label: 'module',
57
+ detail: 'module header',
58
+ body: 'module ${1:Name} exposing (${0})',
59
+ ),
60
+ Snippet.new(
61
+ label: 'import',
62
+ detail: 'import declaration',
63
+ body: 'import ${1:Module} exposing (${0:Name})',
64
+ ),
65
+ Snippet.new(
66
+ label: 'interface',
67
+ detail: 'interface declaration',
68
+ body: <<~SNIP.chomp,
69
+ interface ${1:Name}(${2:a}) with
70
+ ${3:fn} : ${4:args} -> ${0:Return}
71
+ end
72
+ SNIP
73
+ ),
74
+ Snippet.new(
75
+ label: 'implements',
76
+ detail: 'interface implementation',
77
+ body: <<~SNIP.chomp,
78
+ implements ${1:Interface}(${2:Type}) with
79
+ ${3:method}: ${0:fn_name}
80
+ end
81
+ SNIP
82
+ ),
83
+ Snippet.new(
84
+ label: 'uses',
85
+ detail: 'interop import',
86
+ body: <<~SNIP.chomp,
87
+ uses ${1:Module} with
88
+ ${2:fn} : ${3:args} -> ${0:Return}
89
+ end
90
+ SNIP
91
+ ),
92
+ Snippet.new(
93
+ label: 'lambda',
94
+ detail: 'anonymous function',
95
+ body: '(${1:args}) -> { ${0:body} }',
96
+ ),
97
+ ].freeze
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,25 @@
1
+ module Jade
2
+ module LSP
3
+ State = Data.define(:source_root, :buffers, :registry) do
4
+ def self.empty
5
+ new(source_root: nil, buffers: {}, registry: nil)
6
+ end
7
+
8
+ def with_root(root)
9
+ with(source_root: root)
10
+ end
11
+
12
+ def put_buffer(uri, text)
13
+ with(buffers: buffers.merge(uri => text))
14
+ end
15
+
16
+ def close(uri)
17
+ with(buffers: buffers.except(uri))
18
+ end
19
+
20
+ def set_registry(reg)
21
+ with(registry: reg)
22
+ end
23
+ end
24
+ end
25
+ end
data/lib/jade/lsp.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'json'
2
+ require 'pathname'
3
+
4
+ require 'jade'
5
+ require 'jade/formatter'
6
+ require 'jade/frontend/comment_attacher'
7
+ require 'jade/lsp/snippets'
8
+ require 'jade/lsp/converters'
9
+ require 'jade/lsp/state'
10
+ require 'jade/lsp/handlers'
11
+ require 'jade/lsp/server'
12
+
13
+ module Jade
14
+ module LSP
15
+ end
16
+ end
@@ -0,0 +1,56 @@
1
+ require 'digest'
2
+ require 'fileutils'
3
+
4
+ module Jade
5
+ module ModuleLoader
6
+ module Cache
7
+ extend self
8
+
9
+ MAGIC = 'jade-cache-v2'
10
+
11
+ def read(cache_dir, module_name, key)
12
+ path = path_for(cache_dir, module_name)
13
+ return nil unless File.exist?(path)
14
+
15
+ Marshal.load(File.binread(path)) => [MAGIC, ^key, interface_digest, entry]
16
+ [entry, interface_digest]
17
+ rescue StandardError, NoMatchingPatternError
18
+ nil
19
+ end
20
+
21
+ def write(cache_dir, module_name, entry, key, interface_digest)
22
+ path = path_for(cache_dir, module_name)
23
+ FileUtils.mkdir_p(File.dirname(path))
24
+
25
+ tmp = "#{path}.#{Process.pid}.tmp"
26
+ File.binwrite(tmp, Marshal.dump([MAGIC, key, interface_digest, entry]))
27
+ File.rename(tmp, path)
28
+ end
29
+
30
+ def clean(cache_dir)
31
+ FileUtils.rm_rf(cache_dir)
32
+ end
33
+
34
+ def compute_key(entry, dep_digests)
35
+ Digest::SHA256.hexdigest(
36
+ [compiler_fingerprint, entry.source.text, dep_digests.sort.inspect]
37
+ .join("\n")
38
+ )
39
+ end
40
+
41
+ def compiler_fingerprint
42
+ @compiler_fingerprint ||=
43
+ Dir[File.expand_path('../**/*.rb', __dir__)]
44
+ .sort
45
+ .map { Digest::SHA256.file(it).hexdigest }
46
+ .then { Digest::SHA256.hexdigest(it.join) }
47
+ end
48
+
49
+ private
50
+
51
+ def path_for(cache_dir, module_name)
52
+ File.join(cache_dir, "#{module_name.tr('.', '/')}.entry")
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,23 @@
1
+ module Jade
2
+ module ModuleLoader
3
+ DependencyGraph = Data.define(:nodes) do
4
+ def initialize(nodes: {})
5
+ super
6
+ end
7
+
8
+ def size
9
+ nodes.size
10
+ end
11
+
12
+ def empty?
13
+ nodes.empty?
14
+ end
15
+
16
+ def add(node, imports)
17
+ nodes
18
+ .merge(node => imports.to_set.to_a)
19
+ .then { with(nodes: it) }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,48 @@
1
+ module Jade
2
+ module ModuleLoader
3
+ module DependencyResolver
4
+ extend self
5
+
6
+ def resolve(entry, registry)
7
+ case entry.ast
8
+ in AST::Module(body:)
9
+ resolve_body(body, entry, registry)
10
+
11
+ in AST::Body
12
+ resolve_body(entry.ast, entry, registry)
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def resolve_body(body, entry, registry)
19
+ body => AST::Body(expressions:)
20
+
21
+ expressions
22
+ .reduce([registry, []]) do |(acc_registry, acc_imports), ast_node|
23
+ case ast_node
24
+ in AST::ImportDeclaration(module_name:) if stdlib?(module_name, acc_registry)
25
+ [acc_registry, acc_imports]
26
+
27
+ in AST::ImportDeclaration(module_name:)
28
+ # TODO: [ModuleLoaderRefactor] This is more of DependencyLoader
29
+ [
30
+ ModuleLoader.load_import(module_name, acc_registry),
31
+ acc_imports + [module_name],
32
+ ]
33
+
34
+ else
35
+ [acc_registry, acc_imports]
36
+ end
37
+ end
38
+ .then { |registry, imports| registry.add_dependencies(entry, imports) }
39
+ end
40
+
41
+ def stdlib?(module_name, registry)
42
+ registry
43
+ .get(module_name)
44
+ .then { it && Stdlib.is_stdlib?(it) }
45
+ end
46
+ end
47
+ end
48
+ end