xo-expression xo-reader: type unifier + misc improvements
This commit is contained in:
parent
6a7353f689
commit
75b74918b7
31 changed files with 1005 additions and 76 deletions
|
|
@ -31,7 +31,7 @@ namespace xo {
|
|||
exprtype extype() const { return extype_; }
|
||||
TypeDescr valuetype() const { return valuetype_; }
|
||||
|
||||
/** write human-readable representation to stream **/
|
||||
/** write human-readable representation to stream @p os **/
|
||||
virtual void display(std::ostream & os) const = 0;
|
||||
/** human-readable string representation **/
|
||||
virtual std::string display_string() const;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ namespace xo {
|
|||
**/
|
||||
static rp<Lambda> make_from_env(const std::string & name,
|
||||
const rp<LocalEnv> & env,
|
||||
TypeDescr explicit_return_td,
|
||||
const rp<Expression> & body);
|
||||
|
||||
/** downcast from Expression **/
|
||||
|
|
@ -105,6 +106,7 @@ namespace xo {
|
|||
* and body expression @p body
|
||||
**/
|
||||
static TypeDescr assemble_lambda_td(const std::vector<rp<Variable>> & argv,
|
||||
TypeDescr explicit_return_td,
|
||||
const rp<Expression> & body);
|
||||
|
||||
/** create string description for function signature,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
/** @file TypeBlueprint.hpp **/
|
||||
|
||||
#include "xo/refcnt/Refcounted.hpp"
|
||||
#include "type_ref.hpp"
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
class TypeBlueprint;
|
||||
|
||||
/** map from a type variable, to contraints on the resolution of that variable **/
|
||||
using type_substitution_map = std::map<type_var, rp<TypeBlueprint>>;
|
||||
|
||||
/** @class TypeBlueprint
|
||||
* @brief record constraints on a type variable.
|
||||
*
|
||||
* Within type unification, a TypeBlueprint represents
|
||||
* current state of knowledge as to the resolution of a particular type.
|
||||
*
|
||||
* Structurally homologous to @ref xo::reflect::TypeDescr,
|
||||
* but TypeDescr is intended to represent fully-defined types.
|
||||
* Conversely TypeBlueprint instances will be abandoned once
|
||||
* a corresponding TypeDescr exists.
|
||||
**/
|
||||
class TypeBlueprint : public xo::ref::Refcount {
|
||||
public:
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
public:
|
||||
TypeBlueprint() = default;
|
||||
|
||||
/** contruct blueprint for type_ref @p ref **/
|
||||
static rp<TypeBlueprint> make(const type_ref& ref);
|
||||
/** contruct blueprint for type variable @p name.
|
||||
* equivalent to @c make(type_ref(name, nullptr))
|
||||
**/
|
||||
static rp<TypeBlueprint> typevar(const type_var& name);
|
||||
|
||||
/** compare two blueprints for equality.
|
||||
* blueprints are equal iff (we know that) they refer to the same concrete type.
|
||||
**/
|
||||
static bool equals(bp<TypeBlueprint> lhs, bp<TypeBlueprint> rhs);
|
||||
|
||||
const type_ref& ref() const { return ref_; }
|
||||
const type_var& id() const { return ref_.id(); }
|
||||
TypeDescr td() const { return ref_.td(); }
|
||||
|
||||
bool is_concrete() const { return ref_.is_concrete(); }
|
||||
bool is_variable() const;
|
||||
|
||||
/** upsert into @p *p_typevarset all unresolved type variables **/
|
||||
void upsert_typevars(std::set<type_var> * p_typevar_set) const;
|
||||
|
||||
/** apply substitutions in @p sub_map to this type **/
|
||||
bp<TypeBlueprint> substitute(const type_substitution_map& sub_map);
|
||||
|
||||
/** replace with resolved type description.
|
||||
* Promise:
|
||||
* 1. ref().td() == @p td
|
||||
* 2. this->is_concrete() == true
|
||||
* 3. this->is_variable() == false
|
||||
**/
|
||||
void resolve_to(TypeDescr td);
|
||||
|
||||
/** write human-readable representation to stream @p os **/
|
||||
void display(std::ostream & os) const;
|
||||
|
||||
private:
|
||||
/** construct blueprint for @p ref **/
|
||||
explicit TypeBlueprint(const type_ref & ref);
|
||||
|
||||
private:
|
||||
/** name of the type being constrained here **/
|
||||
type_ref ref_;
|
||||
|
||||
// additional descriptive info..
|
||||
};
|
||||
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream & os, const TypeBlueprint & x) {
|
||||
x.display(os);
|
||||
return os;
|
||||
}
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end TypeBlueprint.hpp **/
|
||||
|
|
@ -2,18 +2,48 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "xo/flatstring/flatstring.hpp"
|
||||
#include "xo/reflect/TypeDescr.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
using type_var = xo::flatstring<11>;
|
||||
using prefix_type = xo::flatstring<8>;
|
||||
using type_var = xo::flatstring<16>;
|
||||
|
||||
/** @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.
|
||||
**/
|
||||
struct type_ref {
|
||||
class type_ref {
|
||||
public:
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
public:
|
||||
type_ref() = default;
|
||||
type_ref(const type_var& id, TypeDescr td);
|
||||
|
||||
/** generate a unique type-variable name, that begins with @p prefix **/
|
||||
static type_var generate_unique(prefix_type prefix);
|
||||
|
||||
const type_var& id() const { return id_; }
|
||||
TypeDescr td() const { return td_; }
|
||||
|
||||
/** true iff type at this location has been resolved **/
|
||||
bool is_concrete() const;
|
||||
|
||||
void resolve_to(TypeDescr td);
|
||||
|
||||
private:
|
||||
/** unique (likely generated) name for type at this location **/
|
||||
type_var id_;
|
||||
/** description for concrete type, once resolved.
|
||||
* may be null when type_ref created.
|
||||
* expected to be immutable once established.
|
||||
* note that TypeDescr itself may be incomplete,
|
||||
* but not for inference purposes
|
||||
**/
|
||||
TypeDescr td_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
60
xo-expression/include/xo/expression/typeinf/type_unifier.hpp
Normal file
60
xo-expression/include/xo/expression/typeinf/type_unifier.hpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/** @file type_unifier.hpp **/
|
||||
|
||||
#include "type_ref.hpp"
|
||||
#include "TypeBlueprint.hpp"
|
||||
#include <map>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
struct unify_result {
|
||||
/** true iff unification success **/
|
||||
bool success_;
|
||||
/** blueprint (possibly concrete) for unified type **/
|
||||
rp<TypeBlueprint> unified_;
|
||||
/** if @ref success_ is false -> non-null source function
|
||||
* in which contradiction detected
|
||||
**/
|
||||
const char * error_src_function_ = nullptr;
|
||||
/** if @ref success_ is false -> human-readable error description **/
|
||||
std::string error_description_;
|
||||
};
|
||||
|
||||
std::ostream & operator<< (std::ostream & os, const unify_result & x);
|
||||
|
||||
/** @class type_unifer
|
||||
* @brief type unification algorithm
|
||||
**/
|
||||
class type_unifier {
|
||||
public:
|
||||
type_unifier() = default;
|
||||
|
||||
/** error message where unification would require both
|
||||
* 1. equals(s1,t2)
|
||||
* 2. t2 contains s1
|
||||
**/
|
||||
static unify_result occurs_error(const char * src_function,
|
||||
bp<TypeBlueprint> t1,
|
||||
bp<TypeBlueprint> t2,
|
||||
bp<TypeBlueprint> s1,
|
||||
bp<TypeBlueprint> s2);
|
||||
|
||||
/** given fact that @p lhs and @p rhs must refer to
|
||||
* the same type:
|
||||
* 1. unify their type blueprints to get new blueprint U(lhs.rhs)
|
||||
* 2. update @ref constraint_map_ so that typevar ids for
|
||||
* @p lhs and @p rhs refer to U(lhs,rhs)
|
||||
* 3. also update @ref constraint_map_ for any secondary unifications
|
||||
* that are discovered
|
||||
* 4. return error if unification is contradiction encountered.
|
||||
**/
|
||||
unify_result unify(bp<TypeBlueprint> lhs, bp<TypeBlueprint> rhs);
|
||||
|
||||
private:
|
||||
type_substitution_map constraint_map_;
|
||||
};
|
||||
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end type_unifier.hpp **/
|
||||
Loading…
Add table
Add a link
Reference in a new issue