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,67 @@
1
+ module Jade
2
+ module Codegen
3
+ module Boundary
4
+ module Specialized
5
+ # Int / Float / Bool / String. The runtime validators in
6
+ # `Jade::Interop::Boundary` do the check + conversion (e.g.
7
+ # `String#dup`, `Float#to_f`) in one call.
8
+ module Scalar
9
+ extend self
10
+
11
+ HELPER = {
12
+ 'Basics.Int' => 'integer',
13
+ 'Basics.Float' => 'float',
14
+ 'Basics.Bool' => 'bool',
15
+ 'String.String' => 'string',
16
+ }.freeze
17
+
18
+ LABEL = {
19
+ 'Basics.Int' => 'Int',
20
+ 'Basics.Float' => 'Float',
21
+ 'Basics.Bool' => 'Bool',
22
+ 'String.String' => 'String',
23
+ }.freeze
24
+
25
+ # Ruby class used by `List.decode` to validate a list of scalars
26
+ # in a single `Array#all?` C-loop.
27
+ LIST_ELEM_CLASS = {
28
+ 'Basics.Int' => '::Integer',
29
+ 'Basics.Float' => '::Numeric',
30
+ 'Basics.Bool' => '::TrueClass',
31
+ 'String.String' => '::String',
32
+ }.freeze
33
+
34
+ def decode(type, input)
35
+ qname = qname_for(type) or return nil
36
+ label = LABEL[qname].inspect
37
+ "Jade::Interop::Boundary.#{HELPER[qname]}(#{label}, #{input})"
38
+ end
39
+
40
+ # Scalar encoders are identity (Ruby int IS the JSON int, etc.),
41
+ # so `encode` returns nil — callers handle that via
42
+ # `Specialized.identity_encoder?`.
43
+ def encode(_type, _value_expr, _registry)
44
+ nil
45
+ end
46
+
47
+ def identity_encoder?(type)
48
+ qname_for(type) ? true : false
49
+ end
50
+
51
+ def specializable?(type, _registry, _seen)
52
+ identity_encoder?(type)
53
+ end
54
+
55
+ # The scalar's qname (e.g. `"Basics.Int"`) if `type` is a 0-arg
56
+ # application of a known scalar constructor, else nil. Used by
57
+ # `List.decode` to pick `LIST_ELEM_CLASS` for the all? check.
58
+ def qname_for(type)
59
+ return nil unless Specialized.args_of(type) == []
60
+
61
+ Specialized.qname_of(type).then { HELPER.key?(it) ? it : nil }
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,106 @@
1
+ require 'jade/codegen/boundary/specialized/scalar'
2
+ require 'jade/codegen/boundary/specialized/list'
3
+ require 'jade/codegen/boundary/specialized/maybe'
4
+ require 'jade/codegen/boundary/specialized/record'
5
+
6
+ module Jade
7
+ module Codegen
8
+ module Boundary
9
+ # Emits inline boundary code for known-shape types — scalars,
10
+ # `List(specializable)`, `Maybe(specializable)`, and structs whose
11
+ # fields are all specializable. Bypasses `Decode::Runner` and the
12
+ # descriptor cache.
13
+ #
14
+ # This module is the dispatcher: each shape (`Scalar`, `List`,
15
+ # `Maybe`, `Record`) lives in its own file under `specialized/`,
16
+ # exposing `decode` / `encode` / `specializable?` methods that the
17
+ # dispatcher tries in order. Shapes that contain other types
18
+ # (`List`, `Maybe`, `Record`) recurse back through the dispatcher.
19
+ module Specialized
20
+ extend self
21
+
22
+ # Ruby expression that validates `input` and yields the decoded
23
+ # value, or `nil` if `type` isn't specializable.
24
+ def decode_expr(type, input, registry)
25
+ Scalar.decode(type, input) ||
26
+ List.decode(type, input, registry) ||
27
+ Maybe.decode(type, input, registry) ||
28
+ Record.decode(type, input, registry)
29
+ end
30
+
31
+ # Ruby expression that encodes `value_expr` to the wire form, or
32
+ # `nil` if the encoder is identity (caller skips the wrap) or the
33
+ # type isn't specializable (caller falls back to the cache).
34
+ def encode_expr(type, value_expr, registry)
35
+ Record.encode(type, value_expr, registry) ||
36
+ List.encode(type, value_expr, registry) ||
37
+ Maybe.encode(type, value_expr, registry)
38
+ end
39
+
40
+ # True when the encoder for `type` produces output equal to the
41
+ # input — the boundary wrapper can skip the encode call entirely.
42
+ # Recursive: `List(t)` is identity iff `t` is.
43
+ def identity_encoder?(type)
44
+ Scalar.identity_encoder?(type) || List.identity_encoder?(type)
45
+ end
46
+
47
+ # Predicate used by `Record.specializable_struct` when checking
48
+ # field types. The `seen` set carries struct qnames we're already
49
+ # inside, threaded through container shapes for cycle detection.
50
+ def specializable_field?(type, registry, seen)
51
+ Scalar.specializable?(type, registry, seen) ||
52
+ List.specializable?(type, registry, seen) ||
53
+ Maybe.specializable?(type, registry, seen) ||
54
+ Record.specializable?(type, registry, seen)
55
+ end
56
+
57
+ def collect_helpers(body, registry)
58
+ Record.collect_helpers(body, registry)
59
+ end
60
+
61
+ def emit_helpers(structs, registry)
62
+ Record.emit_helpers(structs, registry)
63
+ end
64
+
65
+ # --- type-shape helpers shared across shape modules ---
66
+
67
+ # Both `Type::Application` (from inferred boundary types) and
68
+ # `Symbol::TypeApplication` (from struct field declarations) carry
69
+ # the same constructor/args shape; normalize to a qname string.
70
+ def qname_of(type)
71
+ case type
72
+ in Type::Application(constructor: Type::Constructor(name:))
73
+ name
74
+
75
+ in Symbol::TypeApplication(constructor: Symbol::TypeRef(module_name:, name: n))
76
+ "#{module_name}.#{n}"
77
+
78
+ else
79
+ nil
80
+ end
81
+ end
82
+
83
+ def args_of(type)
84
+ case type
85
+ in Type::Application(args:) then args
86
+ in Symbol::TypeApplication(args:) then args
87
+ else nil
88
+ end
89
+ end
90
+
91
+ # Human-readable label for error messages on container types.
92
+ def type_label(type)
93
+ if (qname = Scalar.qname_for(type))
94
+ Scalar::LABEL[qname]
95
+ elsif (inner = List.inner_of(type))
96
+ "List(#{type_label(inner)})"
97
+ elsif (inner = Maybe.inner_of(type))
98
+ "Maybe(#{type_label(inner)})"
99
+ else
100
+ (qname_of(type) || 'value').split('.').last
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,189 @@
1
+ require 'jade/frontend/type_checking/constraints'
2
+
3
+ module Jade
4
+ module Codegen
5
+ module Boundary
6
+ extend self
7
+ extend Helpers
8
+
9
+ DECODABLE = 'Decode.Decodable'
10
+ ENCODABLE = 'Encode.Encodable'
11
+
12
+ VALUE_PASSTHROUGH_DECODER = 'Jade::Decode::Decoder[Jade::Decode::Desc::Pass[]]'
13
+ VALUE_IDENTITY_ENCODER = '->(v) { v }'
14
+ NEVER_ENCODER = '->(_) { fail "Never arm produced a value" }'
15
+
16
+ def decoder_for(type, registry)
17
+ case type
18
+ in Type::Application(constructor: Type::Constructor(name:), args:)
19
+ decode_app(name, args, registry)
20
+
21
+ else
22
+ nil
23
+ end
24
+ end
25
+
26
+ def encoder_for(type, registry)
27
+ case type
28
+ in Type::Application(constructor: Type::Constructor(name:), args:)
29
+ encode_app(name, args, registry)
30
+
31
+ else
32
+ nil
33
+ end
34
+ end
35
+
36
+ def eligible?(fn_type, registry)
37
+ args, return_type = Type.signature(fn_type)
38
+ args.all? { decoder_for(it, registry) } &&
39
+ return_eligible?(return_type, registry)
40
+ end
41
+
42
+ # Task in return position needs both arms encodable — the wrapper
43
+ # discriminates the outcome rather than producing an encoded Task.
44
+ # Everything else checks the type's own encoder directly.
45
+ def return_eligible?(type, registry)
46
+ case type
47
+ in Type::Application(constructor: Type::Constructor(name: 'Task.Task'), args: [ok_t, err_t])
48
+ !encoder_for(ok_t, registry).nil? && !encoder_for(err_t, registry).nil?
49
+
50
+ else
51
+ !encoder_for(type, registry).nil?
52
+ end
53
+ end
54
+
55
+ def task_arms(task_type, registry)
56
+ task_type => Type::Application(
57
+ constructor: Type::Constructor(name: 'Task.Task'),
58
+ args: [ok_t, err_t],
59
+ )
60
+ ok_enc = encoder_for(ok_t, registry)
61
+ err_enc = encoder_for(err_t, registry)
62
+ [ok_enc, err_enc] if ok_enc && err_enc
63
+ end
64
+
65
+ private
66
+
67
+ def decode_app(name, args, registry)
68
+ case [name, args]
69
+ in ['Basics.Int', []] then intr_call('Decode.int')
70
+ in ['Basics.Float', []] then intr_call('Decode.float')
71
+ in ['Basics.Bool', []] then intr_call('Decode.bool')
72
+ in ['String.String', []] then intr_call('Decode.string')
73
+ in ['Decode.Value', []] then VALUE_PASSTHROUGH_DECODER
74
+
75
+ in ['List.List', [inner]]
76
+ decoder_for(inner, registry)
77
+ &.then { "#{intr('Decode.list')}.call(#{it})" }
78
+
79
+ in ['Maybe.Maybe', [inner]]
80
+ decoder_for(inner, registry)
81
+ &.then { "#{intr('Decode.nullable')}.call(#{it})" }
82
+
83
+ in ['Dict.Dict', [k_t, v_t]]
84
+ k_dec = decoder_for(k_t, registry)
85
+ v_dec = decoder_for(v_t, registry)
86
+ "#{intr('Decode.dict')}.curry[#{k_dec}][#{v_dec}]" if k_dec && v_dec
87
+
88
+ else
89
+ decoder_dispatch(name, args, registry)
90
+ end
91
+ end
92
+
93
+ def encode_app(name, args, registry)
94
+ case [name, args]
95
+ in ['Basics.Int', []] then intr('Encode.int')
96
+ in ['Basics.Float', []] then intr('Encode.float')
97
+ in ['Basics.Bool', []] then intr('Encode.bool')
98
+ in ['String.String', []] then intr('Encode.string')
99
+ in ['Decode.Value', []] then VALUE_IDENTITY_ENCODER
100
+
101
+ # Never is uninhabited — the encoder can never be called. Treat as
102
+ # eligible so Task(a, Never) boundaries work; raise loudly if the
103
+ # impossible happens.
104
+ in ['Basics.Never', []] then NEVER_ENCODER
105
+
106
+ in ['List.List', [inner]]
107
+ encoder_for(inner, registry)
108
+ &.then { "#{intr('Encode.list')}.curry[#{it}]" }
109
+
110
+ in ['Maybe.Maybe', [inner]]
111
+ encoder_for(inner, registry)
112
+ &.then { "#{intr('Encode.nullable')}.curry[#{it}]" }
113
+
114
+ in ['Dict.Dict', [k_t, v_t]]
115
+ k_enc = encoder_for(k_t, registry)
116
+ v_enc = encoder_for(v_t, registry)
117
+ "#{intr('Encode.dict')}.curry[#{k_enc}][#{v_enc}]" if k_enc && v_enc
118
+
119
+ # Task isn't a value-encodable type. `return_eligible?` and
120
+ # `task_arms` handle Task in return position; here we just say
121
+ # "no encoder" so other places that ask for an encoder on a Task
122
+ # value get an honest nil.
123
+ in ['Task.Task', _]
124
+ nil
125
+
126
+ else
127
+ encoder_dispatch(name, args, registry)
128
+ end
129
+ end
130
+
131
+ def intr(qname)
132
+ "Jade::Runtime.intr(#{qname.inspect})"
133
+ end
134
+
135
+ def intr_call(qname)
136
+ "#{intr(qname)}.call"
137
+ end
138
+
139
+ # impl_fn_ref returns a Method ref; callers `.call(...)` it. For
140
+ # 0-arg decoder methods that means `decoder.call()` → the Decoder
141
+ # value. For 1-arg encoder methods that's `encoder.call(value)`.
142
+ def decoder_dispatch(name, args, registry)
143
+ if ref = impl_fn_ref(DECODABLE, name, 'decoder', registry)
144
+ "#{ref}.call"
145
+ else
146
+ derived_dispatch(DECODABLE, name, args, registry)&.dig('decoder')
147
+ end
148
+ end
149
+
150
+ def encoder_dispatch(name, args, registry)
151
+ impl_fn_ref(ENCODABLE, name, 'encoder', registry) ||
152
+ derived_dispatch(ENCODABLE, name, args, registry)&.dig('encoder')
153
+ end
154
+
155
+ def derived_dispatch(interface_qname, type_qname, args, registry)
156
+ type = Type.constructor(type_qname).apply(args)
157
+ constraint = Type.constraint(interface_qname, type, nil)
158
+
159
+ case Frontend::TypeChecking::Constraints.resolve(constraint, registry, nil)
160
+ in Ok[impl] then Codegen::FunctionCall.generate_impl_dispatch(impl, registry)
161
+ in Err then nil
162
+ end
163
+ rescue NoMethodError, NoMatchingPatternError
164
+ # Deriver assumes derivability (type-check-time invariant); boundary
165
+ # synthesis may probe types whose deps fail — treat as ineligible.
166
+ nil
167
+ end
168
+
169
+ def impl_fn_ref(interface_qname, type_qname, fn_name, registry)
170
+ impl = registry.implementations[[interface_qname, type_qname]]
171
+ return nil unless impl
172
+ return nil unless impl.functions[fn_name].is_a?(Symbol::ValueRef)
173
+
174
+ fn_sym = registry.lookup(impl.functions[fn_name])
175
+
176
+ case fn_sym
177
+ in Symbol::Function
178
+ "#{to_qualified(fn_sym.module_name)}::Internal.method(:#{fn_sym.name})"
179
+
180
+ in Symbol::StdlibFunction(codegen:) if codegen.is_a?(String)
181
+ codegen
182
+
183
+ else
184
+ nil
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,18 @@
1
+ module Jade
2
+ module Codegen
3
+ module ConstructorReference
4
+ extend self
5
+ extend Helpers
6
+
7
+ def generate(node, registry)
8
+ node => AST::ConstructorReference(symbol:)
9
+ from_symbol(registry.lookup(symbol))
10
+ end
11
+
12
+ def from_symbol(symbol)
13
+ qualified = to_qualified(symbol.qualified_name)
14
+ symbol.args.empty? ? "#{qualified}[]" : "#{qualified}.method(:[])"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,96 @@
1
+ module Jade
2
+ module Codegen
3
+ # Dynamically-scoped emission state. Each `with_X` wraps a block so the
4
+ # state is visible to the recursive `generate` call tree, then restored
5
+ # on exit. Stored on the Codegen singleton because threading these as
6
+ # parameters through every AST branch would pollute the API.
7
+ module Context
8
+ extend self
9
+
10
+ # Maps [interface_qname, type_var_id] => ruby parameter name. Set by
11
+ # FunctionDeclaration around its body so nested calls can resolve the
12
+ # caller's dict for var-typed constraints. Empty outside any function.
13
+ def dict_env
14
+ @dict_env ||= {}
15
+ end
16
+
17
+ def with_dict_env(env)
18
+ prev = @dict_env
19
+ @dict_env = env
20
+ yield
21
+ ensure
22
+ @dict_env = prev
23
+ end
24
+
25
+ # When set, references with this name emit as `self` (and field accesses
26
+ # on them as bare method calls). Used to rewrite operator-impl lambda
27
+ # bodies — `(a, b) -> { a.amount == b.amount }` becomes
28
+ # `def ==(b); amount == b.amount; end`, no `a = self` shim.
29
+ #
30
+ # Name-based, not symbol-identity-based, because Pattern::Binding doesn't
31
+ # carry the resolved Symbol::Variable.
32
+ def self_var_name
33
+ @self_var_name
34
+ end
35
+
36
+ def with_self_var_name(name)
37
+ prev = @self_var_name
38
+ @self_var_name = name
39
+ yield
40
+ ensure
41
+ @self_var_name = prev
42
+ end
43
+
44
+ # False outside a Module so bare expressions (REPL) get the runtime
45
+ # fallback — no constants exist to reference.
46
+ def hoist_records?
47
+ @hoist_records
48
+ end
49
+
50
+ def with_hoisted_records
51
+ prev = @hoist_records
52
+ @hoist_records = true
53
+ yield
54
+ ensure
55
+ @hoist_records = prev
56
+ end
57
+
58
+ # Methods (def strings) to inline into each type's `Data.define do ... end`
59
+ # block. Populated once at the start of module emission by walking impls
60
+ # of dispatched interfaces; consumed by StructDeclaration /
61
+ # VariantDeclaration. Indexed by the fully-qualified Ruby class string
62
+ # (e.g. `"::Sample::Money"`).
63
+ def dispatched_methods
64
+ @dispatched_methods || {}
65
+ end
66
+
67
+ def with_dispatched_methods(map)
68
+ prev = @dispatched_methods
69
+ @dispatched_methods = map
70
+ yield
71
+ ensure
72
+ @dispatched_methods = prev
73
+ end
74
+
75
+ # Maps boundary decoder/encoder expression strings to module-level
76
+ # const names that hold the same value, precomputed once at module
77
+ # load. Populated by `Boundary.collect_cache` at the start of module
78
+ # emission; consumed by `Boundary.cached_decoder_for` /
79
+ # `cached_encoder_for` from wrapper codegen.
80
+ #
81
+ # Shape: `{ decoders: { spec => const }, encoders: { spec => const } }`.
82
+ # Empty outside a Module — `cached_*` falls through to the raw spec.
83
+ def boundary_cache
84
+ @boundary_cache || { decoders: {}, encoders: {} }
85
+ end
86
+
87
+ def with_boundary_cache(cache)
88
+ prev = @boundary_cache
89
+ @boundary_cache = cache
90
+ yield
91
+ ensure
92
+ @boundary_cache = prev
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,81 @@
1
+ require 'jade/codegen/helpers'
2
+
3
+ module Jade
4
+ module Codegen
5
+ module Emitter
6
+ extend self
7
+ extend Helpers
8
+
9
+ def emit(ir)
10
+ case ir
11
+ in [:var, expr]
12
+ expr
13
+
14
+ in [:!, expr]
15
+ "!(#{emit(expr)})"
16
+
17
+ in [:and, expr1, expr2]
18
+ "#{emit(expr1)} && #{emit(expr2)}"
19
+
20
+ in Integer | TrueClass | FalseClass | Float
21
+ ir.to_s
22
+
23
+ in String
24
+ ir.inspect
25
+
26
+ in [:case, subject, branches]
27
+ branches
28
+ .map { [:case_branch, *it] }
29
+ .map { emit(it) }
30
+ .join("\n")
31
+ .then { "case #{emit(subject)}\n#{it}\nend" }
32
+
33
+ in [:case_branch, pattern, body]
34
+ body
35
+ .map { emit(it) }.join('; ')
36
+ .then { "in #{emit(pattern)} then #{it}" }
37
+
38
+ in [:call, callee, args]
39
+ args
40
+ .map { emit(it) }
41
+ .join(', ')
42
+ .then { "#{emit(callee)}.call(#{it})"}
43
+
44
+ in [:impl_arg, index, fn]
45
+ "impl_arg[#{index}]['#{fn}']"
46
+
47
+ in [:stdlib_fn, name]
48
+ "Jade::Runtime.intr(#{name.inspect})"
49
+
50
+ in [:struct_constructor, qualified_name, arity]
51
+ "#{to_qualified(qualified_name)}.method(:[]).curry(#{arity})"
52
+
53
+ in [:anon_record_constructor, keys]
54
+ "#{data_define(keys)}.method(:[]).curry(#{keys.size})"
55
+
56
+ in [:list, exprs]
57
+ exprs
58
+ .map { emit(it) }
59
+ .join(', ')
60
+ .then { "[#{it}]" }
61
+
62
+ in [:access, expr, key]
63
+ "#{emit(expr)}.#{key}"
64
+
65
+ # patterns
66
+
67
+ in [:constructor, name, args]
68
+ args
69
+ .map { "#{it}" }
70
+ .join(',')
71
+ .then { "#{to_qualified(name)}(#{it})" }
72
+
73
+ in [:_]
74
+ '_'
75
+
76
+ end
77
+ end
78
+
79
+ end
80
+ end
81
+ end