Skip to main content

harn_parser/builtin_signatures/
types.rs

1//! Re-exports of builtin signature shape types from `harn-builtin-meta`, plus
2//! parser-local conversion helpers from the const IR (`Ty`) to the runtime
3//! IR (`TypeExpr`).
4//!
5//! The const-constructible types live in `harn-builtin-meta` (a dep-free
6//! crate consumed by both the parser and `harn-vm`). Conversion to the
7//! parser's owned `TypeExpr` requires types that are private to this crate,
8//! so it lives here as an extension trait.
9
10use crate::ast::{ShapeField, TypeExpr};
11
12pub use harn_builtin_meta::{
13    BuiltinMetadata, BuiltinSignature, Param, ShapeFieldDescriptor, Ty, TY_ANY, TY_BOOL, TY_BYTES,
14    TY_BYTES_OR_NIL, TY_CLOSURE, TY_DECIMAL, TY_DICT, TY_DICT_OR_NIL, TY_DURATION, TY_FLOAT,
15    TY_INT, TY_INT_OR_NIL, TY_LIST, TY_NEVER, TY_NIL, TY_NUMBER, TY_STRING, TY_STRING_OR_NIL,
16};
17
18/// Convert a const-IR [`Ty`] into the parser's owned [`TypeExpr`]. Generic
19/// references stay as `Named(name)` so the checker's existing scope-based
20/// generic-param resolution applies.
21pub fn ty_to_type_expr(ty: &Ty) -> TypeExpr {
22    match ty {
23        Ty::Named(name) => TypeExpr::Named((*name).into()),
24        Ty::Generic(name) => TypeExpr::Named((*name).into()),
25        Ty::Any => TypeExpr::Named("any".into()),
26        Ty::Optional(inner) => {
27            TypeExpr::Union(vec![ty_to_type_expr(inner), TypeExpr::Named("nil".into())])
28        }
29        // Keep the metadata IR compact, but project Harn's built-in container
30        // constructors onto their dedicated AST variants. Leaving (for
31        // example) `Ty::Apply("list", ...)` as a generic `Applied` node makes
32        // a generated builtin contract print exactly like `list<T>` while
33        // remaining incompatible with the same type parsed from Harn source.
34        Ty::Apply("list", [inner]) => TypeExpr::List(Box::new(ty_to_type_expr(inner))),
35        Ty::Apply("dict", [key, value]) => TypeExpr::DictType(
36            Box::new(ty_to_type_expr(key)),
37            Box::new(ty_to_type_expr(value)),
38        ),
39        Ty::Apply("iter", [inner]) => TypeExpr::Iter(Box::new(ty_to_type_expr(inner))),
40        Ty::Apply("generator" | "Generator", [inner]) => {
41            TypeExpr::Generator(Box::new(ty_to_type_expr(inner)))
42        }
43        Ty::Apply("stream" | "Stream", [inner]) => {
44            TypeExpr::Stream(Box::new(ty_to_type_expr(inner)))
45        }
46        Ty::Apply("owned", [inner]) => TypeExpr::Owned(Box::new(ty_to_type_expr(inner))),
47        Ty::Apply(name, args) => TypeExpr::Applied {
48            name: (*name).into(),
49            args: args.iter().map(ty_to_type_expr).collect(),
50        },
51        Ty::Union(members) => TypeExpr::Union(members.iter().map(ty_to_type_expr).collect()),
52        Ty::Fn(params, return_type) => TypeExpr::FnType {
53            params: params.iter().map(ty_to_type_expr).collect(),
54            return_type: Box::new(ty_to_type_expr(return_type)),
55        },
56        Ty::Shape(fields) => TypeExpr::Shape(
57            fields
58                .iter()
59                .map(|f| ShapeField::synthetic(f.name, ty_to_type_expr(&f.ty), f.optional))
60                .collect(),
61        ),
62        Ty::SchemaOf(name) => TypeExpr::Applied {
63            name: "Schema".into(),
64            args: vec![TypeExpr::Named((*name).into())],
65        },
66        Ty::Never => TypeExpr::Never,
67        Ty::LitInt(v) => TypeExpr::LitInt(*v),
68        Ty::LitString(s) => TypeExpr::LitString((*s).into()),
69    }
70}
71
72/// Parser-side extension methods on [`Ty`] and [`BuiltinSignature`] that
73/// depend on the parser's owned AST types (kept out of `harn-builtin-meta`
74/// so that crate stays dep-free).
75pub trait TyExt {
76    /// Materialize as a runtime [`TypeExpr`].
77    fn to_type_expr(&self) -> TypeExpr;
78}
79
80impl TyExt for Ty {
81    fn to_type_expr(&self) -> TypeExpr {
82        ty_to_type_expr(self)
83    }
84}
85
86pub trait BuiltinSignatureExt {
87    /// Materialize per-parameter types as owned [`TypeExpr`]s for the type
88    /// checker's call-site validation.
89    fn param_type_exprs(&self) -> Vec<TypeExpr>;
90    /// Owned [`TypeExpr`] return type.
91    fn return_type_expr(&self) -> TypeExpr;
92}
93
94impl BuiltinSignatureExt for BuiltinSignature {
95    fn param_type_exprs(&self) -> Vec<TypeExpr> {
96        self.params.iter().map(|p| ty_to_type_expr(&p.ty)).collect()
97    }
98
99    fn return_type_expr(&self) -> TypeExpr {
100        ty_to_type_expr(&self.returns)
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107
108    const STRING: Ty = Ty::Named("string");
109    const LIST_ARGS: &[Ty] = &[STRING];
110
111    #[test]
112    fn builtin_container_metadata_uses_language_ast_variants() {
113        assert_eq!(
114            ty_to_type_expr(&Ty::Apply("list", LIST_ARGS)),
115            TypeExpr::List(Box::new(TypeExpr::Named("string".into())))
116        );
117    }
118}