From 9172fcdc27a9a68757b353da4dffe404fdf14c79 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 28 Jul 2025 09:12:41 -0400 Subject: [PATCH] xo-expression xo-reader: parser improvements, prep type inf/unify --- .../xo/expression/GeneralizedExpression.hpp | 22 ++++++--- include/xo/expression/Lambda.hpp | 33 ++++++++++--- include/xo/expression/typeinf/type_ref.hpp | 9 +++- .../xo/expression/typeinf/type_unifier.hpp | 3 ++ src/expression/DefineExpr.cpp | 1 + src/expression/GeneralizedExpression.cpp | 37 ++++++++++++++ src/expression/Lambda.cpp | 49 ++++++++++++------- src/expression/typeinf/type_ref.cpp | 12 +++++ src/expression/typeinf/type_unifier.cpp | 12 +++++ 9 files changed, 147 insertions(+), 31 deletions(-) diff --git a/include/xo/expression/GeneralizedExpression.hpp b/include/xo/expression/GeneralizedExpression.hpp index 552d26a9..0c7c2f84 100644 --- a/include/xo/expression/GeneralizedExpression.hpp +++ b/include/xo/expression/GeneralizedExpression.hpp @@ -6,7 +6,8 @@ #pragma once #include "xo/refcnt/Refcounted.hpp" -#include "xo/reflect/TypeDescr.hpp" +#include "xo/expression/typeinf/type_ref.hpp" +//#include "xo/reflect/TypeDescr.hpp" #include "exprtype.hpp" namespace xo { @@ -20,16 +21,25 @@ namespace xo { **/ class GeneralizedExpression : public ref::Refcount { public: + using type_ref = xo::scm::type_ref; + using prefix_type = xo::scm::prefix_type; using TypeDescr = xo::reflect::TypeDescr; using ppstate = xo::print::ppstate; using ppindentinfo = xo::print::ppindentinfo; public: - GeneralizedExpression(exprtype extype, TypeDescr valuetype) - : extype_{extype}, valuetype_{valuetype}{} + /** if @p valuetype is null, generate unique type variable + * using prefix derived from @p extype. + **/ + GeneralizedExpression(exprtype extype, TypeDescr valuetype); + /** if @p valuetype is null, generate unique type variable + * name, beginning with @p prefix + **/ + GeneralizedExpression(exprtype extype, prefix_type prefix, TypeDescr valuetype); exprtype extype() const { return extype_; } - TypeDescr valuetype() const { return valuetype_; } + const type_ref & valuetype_ref() const { return valuetype_ref_; } + TypeDescr valuetype() const { return valuetype_ref_.td(); } /** write human-readable representation to stream @p os **/ virtual void display(std::ostream & os) const = 0; @@ -39,7 +49,7 @@ namespace xo { virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const = 0; /** useful when scaffolding expressions in a parser **/ - void assign_valuetype(TypeDescr x) { valuetype_ = x; } + void assign_valuetype(TypeDescr x) { valuetype_ref_.resolve_to(x); } private: /** expression type (constant | apply | ..) for this expression **/ @@ -47,7 +57,7 @@ namespace xo { /** type information (when available) for values produced by this * expression. **/ - TypeDescr valuetype_ = nullptr; + type_ref valuetype_ref_; }; inline std::ostream & diff --git a/include/xo/expression/Lambda.hpp b/include/xo/expression/Lambda.hpp index 636dfbc0..040420bb 100644 --- a/include/xo/expression/Lambda.hpp +++ b/include/xo/expression/Lambda.hpp @@ -22,6 +22,17 @@ namespace xo { **/ class Lambda : public FunctionInterface { public: + /** + * @p name. Name for this lambda -- must be unique + * @p lambda_type. Function signature + * @p local_env. Environment with formals as content + * @p body. Expression for lambda function body + **/ + static rp make(const std::string & name, + TypeDescr lambda_type, + const rp & local_env, + const rp & body); + /** * @p name Name for this lambda -- must be unique * @p argv Formal parameters, in left-to-right order @@ -43,6 +54,21 @@ namespace xo { TypeDescr explicit_return_td, const rp & body); + /** create type description for lambda with arguments @p argv + * and return type @p return_td + **/ + static TypeDescr assemble_lambda_td(const std::vector> & argv, + TypeDescr return_td); + + /** create type description for lambda with arguments @p argv + * and body expression @p body. + * @p explicit_return_td will be used if non-null. + * otherwise use @p body valuetype + **/ + static TypeDescr assemble_lambda_td(const std::vector> & argv, + TypeDescr explicit_return_td, + const rp & body); + /** downcast from Expression **/ static bp from(bp x) { return bp::from(x); @@ -102,13 +128,6 @@ namespace xo { virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const override; protected: - /** create type description for lambda with arguments @p argv - * and body expression @p body - **/ - static TypeDescr assemble_lambda_td(const std::vector> & argv, - TypeDescr explicit_return_td, - const rp & body); - /** create string description for function signature, * consistent with c++ expectation **/ diff --git a/include/xo/expression/typeinf/type_ref.hpp b/include/xo/expression/typeinf/type_ref.hpp index b158a005..ccac6481 100644 --- a/include/xo/expression/typeinf/type_ref.hpp +++ b/include/xo/expression/typeinf/type_ref.hpp @@ -13,7 +13,8 @@ namespace xo { /** @class type_ref * @brief name and eventual resolution for type associated with an expression. * - * Type inference / unification operates on @ref xo::scm::TypeTemplate instances, see also. + * Type inference / unification operates on + * @ref xo::scm::TypeBlueprint instances, see also. **/ class type_ref { public: @@ -23,6 +24,12 @@ namespace xo { type_ref() = default; type_ref(const type_var& id, TypeDescr td); + /** if type not determined (@p td is nullptr), + * -> generate and store type variable name. + * otherwise type already resolvedn + **/ + static type_ref dwim(prefix_type prefix, TypeDescr td); + /** generate a unique type-variable name, that begins with @p prefix **/ static type_var generate_unique(prefix_type prefix); diff --git a/include/xo/expression/typeinf/type_unifier.hpp b/include/xo/expression/typeinf/type_unifier.hpp index 22cb53bb..f0ba659c 100644 --- a/include/xo/expression/typeinf/type_unifier.hpp +++ b/include/xo/expression/typeinf/type_unifier.hpp @@ -49,6 +49,9 @@ namespace xo { **/ unify_result unify(bp lhs, bp rhs); + /** lookup type variable by @p name, to get resolution **/ + rp lookup(const type_var & name) const; + private: type_substitution_map constraint_map_; }; diff --git a/src/expression/DefineExpr.cpp b/src/expression/DefineExpr.cpp index 1d9ce563..0e09d000 100644 --- a/src/expression/DefineExpr.cpp +++ b/src/expression/DefineExpr.cpp @@ -64,6 +64,7 @@ namespace xo { DefineExpr::pretty_print(const ppindentinfo & ppii) const { return ppii.pps()->pretty_struct(ppii, "Define", + //refrtag("type", this->valuetype()), // need pretty refrtag("name", lhs_var_->name()), refrtag("rhs", rhs_)); } diff --git a/src/expression/GeneralizedExpression.cpp b/src/expression/GeneralizedExpression.cpp index 3734e291..9365241e 100644 --- a/src/expression/GeneralizedExpression.cpp +++ b/src/expression/GeneralizedExpression.cpp @@ -6,6 +6,43 @@ namespace xo { namespace ast { + namespace { + using xo::scm::prefix_type; + + prefix_type exprtype2prefix(exprtype x) + { + switch (x) { + case exprtype::invalid: assert(false); break; + case exprtype::constant: return prefix_type::from_chars("k"); + case exprtype::primitive: return prefix_type::from_chars("pm"); + case exprtype::define: return prefix_type::from_chars("def"); + case exprtype::assign: return prefix_type::from_chars("="); + case exprtype::apply: return prefix_type::from_chars("@"); + case exprtype::lambda: return prefix_type::from_chars("lm"); + case exprtype::variable: return prefix_type::from_chars("var"); + case exprtype::ifexpr: return prefix_type::from_chars("if"); + case exprtype::sequence: return prefix_type::from_chars("seq"); + case exprtype::convert: return prefix_type::from_chars("cvt"); + case exprtype::n_expr: assert(false); break; + } + + return prefix_type::from_chars("?expr"); + } + } + + GeneralizedExpression::GeneralizedExpression(exprtype extype, + TypeDescr valuetype) + : extype_{extype}, + valuetype_ref_{type_ref::dwim(exprtype2prefix(extype), valuetype)} + {} + + GeneralizedExpression::GeneralizedExpression(exprtype extype, + prefix_type prefix, + TypeDescr valuetype) + : extype_{extype}, + valuetype_ref_{type_ref::dwim(prefix, valuetype)} + {} + std::string GeneralizedExpression::display_string() const { return tostr(*this); diff --git a/src/expression/Lambda.cpp b/src/expression/Lambda.cpp index eafb5d3b..cdcbdb27 100644 --- a/src/expression/Lambda.cpp +++ b/src/expression/Lambda.cpp @@ -20,16 +20,9 @@ namespace xo { namespace ast { TypeDescr Lambda::assemble_lambda_td(const std::vector> & argv, - TypeDescr explicit_return_td, - const rp & body) + TypeDescr return_td) { - if (!body) - return nullptr; - - /** assemble function type. - * - * NOTE: need this to be unique! - **/ + assert(return_td != nullptr); std::vector arg_td_v; { @@ -40,6 +33,25 @@ namespace xo { } } + auto function_info + = FunctionTdxInfo(return_td, + arg_td_v, + false /*!is_noexcept*/); + + TypeDescr lambda_td + = TypeDescrBase::require_by_fn_info(function_info); + + return lambda_td; + } + + TypeDescr + Lambda::assemble_lambda_td(const std::vector> & argv, + TypeDescr explicit_return_td, + const rp & body) + { + if (!body) + return nullptr; + if (explicit_return_td && body->valuetype() && (explicit_return_td != body->valuetype())) { throw std::runtime_error(tostr("explicit lambda return type T1 conflicts with lambda body T2", xtag("T1", explicit_return_td), @@ -48,15 +60,9 @@ namespace xo { // TODO: unify(explicit_return_td, body->valuetype()) - auto function_info - = FunctionTdxInfo(explicit_return_td ? explicit_return_td : body->valuetype(), - arg_td_v, - false /*!is_noexcept*/); + TypeDescr return_td = explicit_return_td ? explicit_return_td : body->valuetype(); - TypeDescr lambda_td - = TypeDescrBase::require_by_fn_info(function_info); - - return lambda_td; + return assemble_lambda_td(argv, return_td); } std::string @@ -78,6 +84,15 @@ namespace xo { return ss.str(); } + rp + Lambda::make(const std::string & name, + TypeDescr lambda_td, + const rp & env, + const rp & body) + { + return new Lambda(name, lambda_td, env, body); + } + rp Lambda::make_from_env(const std::string & name, const rp & env, diff --git a/src/expression/typeinf/type_ref.cpp b/src/expression/typeinf/type_ref.cpp index 8df033ae..0d155967 100644 --- a/src/expression/typeinf/type_ref.cpp +++ b/src/expression/typeinf/type_ref.cpp @@ -11,6 +11,18 @@ namespace xo { bool type_ref::is_concrete() const { return td_ != nullptr; } + type_ref + type_ref::dwim(prefix_type prefix, TypeDescr td) + { + if (td) { + /** type resolved, type variable not needed **/ + return type_ref(type_var(), td); + } else { + /** type not resolved, assign a unique type variable **/ + return type_ref(generate_unique(prefix), td); + } + } + auto type_ref::generate_unique(xo::scm::prefix_type prefix) -> xo::scm::type_var { diff --git a/src/expression/typeinf/type_unifier.cpp b/src/expression/typeinf/type_unifier.cpp index 4f73718b..77046789 100644 --- a/src/expression/typeinf/type_unifier.cpp +++ b/src/expression/typeinf/type_unifier.cpp @@ -212,6 +212,18 @@ namespace xo { }; } + rp + type_unifier::lookup(const type_var & name) const + { + auto ix = constraint_map_.find(name); + + if (ix != constraint_map_.end()) { + return ix->second; + } else { + return nullptr; + } + } + } /*namespace scm*/ } /*namespace xo*/