Module: Rigor::Inference::HktBodyParser

Defined in:
lib/rigor/inference/hkt_body_parser.rb

Overview

ADR-20 slice 2b — parses the body of an ‘HktRegistry::Definition` (a `String`, as populated by Slice 1’s ‘HktDirectives.parse_define` from `%arigor:v1:hkt_define` payloads) into the `HktBody` node tree the Slice 2a reducer evaluates against.

The minimum-viable grammar covered here is the union-of-atoms-and-parameterised-forms subset of ADR-20 § D3 — sufficient for ‘JSON.parse`’s ‘json::value` recursive sum and for any other recursive-data-shape signatures (Lisp value trees, dry-types refinements without conditionals). The conditional / indexed-access forms (`E <: T ? A : B`, `E in [k1, k2]`) drafted in D3 remain a follow-up slice — bodies that contain `?` raise `ParseError` and the calling directive parser drops the body_tree (the body String remains stored and the reducer falls back to `app.bound`).

## Grammar (slice 2b)

body         := union
union        := type_expr ("|" type_expr)*
type_expr    := atom | nominal_app | app_ref | param
atom         := "nil" | "true" | "false" | "bool" | "untyped"
param        := UCNAME   (when UCNAME ∈ params)
nominal_app  := class_name ("[" type_expr ("," type_expr)* "]")?
class_name   := "::"? UCNAME ("::" UCNAME)*
app_ref      := "App" "[" uri "," type_expr ("," type_expr)* "]"
uri          := IDENT ("::" IDENT)+
UCNAME       := /[A-Z]\w*/
IDENT        := /[a-z_]\w*/

## Disambiguation

The same syntactic UCNAME spells both a parameter reference (‘K` when `params = [:K]`) and a nominal class name (`Integer`). The parser resolves by checking the `params` set passed to HktBodyParser.parse; an unknown UCNAME is treated as a nominal class name. `App` is reserved at the head position of an `App` form; using `App` as a class name is therefore not supported.

Atoms are kept verbatim as ‘HktBody::TypeLeaf` nodes wrapping the appropriate `Rigor::Type::*` carrier: `nil` / `true` / `false` produce `Constant` carriers; `bool` produces the `Constant<true> | Constant<false>` union; `untyped` produces `Combinator.untyped` (i.e. `Dynamic`). Nominal class names produce raw `Type::Nominal` carriers (no `name_scope` resolution at this slice — the reducer trusts the name verbatim).

Defined Under Namespace

Classes: ParseError, Parser, Token, Tokenizer

Class Method Summary collapse

Class Method Details

.parse(string, params:) ⇒ Object

Raises:

  • (ArgumentError)


63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rigor/inference/hkt_body_parser.rb', line 63

def parse(string, params:)
  raise ArgumentError, "string must be a String, got #{string.class}" unless string.is_a?(String)
  raise ArgumentError, "params must be an Array, got #{params.class}" unless params.is_a?(Array)

  params_set = params.to_h { |p| [p.to_sym, true] }
  tokens = Tokenizer.new(string).tokenize
  parser = Parser.new(tokens, params_set)
  result = parser.parse_union
  parser.expect_eof!
  result
end