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,15 @@
1
+ require 'jade/port'
2
+
3
+ module Jade
4
+ module Calendar
5
+ module Runtime
6
+ extend Jade::Port
7
+
8
+ task :today_raw do |t|
9
+ ::Time.now
10
+ .then { { year: it.year, month: it.month, day: it.day } }
11
+ .then { t.ok(it) }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,96 @@
1
+ require 'jade/source'
2
+ require 'jade/lexer'
3
+ require 'jade/ast'
4
+ require 'jade/parsing'
5
+ require 'jade/formatter'
6
+ require 'jade/frontend/comment_attacher'
7
+
8
+ module Jade
9
+ module CLI
10
+ module Fmt
11
+ module_function
12
+
13
+ def run(argv)
14
+ mode = :stdout
15
+ file = nil
16
+
17
+ argv.each do |arg|
18
+ case arg
19
+ when '-i', '--in-place' then mode = :in_place
20
+ when '-c', '--check' then mode = :check
21
+ when '-h', '--help' then usage
22
+ when /\A-/
23
+ warn "unknown option: #{arg}"
24
+ usage
25
+ else
26
+ usage if file
27
+ file = arg
28
+ end
29
+ end
30
+
31
+ format(file, mode)
32
+ end
33
+
34
+ def format(file, mode)
35
+ source_text = read_source(file)
36
+ source = Source.new(uri: file || 'stdin', text: source_text)
37
+
38
+ case Parsing.parse(Lexer.tokenize(source), source:)
39
+ in Ok([ast, comments])
40
+ emit(Formatter.format(ast, comments:, source:) + "\n",
41
+ source_text, file, mode)
42
+
43
+ in Err(error)
44
+ warn "Parse error: #{error.message}"
45
+ exit 2
46
+ end
47
+ end
48
+
49
+ def read_source(file)
50
+ case
51
+ when file then File.read(file)
52
+ when !$stdin.tty? then $stdin.read
53
+ else usage
54
+ end
55
+ end
56
+
57
+ def emit(formatted, source_text, file, mode)
58
+ case mode
59
+ when :in_place
60
+ usage unless file
61
+ write_in_place(formatted, source_text, file)
62
+
63
+ when :check
64
+ exit 0 if formatted == source_text
65
+ warn "#{file || 'stdin'}: not formatted"
66
+ exit 1
67
+
68
+ when :stdout
69
+ print formatted
70
+ end
71
+ end
72
+
73
+ def write_in_place(formatted, source_text, file)
74
+ return if formatted == source_text
75
+
76
+ File.write(file, formatted)
77
+ warn "Formatted #{file}"
78
+ end
79
+
80
+ def usage
81
+ warn <<~USAGE
82
+ Usage: jade fmt [options] [file]
83
+
84
+ Options:
85
+ -i, --in-place Rewrite the file in place.
86
+ -c, --check Exit 0 if formatted, 1 if drift, 2 on parse error.
87
+ Does not write.
88
+ -h, --help Show this message.
89
+
90
+ Reads from stdin when no file is given.
91
+ USAGE
92
+ exit 1
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,13 @@
1
+ require 'jade/lsp'
2
+
3
+ module Jade
4
+ module CLI
5
+ module Lsp
6
+ module_function
7
+
8
+ def run(_argv)
9
+ Jade::LSP::Server.new.run
10
+ end
11
+ end
12
+ end
13
+ end
data/lib/jade/cli/q.rb ADDED
@@ -0,0 +1,113 @@
1
+ require 'jade'
2
+ require 'jade/lsp'
3
+ require 'json'
4
+
5
+ module Jade
6
+ module CLI
7
+ # Headless query interface to the same compiler intelligence the LSP
8
+ # server uses. Intended for tools and agents that want a quick JSON
9
+ # answer instead of speaking JSON-RPC.
10
+ module Q
11
+ USAGE = <<~TXT.freeze
12
+ Usage: jade q COMMAND [ARGS]
13
+
14
+ hover FILE:LINE:COL Type info at the given position.
15
+ symbols FILE Document symbols (outline) for FILE.
16
+ defn FILE:LINE:COL Goto-definition location.
17
+ refs FILE:LINE:COL Find all references (incl. declaration).
18
+
19
+ FILE is relative to the project root (cwd).
20
+ LINE and COL are 0-indexed (LSP convention).
21
+
22
+ Compile cache lives at .jade/cache, so repeat queries are fast.
23
+ TXT
24
+
25
+ module_function
26
+
27
+ def run(argv)
28
+ case argv[0]
29
+ when 'hover' then dump(hover(argv[1]))
30
+ when 'symbols' then dump(symbols(argv[1]))
31
+ when 'defn' then dump(defn(argv[1]))
32
+ when 'refs' then dump(refs(argv[1]))
33
+ else
34
+ warn USAGE
35
+ exit 1
36
+ end
37
+ end
38
+
39
+ def hover(arg)
40
+ file, line, col = parse_position(arg)
41
+ Context.new(file).then do |ctx|
42
+ Jade::LSP::Converters.hover_for_path(
43
+ ctx.path_at(line, col), ctx.registry, ctx.entry
44
+ )
45
+ end
46
+ end
47
+
48
+ def symbols(file)
49
+ fail 'FILE required' unless file
50
+
51
+ Context.new(file).entry.then do |entry|
52
+ entry.ast.body.expressions.filter_map do |node|
53
+ Jade::LSP::Converters.to_document_symbol(node, entry.source)
54
+ end
55
+ end
56
+ end
57
+
58
+ def defn(arg)
59
+ file, line, col = parse_position(arg)
60
+ Context.new(file).then do |ctx|
61
+ Jade::LSP::Converters.definition_for_path(
62
+ ctx.path_at(line, col), ctx.registry, ctx.entry, ctx.source_root
63
+ )
64
+ end
65
+ end
66
+
67
+ def refs(arg)
68
+ file, line, col = parse_position(arg)
69
+ Context.new(file).then do |ctx|
70
+ Jade::LSP::Converters.references_for_path(
71
+ ctx.path_at(line, col), ctx.registry, ctx.entry, ctx.source_root,
72
+ include_declaration: true,
73
+ )
74
+ end
75
+ end
76
+
77
+ def parse_position(arg)
78
+ fail 'FILE:LINE:COL required' unless arg
79
+ fail "expected FILE:LINE:COL, got #{arg.inspect}" unless arg.count(':') == 2
80
+
81
+ arg.split(':').then { |(file, line, col)| [file, line.to_i, col.to_i] }
82
+ end
83
+
84
+ def dump(result)
85
+ puts JSON.pretty_generate(result)
86
+ end
87
+
88
+ class Context
89
+ attr_reader :file, :source_root, :registry, :entry
90
+
91
+ def initialize(file)
92
+ @file = file
93
+ @source_root = Dir.pwd
94
+ @registry = Jade::ModuleLoader.load(
95
+ @source_root, file,
96
+ cache_dir: File.join(@source_root, '.jade/cache'),
97
+ tolerant: true,
98
+ )
99
+ @entry = @registry
100
+ .modules
101
+ .each_value
102
+ .find { it.source&.uri == file } || fail("no module at #{file}")
103
+ end
104
+
105
+ def path_at(line, col)
106
+ Jade::LSP::Converters
107
+ .position_to_offset(entry.source, line, col)
108
+ .then { entry.ast.find_at_path(it) }
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
data/lib/jade/cli.rb ADDED
@@ -0,0 +1,43 @@
1
+ require 'jade'
2
+
3
+ module Jade
4
+ module CLI
5
+ SUBCOMMANDS = {
6
+ 'fmt' => 'Fmt',
7
+ 'lsp' => 'Lsp',
8
+ 'q' => 'Q',
9
+ }.freeze
10
+
11
+ module_function
12
+
13
+ def run(argv)
14
+ sub, *rest = argv
15
+
16
+ case sub
17
+ when nil, '-h', '--help', 'help'
18
+ usage
19
+
20
+ when *SUBCOMMANDS.keys
21
+ require "jade/cli/#{sub}"
22
+ const_get(SUBCOMMANDS.fetch(sub)).run(rest)
23
+
24
+ else
25
+ warn "jade: unknown command #{sub.inspect}\n\n"
26
+ usage($stderr)
27
+ exit 1
28
+ end
29
+ end
30
+
31
+ def usage(io = $stdout)
32
+ io.puts <<~TXT
33
+ Usage: jade COMMAND [ARGS]
34
+
35
+ fmt Format .jd source (stdin or file).
36
+ lsp Run the language server (stdio JSON-RPC).
37
+ q Headless query interface (hover/symbols/defn/refs).
38
+
39
+ Run `jade COMMAND --help` for command-specific options.
40
+ TXT
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,13 @@
1
+ require 'jade/port'
2
+
3
+ module Jade
4
+ module Clock
5
+ module Runtime
6
+ extend Jade::Port
7
+
8
+ task :now_raw do |t|
9
+ t.ok({ millis: (::Time.now.to_r * 1000).to_i })
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,94 @@
1
+ module Jade
2
+ module Codegen
3
+ module Boundary
4
+ # Per-module cache mapping each type a boundary wrapper needs to
5
+ # decode/encode to a const name (`BOUNDARY_DEC_0`, etc.) that holds
6
+ # the value once at module load. `collect` walks the body to build
7
+ # the map; `decoder_for` / `encoder_for` consult it from wrapper
8
+ # codegen, falling back to the raw `Boundary` spec when uncached
9
+ # (e.g. when emission runs outside a Module).
10
+ module Cache
11
+ extend self
12
+ extend Helpers
13
+
14
+ def decoder_for(type, registry)
15
+ Codegen.boundary_cache[:decoders][type] || Boundary.decoder_for(type, registry)
16
+ end
17
+
18
+ def encoder_for(type, registry)
19
+ Codegen.boundary_cache[:encoders][type] || Boundary.encoder_for(type, registry)
20
+ end
21
+
22
+ def task_arms(task_type, registry)
23
+ task_type => Type::Application(args: [ok_t, err_t])
24
+ [encoder_for(ok_t, registry), encoder_for(err_t, registry)]
25
+ end
26
+
27
+ def collect(body, registry)
28
+ per_fn = body
29
+ .expressions
30
+ .filter_map do
31
+ boundary_types(it, registry) if it.is_a?(AST::FunctionDeclaration)
32
+ end
33
+
34
+ {
35
+ decoders: cache_map(per_fn.flat_map { it[:decoders] }, 'DEC') { |t|
36
+ Boundary::Specialized.decode_expr(t, '_', registry)
37
+ },
38
+ encoders: cache_map(per_fn.flat_map { it[:encoders] }, 'ENC') { |t|
39
+ Boundary::Specialized.identity_encoder?(t) ||
40
+ Boundary::Specialized.encode_expr(t, '_', registry)
41
+ },
42
+ }
43
+ end
44
+
45
+ # Types with a specialized inline emission don't need a cached
46
+ # constant — the wrapper emits the validation directly.
47
+ def cache_map(types, tag, &specialized)
48
+ types
49
+ .reject(&specialized)
50
+ .uniq
51
+ .each_with_index
52
+ .map { |t, i| [t, "BOUNDARY_#{tag}_#{i}"] }
53
+ .to_h
54
+ end
55
+
56
+ def constants(cache, registry)
57
+ cache[:decoders].map { |type, name| "#{name} = #{Boundary.decoder_for(type, registry)}" } +
58
+ cache[:encoders].map { |type, name| "#{name} = #{Boundary.encoder_for(type, registry)}" }
59
+ end
60
+
61
+ private
62
+
63
+ # Returns the {decoders:, encoders:} type lists this fn's wrapper
64
+ # would touch, or `nil` when the fn produces no wrapper (not
65
+ # exposed, polymorphic, or ineligible).
66
+ def boundary_types(fn_node, registry)
67
+ symbol = fn_node.symbol
68
+ return nil unless registry.get(symbol.module_name).exposed_value(symbol.name)
69
+ return nil unless dict_constraints(symbol, registry).empty?
70
+
71
+ fn_type = fn_type_for(symbol, registry)
72
+ return nil unless Boundary.eligible?(fn_type, registry)
73
+
74
+ args, return_type = Type.signature(fn_type)
75
+
76
+ case return_type
77
+ in Type::Application(constructor: Type::Constructor(name: 'Task.Task'), args: arms)
78
+ arms
79
+ else
80
+ [return_type]
81
+ end
82
+ .then { { decoders: args, encoders: it } }
83
+ end
84
+
85
+ def fn_type_for(symbol, registry)
86
+ registry
87
+ .get(symbol.module_name)
88
+ .env
89
+ .then { it.substitution.apply(it.bindings[symbol.qualified_name].type) }
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,65 @@
1
+ module Jade
2
+ module Codegen
3
+ module Boundary
4
+ module Specialized
5
+ # `List(t)` where `t` is itself specializable. Two shapes:
6
+ #
7
+ # - `List(scalar)` — emits a single `Array#all?` C-loop check via
8
+ # `Boundary.list_of`, then passes the array through.
9
+ # - `List(specializable)` — validates Array shape with
10
+ # `Boundary.array`, then maps the inner decoder over each element.
11
+ module List
12
+ extend self
13
+
14
+ def decode(type, input, registry)
15
+ inner = inner_of(type) or return nil
16
+
17
+ scalar_optimized(inner, input) ||
18
+ generic_decode(type, inner, input, registry)
19
+ end
20
+
21
+ def encode(type, value_expr, registry)
22
+ inner = inner_of(type) or return nil
23
+ return nil if Specialized.identity_encoder?(inner)
24
+
25
+ elem = Specialized.encode_expr(inner, '_1', registry) or return nil
26
+ "#{value_expr}.map { #{elem} }"
27
+ end
28
+
29
+ def identity_encoder?(type)
30
+ inner = inner_of(type) or return false
31
+ Specialized.identity_encoder?(inner)
32
+ end
33
+
34
+ def specializable?(type, registry, seen)
35
+ inner = inner_of(type) or return false
36
+ Specialized.specializable_field?(inner, registry, seen)
37
+ end
38
+
39
+ def inner_of(type)
40
+ return nil unless Specialized.qname_of(type) == 'List.List'
41
+ args = Specialized.args_of(type)
42
+ args&.size == 1 ? args[0] : nil
43
+ end
44
+
45
+ private
46
+
47
+ # `List(scalar)` fast path: validate elements with a single
48
+ # C-loop `all?` check, no per-element decoder call.
49
+ def scalar_optimized(inner, input)
50
+ qname = Scalar.qname_for(inner) or return nil
51
+ klass = Scalar::LIST_ELEM_CLASS[qname]
52
+ label = "List(#{Scalar::LABEL[qname]})".inspect
53
+ "Jade::Interop::Boundary.list_of(#{klass}, #{label}, #{input})"
54
+ end
55
+
56
+ def generic_decode(type, inner, input, registry)
57
+ elem = Specialized.decode_expr(inner, '_1', registry) or return nil
58
+ label = "List(#{Specialized.type_label(inner)})".inspect
59
+ "Jade::Interop::Boundary.array(#{label}, #{input}).map { #{elem} }"
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,40 @@
1
+ module Jade
2
+ module Codegen
3
+ module Boundary
4
+ module Specialized
5
+ # `Maybe(t)` where `t` is itself specializable. Both decode and
6
+ # encode bind the input via `.then { it ... }` so a complex
7
+ # `value_expr` (e.g. a full `Internal.X(...)` call) isn't
8
+ # re-evaluated.
9
+ module Maybe
10
+ extend self
11
+
12
+ def decode(type, input, registry)
13
+ inner = inner_of(type) or return nil
14
+ elem = Specialized.decode_expr(inner, 'it', registry) or return nil
15
+
16
+ "#{input}.then { it.nil? ? Jade::Maybe::Nothing[] : Jade::Maybe::Just[#{elem}] }"
17
+ end
18
+
19
+ def encode(type, value_expr, registry)
20
+ inner = inner_of(type) or return nil
21
+ inner_enc = Specialized.encode_expr(inner, 'it._1', registry) || 'it._1'
22
+
23
+ "#{value_expr}.then { it.is_a?(::Jade::Maybe::Just) ? #{inner_enc} : nil }"
24
+ end
25
+
26
+ def specializable?(type, registry, seen)
27
+ inner = inner_of(type) or return false
28
+ Specialized.specializable_field?(inner, registry, seen)
29
+ end
30
+
31
+ def inner_of(type)
32
+ return nil unless Specialized.qname_of(type) == 'Maybe.Maybe'
33
+ args = Specialized.args_of(type)
34
+ args&.size == 1 ? args[0] : nil
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,165 @@
1
+ module Jade
2
+ module Codegen
3
+ module Boundary
4
+ module Specialized
5
+ # Structs whose fields are all specializable. Each specializable
6
+ # struct gets a pair of `def self.decode_<name>` / `encode_<name>`
7
+ # helper methods emitted at module level; the wrapper body for
8
+ # `birthday(person: Person) -> Person` becomes
9
+ # `encode_person(Internal.birthday(decode_person(person)))`.
10
+ #
11
+ # Cycle detection: a struct referencing itself (directly or
12
+ # mutually) falls back to the descriptor cache path. The `seen`
13
+ # set carries qnames of structs we're currently inside; revisiting
14
+ # one means we'd loop, so we bail with nil.
15
+ module Record
16
+ extend self
17
+ extend Helpers
18
+
19
+ def decode(type, input, registry)
20
+ struct = struct_for(type, registry) or return nil
21
+ "#{decode_helper_name(struct)}(#{input})"
22
+ end
23
+
24
+ def encode(type, value_expr, registry)
25
+ struct = struct_for(type, registry) or return nil
26
+ "#{encode_helper_name(struct)}(#{value_expr})"
27
+ end
28
+
29
+ def specializable?(type, registry, seen)
30
+ specializable_struct(type, registry, seen) ? true : false
31
+ end
32
+
33
+ # All specializable structs reachable from any exposed
34
+ # function's boundary signature, transitively (through nested
35
+ # struct fields and `List` / `Maybe` wrappers). Each one needs
36
+ # `decode_<name>` / `encode_<name>` helper methods emitted.
37
+ def collect_helpers(body, registry)
38
+ body.expressions
39
+ .filter { it.is_a?(AST::FunctionDeclaration) }
40
+ .flat_map { fn_reachable_structs(it, registry) }
41
+ .uniq
42
+ .then { transitive_closure(it, registry) }
43
+ end
44
+
45
+ def emit_helpers(structs, registry)
46
+ structs.flat_map do
47
+ [decode_helper(it, registry), encode_helper(it, registry)]
48
+ end
49
+ end
50
+
51
+ def struct_for(type, registry)
52
+ specializable_struct(type, registry, ::Set.new)
53
+ end
54
+
55
+ # Returns specializable structs reachable from `type` through
56
+ # any depth of `List` / `Maybe` / nested struct fields. Used by
57
+ # `collect_helpers` to seed the closure walk.
58
+ def structs_in(type, registry)
59
+ if (struct = struct_for(type, registry))
60
+ [struct]
61
+ elsif (inner = List.inner_of(type))
62
+ structs_in(inner, registry)
63
+ elsif (inner = Maybe.inner_of(type))
64
+ structs_in(inner, registry)
65
+ else
66
+ []
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def specializable_struct(type, registry, seen)
73
+ struct = lookup_struct(type, registry) or return nil
74
+ return nil if seen.include?(struct.qualified_name)
75
+
76
+ struct.record_type.fields.values
77
+ .all? { Specialized.specializable_field?(it, registry, seen + [struct.qualified_name]) }
78
+ .then { it ? struct : nil }
79
+ end
80
+
81
+ def lookup_struct(type, registry)
82
+ return nil unless Specialized.args_of(type) == []
83
+ qname = Specialized.qname_of(type) or return nil
84
+
85
+ parts = qname.split('.')
86
+ ref = Symbol.type_ref(parts[0..-2].join('.'), parts[-1])
87
+ sym = registry.lookup(ref) or return nil
88
+ sym.is_a?(Symbol::Struct) ? sym : nil
89
+ end
90
+
91
+ # Reachability walk from `seeds` through nested struct fields.
92
+ # Pure-functional: each call builds a fresh `collected + frontier`.
93
+ def transitive_closure(seeds, registry, collected = ::Set.new)
94
+ frontier = seeds.reject { collected.include?(it) }
95
+ return collected.to_a if frontier.empty?
96
+
97
+ transitive_closure(
98
+ frontier.flat_map { nested_structs(it, registry) },
99
+ registry,
100
+ collected + frontier,
101
+ )
102
+ end
103
+
104
+ def nested_structs(struct, registry)
105
+ struct.record_type.fields.values.flat_map { structs_in(it, registry) }
106
+ end
107
+
108
+ def fn_reachable_structs(fn_node, registry)
109
+ symbol = fn_node.symbol
110
+ return [] unless registry.get(symbol.module_name).exposed_value(symbol.name)
111
+
112
+ fn_type = registry.get(symbol.module_name)
113
+ .env
114
+ .then { it.substitution.apply(it.bindings[symbol.qualified_name].type) }
115
+
116
+ args, ret = Type.signature(fn_type)
117
+ (args + [ret]).flat_map { structs_in(it, registry) }
118
+ end
119
+
120
+ def decode_helper_name(struct)
121
+ "decode_#{snake(struct.name)}"
122
+ end
123
+
124
+ def encode_helper_name(struct)
125
+ "encode_#{snake(struct.name)}"
126
+ end
127
+
128
+ def decode_helper(struct, registry)
129
+ ctor = "::#{to_qualified(struct.module_name)}::#{struct.name}"
130
+ hash_call = "Jade::Interop::Boundary.hash(#{struct.name.inspect}, value)"
131
+
132
+ struct.record_type.fields
133
+ .map { |k, t| field_decode(k, t, registry) }
134
+ .then { Pretty.call(ctor, it, open: '[', close: ']') }
135
+ .then { Pretty.block("#{hash_call}.then do |h|", it) }
136
+ .then { Pretty.block("def self.#{decode_helper_name(struct)}(value)", it) }
137
+ end
138
+
139
+ def encode_helper(struct, registry)
140
+ struct.record_type.fields
141
+ .map { |k, t| "#{k.inspect} => #{field_encode_value(t, "p.#{k}", registry)}" }
142
+ .then { "{ #{it.join(', ')} }" }
143
+ .then { Pretty.block("def self.#{encode_helper_name(struct)}(p)", it) }
144
+ end
145
+
146
+ def field_decode(key, type, registry)
147
+ Specialized.decode_expr(type, "h[#{key.to_s.inspect}]", registry) ||
148
+ fail("non-specializable field type for #{key}: #{type}")
149
+ end
150
+
151
+ def field_encode_value(type, accessor, registry)
152
+ Specialized.encode_expr(type, accessor, registry) || accessor
153
+ end
154
+
155
+ def snake(name)
156
+ name
157
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
158
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
159
+ .downcase
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end